Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
virtual-copy-support-test.cpp
Go to the documentation of this file.
1/*
2 VirtualCopySupport(Test) - copy and clone type-erased objects
3
4 Copyright (C)
5 2015, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12* *****************************************************************/
13
20#include "lib/test/run.hpp"
21#include "lib/format-string.hpp"
24#include "lib/format-string.hpp"
25#include "lib/format-cout.hpp"
26#include "lib/util.hpp"
27
28#include <string>
29#include <type_traits>
30
31using util::_Fmt;
32using util::isnil;
33using std::string;
34
35using LERR_(LOGIC);
36using LERR_(WRONG_TYPE);
37
38
39namespace lib {
40namespace meta {
41namespace test {
42
43 namespace { // Test fixture...
44
45 int _CheckSum_ = 0;
46
47 class Interface;
48
49
59 {
60 public:
61 virtual void copyInto (void* ) const { /* NOP */ };
62 virtual void moveInto (void* ) { /* NOP */ };
63 virtual void copyInto (Interface&) const { /* NOP */ };
64 virtual void moveInto (Interface&) { /* NOP */ };
65 };
66
67
72 : public CopyInterface
73 {
74 public:
75 virtual ~Interface() { }
76 virtual operator string() const =0;
77 virtual bool empty() const =0;
78 };
79
83 template<uint i>
84 class Sub
85 : public Interface
86 {
87 static_assert (0 < i, "invalid construction");
88
89 char storage_[i];
90
91 char&
93 {
94 return storage_[i-1];
95 }
96 char const&
97 access() const
98 {
99 return storage_[i-1];
100 }
101
102 public: /* == Implementation of the Interface == */
103
104 virtual operator string() const override
105 {
106 return _Fmt("Sub|%s|%d|-%s")
107 % util::typeStr(this)
108 % i
109 % access();
110 }
111
112 virtual bool
113 empty() const
114 {
115 return not access();
116 }
117
118
119 public: /* == full set of copy and assignment operations == */
120
122 {
123 _CheckSum_ -= access();
124 }
126 {
127 access() = 'A' + rani(23);
128 _CheckSum_ += access();
129 }
130 Sub (Sub const& osub)
131 {
132 access() = osub.access();
133 _CheckSum_ += access();
134 }
136 {
137 access() = 0;
138 std::swap(access(),rsub.access());
139 }
140 Sub&
142 {
143 if (!util::isSameObject (*this, osub))
144 {
145 _CheckSum_ -= access();
146 access() = osub.access();
147 _CheckSum_ += access();
148 }
149 return *this;
150 }
151 Sub&
153 {
154 _CheckSum_ -= access();
155 access() = 0;
156 std::swap(access(),rsub.access());
157 return *this;
158 }
159 };
160
161
162 /* == create various flavours of copyable / noncopyable objects == */
163
164 template<char c>
166 : public Sub<c>
167 { };
168
169 template<char c>
171 : public Sub<c>
172 {
173 void operator= (UnAssignable const&); // private and unimplemented
174 public:
175 UnAssignable() = default;
177 UnAssignable(UnAssignable const&) = default;
178 };
179
180 template<char c>
182 : public UnAssignable<c>
183 {
184 public:
185 OnlyMovable (OnlyMovable const&) = delete;
186 OnlyMovable() = default;
188 };
189
190 template<char c>
192 : public OnlyMovable<c>
193 {
194 public:
196 Noncopyable () = default;
197 };
198
199
200
201 /* == concrete implementation subclass with virtual copy support == */
202
203 template<class IMP>
204 class Opaque //-----Interface| CRTP-Impl | direct Baseclass
205 : public CopySupport<IMP>::template Policy<Interface, Opaque<IMP>, IMP>
206 {
207 public:
208 static Opaque&
210 {
211 Opaque* impl = dynamic_cast<Opaque*> (&bas);
212
213 if (!impl)
214 throw error::Logic{"virtual copy works only on instances "
215 "of the same concrete implementation class"
216 , LERR_(WRONG_TYPE)};
217 else
218 return *impl;
219 }
220 };
221
222 // == Test subject(s)==========================
223 using RegularImpl = Opaque<Regular<'a'>>;
224 using ClonableImpl = Opaque<UnAssignable<'b'>>;
225 using MovableImpl = Opaque<OnlyMovable<'c'>>;
226 using ImobileImpl = Opaque<Noncopyable<'d'>>;
227
228 }//(End)Test fixture
229
230
231
232
233
234
235
236 /**********************************************************************************************/
242 class VirtualCopySupport_test : public Test
243 {
244 virtual void
245 run (Arg)
246 {
247 seedRand();
248 CHECK(0 == _CheckSum_);
249
251
252 CHECK(0 == _CheckSum_);
253
258
259 CHECK(0 == _CheckSum_);
260 }
261
262
275 void
277 {
278 /* == full copy, move and assignment == */
279 Regular<'A'> a;
280 Regular<'A'> aa(a);
281 Regular<'A'> a1;
282
283 cout << a <<endl
284 << aa <<endl
285 << a1 <<endl;
286
287 a1 = a;
288
289 CHECK (string(a) == string(aa));
290 CHECK (string(a) == string(a1));
291 CHECK (!isnil(a1));
292
293 a = std::move(a1);
294
295 CHECK (isnil(a1));
296 CHECK (string(a) == string(aa));
297
298
299 /* == interface vs. concrete class == */
300 Regular<'B'> b;
301 Interface& ii = b;
302
303 string prevID(b);
304 ii = a; // Copy operation of Base-Interface is NOP
305 CHECK (string(b) == prevID);
306
307
308 /* == assignment inhibited == */
309 UnAssignable<'C'> c;
310 UnAssignable<'C'> cc(c);
311
312 CHECK (string(c) == string(cc));
313
314 prevID = cc;
315 UnAssignable<'C'> ccc(std::move(cc));
316
317 cout << cc <<endl
318 << ccc <<endl;
319
320 CHECK (string(ccc) == prevID);
321 CHECK (string(cc) != prevID);
322 CHECK (!isnil(ccc));
323 CHECK (isnil (cc)); // killed by moving away
324
325 // c = cc; // does not compile
326
327
328 /* == only move construction allowed == */
329 OnlyMovable<'D'> d;
330 OnlyMovable<'D'> dd (std::move(d));
331
332 cout << d <<endl
333 << dd <<endl;
334
335 CHECK (string(dd) != string(d));
336 CHECK (!isnil(dd));
337 CHECK (isnil(d));
338
339 // OnlyMovable<'D'> d1 (dd); // does not compile
340 // d = dd; // does not compile;
341
342
343 /* == all copy/assignment inhibited == */
344 Noncopyable<'E'> e;
345 // Noncopyable<'E'> ee (e); // does not compile
346 // Noncopyable<'E'> eee (std::move (e)); // does not compile
347 // e = Noncopyable<'E'>(); // does not compile
348
349 CHECK (!isnil (e));
350 }
351
352
353
354
355
356
357 void
359 {
360 RegularImpl a,aa,aaa;
361 Interface& i(a);
362 Interface& ii(aa);
363 Interface& iii(aaa);
364
365 char storage[sizeof(RegularImpl)];
366 Interface& iiii (*reinterpret_cast<Interface*> (&storage));
367
368 string prevID = a;
369 CHECK (!isnil (a));
370
371 i.moveInto(&storage);
372 CHECK (string(iiii) == prevID);
373 CHECK (!isnil(iiii));
374 CHECK ( isnil(i));
375
376 ii.copyInto(i);
377 CHECK (!isnil(i));
378 CHECK (!isnil(ii));
379 CHECK (string(i) == string(ii));
380
381 prevID = iii;
382 iii.moveInto(ii);
383 CHECK (!isnil(ii));
384 CHECK ( isnil(iii));
385 CHECK (string(ii) == prevID);
386
387 // Verify that type mismatch in assignment is detected...
388 Opaque<Regular<'!'>> divergent;
389 Interface& evil(divergent);
390 VERIFY_ERROR (WRONG_TYPE, evil.copyInto(i));
391 VERIFY_ERROR (WRONG_TYPE, evil.moveInto(i));
392
393
394 cout << "==fullVirtualCopySupport=="<<endl
395 << i <<endl
396 << ii <<endl
397 << iii <<endl
398 << iiii <<endl;
399
400 //need to clean-up the placement-new instance explicitly
401 iiii.~Interface();
402 }
403
404
405 void
407 {
408 ClonableImpl b,bb,bbb;
409 Interface& i(b);
410 Interface& ii(bb);
411 Interface& iii(bbb);
412
413 char storage[sizeof(ClonableImpl)];
414 Interface& iiii (*reinterpret_cast<Interface*> (&storage));
415
416 string prevID = b;
417 CHECK (!isnil (b));
418
419 i.moveInto(&storage);
420 CHECK (string(iiii) == prevID);
421 CHECK (!isnil(iiii));
422 CHECK ( isnil(i));
423
424 iiii.~Interface(); //clean-up previously placed instance
425
426 prevID = ii;
427 ii.copyInto(&storage);
428 CHECK (!isnil(ii));
429 CHECK (!isnil(iiii));
430 CHECK ( isnil(i));
431 CHECK (string(iiii) == prevID);
432 CHECK (string(ii) == prevID);
433
434 prevID = iii;
435 VERIFY_ERROR (LOGIC, iii.copyInto(ii));
436 VERIFY_ERROR (LOGIC, iii.moveInto(ii));
437 CHECK (string(iii) == prevID);
438 CHECK (!isnil(iii));
439
440 cout << "==noAssignementSupport=="<<endl
441 << i <<endl
442 << ii <<endl
443 << iii <<endl
444 << iiii <<endl;
445
446 //clean-up placement-new instance
447 iiii.~Interface();
448 }
449
450
451 void
453 {
454 MovableImpl c,cc;
455 Interface& i(c);
456 Interface& ii(cc);
457
458 char storage[sizeof(MovableImpl)];
459 Interface& iiii (*reinterpret_cast<Interface*> (&storage));
460
461 string prevID = i;
462 CHECK (!isnil (i));
463
464 i.moveInto(&storage);
465 CHECK (string(iiii) == prevID);
466 CHECK (!isnil(iiii));
467 CHECK ( isnil(i));
468
469 prevID = ii;
470 VERIFY_ERROR (LOGIC, ii.copyInto(&storage));
471 VERIFY_ERROR (LOGIC, ii.copyInto(i));
472 VERIFY_ERROR (LOGIC, ii.moveInto(i));
473 CHECK (string(ii) == prevID);
474 CHECK (!isnil(ii));
475 CHECK ( isnil(i));
476
477 cout << "==onlyMovableSupport=="<<endl
478 << i <<endl
479 << ii <<endl
480 << iiii <<endl;
481
482 //clean-up placement-new instance
483 iiii.~Interface();
484 }
485
486
487 void
489 {
490 ImobileImpl d,dd;
491 Interface& i(d);
492 Interface& ii(dd);
493 char storage[sizeof(ImobileImpl)];
494
495 CHECK (!isnil (i));
496
497 string prevID = ii;
498 VERIFY_ERROR (LOGIC, ii.copyInto(&storage));
499 VERIFY_ERROR (LOGIC, ii.moveInto(&storage));
500 VERIFY_ERROR (LOGIC, ii.copyInto(i));
501 VERIFY_ERROR (LOGIC, ii.moveInto(i));
502 CHECK (string(ii) == prevID);
503 CHECK (!isnil(ii));
504 CHECK (!isnil (i));
505
506 cout << "==disabledCopySupport=="<<endl
507 << i <<endl
508 << ii <<endl;
509
510 //no clean-up,
511 //since we never created anything in the storage buffer
512 }
513 };
514
515
518
519
520
521}}} // namespace lib::meta::test
A front-end for using printf-style formatting.
#define LERR_(_NAME_)
Definition error.hpp:45
Automatically use custom string conversion in C++ stream output.
Front-end for printf-style string template interpolation.
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
Policy to pick a suitable implementation of "virtual copy operations".
Implementation namespace for support and library code.
int rani(uint bound=_iBOUND())
Definition random.hpp:135
LumieraError< LERR_(LOGIC)> Logic
Definition error.hpp:207
Test runner and basic definitions for tests.
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee's memory identities.
Definition util.hpp:421
bool isnil(lib::time::Duration const &dur)
Simplistic test class runner.
#define LAUNCHER(_TEST_CLASS_, _GROUPS_)
Definition run.hpp:116
A collection of frequently used helper functions to support unit testing.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Helper for building »virtual copy« operations.