Lumiera  0.pre.03
»edit your freedom«
polymorphic-value-test.cpp
Go to the documentation of this file.
1 /*
2  PolymorphicValue(Test) - verify handling of opaque polymorphic values
3 
4  Copyright (C)
5  2011, 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/test/test-helper.hpp"
22 #include "lib/util-foreach.hpp"
23 
25 
26 #include <vector>
27 
28 
29 namespace lib {
30 namespace test{
31 
32  using ::Test;
33  using util::for_each;
34  using util::unConst;
35  using util::isSameObject;
36  using lumiera::error::LUMIERA_ERROR_ASSERTION;
37 
38 
39  namespace { // test dummy hierarchy
40  // Note: largely varying space requirements
41  // correct function depending on concrete class
42 
43 
44  struct Interface
45  {
46  virtual ~Interface() {}
47  virtual long apiFunc() =0;
48 
49  virtual long& localSum() =0;
50 
51  bool
52  operator== (Interface const& o) const
53  {
54  return unConst(this)->localSum()
55  == unConst(o).localSum();
56  }
57  };
58 
59 
60  const uint MAX_RAND = 1000;
61  const uint MAX_ELM = 111;
62  const uint MAX_SIZ = sizeof(long[MAX_ELM]);
63 
64  /* Checksums to verify proper ctor-dtor calls and copy operations */
65  long _checkSum = 0;
66  long _callSum = 0;
67  uint _created = 0;
68 
69 
76  template<uint ii, class BASE=Interface>
77  struct Imp : BASE
78  {
79  long localData_[ii];
80 
81  ~Imp()
82  {
83  mark (-1 * localSum());
84  CHECK (0 == localSum());
85  }
86 
87  Imp()
88  {
89  REQUIRE (0 < ii);
90  localSum() = 0;
91  mark(ii);
92  ++ _created;
93  }
94 
95  Imp (Imp const& o)
96  {
97  ++ _created;
98  copyData (o);
99  _checkSum += localSum();
100  }// adjust, because we've gotten two identical instances
101 
102  Imp&
103  operator= (Imp const& o)
104  {
105  _checkSum -= localSum();
106  copyData (o);
107  _checkSum += localSum();
108  return *this;
109  }
110 
111  private:
112  virtual long
113  apiFunc()
114  {
115  long rr = ii * (1 + rani(MAX_RAND));
116  mark (rr);
117  _callSum += rr;
118  return rr;
119  }
120 
121  long&
122  localSum()
123  {
124  return localData_[ii-1];
125  }
126 
127  void
128  mark (long markerValue)
129  {
130  localSum() += markerValue;
131  _checkSum += markerValue;
132  }
133 
134  void
135  copyData (Imp const& o)
136  {
137  for (uint i=0; i<ii; ++i)
138  localData_[i] = o.localData_[i];
139  }
140  };
141 
142 
147  const size_t _ALIGN_ = sizeof(size_t);
148 
149  }
150 
152  using TestList = std::vector<PolyVal> ;
153 
154 
155 
156 
157 
158 
159  /******************************************************************************/
165  class PolymorphicValue_test : public Test
166  {
167 
168  virtual void
169  run (Arg)
170  {
171  _checkSum = 0;
172  _callSum = 0;
173  _created = 0;
174  seedRand();
175 
176  verifyBasics();
177 
178  {
179  TestList objs = createOpaqueValues ();
180  for_each (objs, operate);
181  }
182  CHECK (0 == _checkSum); // all dead
183 
184  verifyOverrunProtection();
185  verifyCopySupportDetectionMetafunctions();
186  }
187 
188 
189  TestList
190  createOpaqueValues ()
191  {
192  TestList list;
193  list.push_back (PolyVal::build<Imp<1>> () );
194  list.push_back (PolyVal::build<Imp<11>> () );
195  list.push_back (PolyVal::build<Imp<111>>() );
196  list.push_back (PolyVal::build<Imp<23>> () );
197  list.push_back (PolyVal::build<Imp<5>> () );
198  return list;
199  } //note: copy
200 
201 
202  static void
203  operate (PolyVal& elm)
204  {
205  PolyVal myLocalVal(elm);
206  CHECK (elm == myLocalVal);
207 
208  long prevSum = _callSum;
209  long randVal = myLocalVal->apiFunc();
210  CHECK (prevSum + randVal == _callSum);
211  CHECK (elm != myLocalVal);
212 
213  elm = myLocalVal;
214  CHECK (elm == myLocalVal);
215  CHECK (!isSameObject (elm, myLocalVal));
216 
217  CHECK (sizeof(myLocalVal) <= MAX_SIZ + polyvalue::Trait<Interface>::ADMIN_OVERHEAD + _ALIGN_);
218  }
219 
220 
221  void
222  verifyBasics()
223  {
224  typedef Imp<MAX_ELM> MaximumSizedImp;
225 
226  // Standard case: no copy support by client objects
227  verifyCreation_and_Copy<PolyVal, MaximumSizedImp>();
228 
229  // Special case: client objects expose extension point for copy support
230  using CopySupportAPI = polyvalue::CopySupport<Interface>; // Copy support API declared as sub-interface
231  using CopySupportingImp = Imp<MAX_ELM,CopySupportAPI>; // insert this sub-interface between public API and Implementation
232  using OptimalPolyVal = PolymorphicValue<Interface, MAX_SIZ, CopySupportAPI>; // Make the Holder use this special attachment point
233  CHECK (sizeof(OptimalPolyVal) < sizeof(PolyVal)); // results in smaller Holder and less implementation overhead
234 
235  verifyCreation_and_Copy<OptimalPolyVal, CopySupportingImp>();
236  }
237 
238 
239  template<class PV,class IMP>
240  void
241  verifyCreation_and_Copy()
242  {
243  using Holder = PV;
244  using ImpType = IMP;
245  using Api = typename PV::Interface ;
246 
247  long prevSum = _checkSum;
248  uint prevCnt = _created;
249 
250  Holder val = Holder::template build<ImpType>();
251  CHECK (prevSum+111 == _checkSum); // We got one primary ctor call
252  CHECK (prevCnt+1 <= _created); // Note: usually, the compiler optimises
253  CHECK (prevCnt+2 >= _created); // and skips the spurious copy-operation
254  CHECK (sizeof(Holder) >= sizeof(ImpType));
255  Api& api = val;
256  CHECK (isSameObject(api,val));
257  CHECK (INSTANCEOF(ImpType, &api));
258 
259  prevCnt = _created;
260  Holder val2(val); // invoke copy ctor without knowing the implementation type
261  api.apiFunc();
262  CHECK (val != val2); // invoking the API function had an sideeffect on the state
263  val = val2; // assignment of copy back to the original...
264  CHECK (val == val2); // cancels the side effect
265 
266  CHECK (prevCnt+1 == _created); // one new embedded instance was created by copy ctor
267  }
268 
269 
270  void
271  verifyOverrunProtection()
272  {
273  typedef Imp<MAX_ELM+1> OversizedImp;
274  CHECK (MAX_SIZ < sizeof(OversizedImp));
275 #if false
276  VERIFY_ERROR (ASSERTION, PolyVal::build<OversizedImp>() );
277 #endif
278  }
279 
280 
290  void
292  {
293  typedef polyvalue::CopySupport<Interface> CopySupportAPI;
294  typedef polyvalue::CloneValueSupport<Interface> CloneOnlyAPI;
295 
299 
302  }
303  };
304 
305 
306  LAUNCHER (PolymorphicValue_test, "unit common");
307 
308 
309 }} // namespace lib::test
const size_t _ALIGN_
maximum additional storage maybe wasted due to alignment of the contained object within the embedded ...
Definition: run.hpp:40
#define INSTANCEOF(CLASS, EXPR)
shortcut for subclass test, intended for assertions only.
Definition: util.hpp:514
A variation for limited copy support.
helper to detect presence of a function to support clone operations
int rani(uint bound=_iBOUND())
Definition: random.hpp:135
bool operator==(PtrDerefIter< I1 > const &il, PtrDerefIter< I2 > const &ir)
Supporting equality comparisons...
A mechanism to allow for opaque polymorphic value objects.
trait template to deal with different ways to support copy operations.
Implementation namespace for support and library code.
Template to generate concrete implementation classes.
Simplistic test class runner.
Template to build polymorphic value objects.
helper to detect if the API supports only copy construction, but no assignment
void for_each(CON const &elements, FUN function, P1 &&bind1, ARGS &&...args)
Accept binding for arbitrary function arguments.
Interface for active support of copy operations by the embedded client objects.
A collection of frequently used helper functions to support unit testing.
Perform operations "for each element" of a collection.
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee&#39;s memory identities. ...
Definition: util.hpp:421