Lumiera  0.pre.03
»edit your freedom«
polymorphic-value.hpp
Go to the documentation of this file.
1 /*
2  POLYMORPHIC-VALUE.hpp - building opaque polymorphic value objects
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 
152 #ifndef LIB_POLYMORPHIC_VALUE_H
153 #define LIB_POLYMORPHIC_VALUE_H
154 
155 
156 #include "lib/error.hpp"
158 #include "lib/util.hpp"
159 
160 #include <cstddef>
161 #include <new>
162 
163 
164 namespace lib {
165 
166  namespace polyvalue { // implementation details...
167 
168  namespace error = lumiera::error;
169  using lib::meta::enable_if;
170  using lib::meta::Yes_t;
171  using lib::meta::No_t;
172 
173  struct EmptyBase{ };
174 
190  template<class IFA
191  ,class BA = IFA
192  >
194  : public BA
195  {
196  public:
197  virtual ~CopySupport() { };
198  virtual void cloneInto (void* targetBuffer) const =0;
199  virtual void copyInto (IFA& targetBase) const =0;
200  };
201 
208  template<class BA>
210  : public BA
211  {
212  public:
213  virtual ~CloneValueSupport() { };
214  virtual void cloneInto (void* targetBuffer) const =0;
215  };
217 
218 
223  template<typename T>
225  {
226 
227  META_DETECT_FUNCTION_NAME(cloneInto);
228 
229  public:
230  enum{ value = HasFunName_cloneInto<T>::value
231  }; // warning: match on the function name only
232  };
233 
238  template<typename T>
240  {
241  META_DETECT_MEMBER(copyInto);
242 
243  public:
244  enum{ value = exposes_CloneFunction<T>::value
245  && ! HasMember_copyInto<T>::value
246  };
247  };
248 
254  template<class API, class YES =void>
256  {
257  template<class IMP>
258  static void
259  assignEmbedded(IMP& dest,IMP const& src)
260  {
261  dest = src;
262  }
263  };
264 
272  template<class API>
273  struct AssignmentPolicy<API, enable_if< allow_Clone_but_no_Copy<API> >>
274  {
275  template<class IMP>
276  static void
277  assignEmbedded(IMP&,IMP const&)
278  {
279  throw error::Logic("attempt to overwrite unmodifiable value");
280  }
281  };
282 
283 
284 
293  template <class TY, class YES = void>
294  struct Trait
295  {
298  using AdapterAttachment = CopyAPI;
299  enum{ ADMIN_OVERHEAD = 2 * sizeof(void*) }; // need second VTable for CopyAPI mix-in
300 
301  static CopyAPI&
302  accessCopyHandlingInterface (TY& bufferContents)
303  {
304  REQUIRE (INSTANCEOF (CopyAPI, &bufferContents));
305  return dynamic_cast<CopyAPI&> (bufferContents);
306  }
307  };
308 
309 
317  template <class TY>
318  struct Trait<TY, enable_if< exposes_CloneFunction<TY> >>
319  {
320  using CopyAPI = TY;
322  using AdapterAttachment = struct{ /* irrelevant */ };
323  enum{ ADMIN_OVERHEAD = 1 * sizeof(void*) }; // just the VTable of the payload
324 
325  template<class IFA>
326  static CopyAPI&
327  accessCopyHandlingInterface (IFA& bufferContents)
328  {
329  REQUIRE (INSTANCEOF (CopyAPI, &bufferContents));
330  return static_cast<CopyAPI&> (bufferContents);
331  }
332  };
333 
334  }//(End)implementation details
335 
336 
337 
338 
339 
340 
341 
342 
343 
360  template
361  < class IFA
362  , size_t storage
363  , class CPY = IFA
364  >
366  {
367  private:
369  typedef typename _Traits::CopyAPI _CopyHandlingAdapter;
370  typedef typename _Traits::Assignment _AssignmentPolicy;
371  enum{
372  siz = storage + _Traits::ADMIN_OVERHEAD
373  };
374  // WARNING: never add any member fields here /////////////////TICKET #1204
375 
376 
377  /* === embedded object in buffer === */
378 
380  alignas(IFA) mutable
381  std::byte buf_[siz];
382 
383  IFA&
384  accessEmbedded() const
385  {
386  return * std::launder (reinterpret_cast<IFA*> (&buf_));
387  }
388 
389  void
390  destroyEmbedded()
391  {
392  accessEmbedded().~IFA();
393  }
394 
395 
406  template<class IMP>
407  class Adapter
408  : public IMP
409  , public _Traits::AdapterAttachment // mix-in, might be empty
410  {
411  virtual void
412  cloneInto (void* targetBuffer) const
413  {
414  new(targetBuffer) Adapter(*this); // forward to copy ctor
415  }
416 
417  virtual void
418  copyInto (IFA& targetBase) const
419  {
420  REQUIRE (INSTANCEOF (Adapter, &targetBase));
421  Adapter& target = static_cast<Adapter&> (targetBase);
422  _AssignmentPolicy::assignEmbedded(target,*this);
423  } // forward to assignment operator
424 
425  public: /* == forwarding ctor to implementation type == */
426 
427  template<typename...ARGS>
428  Adapter (ARGS&&... args)
429  : IMP(std::forward<ARGS>(args)...)
430  { }
431 
432  /* using default copy and assignment */
433  };
434 
435  template<typename IMP>
436  using TypeSelector = Adapter<IMP>*;
437 
438 
439  _CopyHandlingAdapter&
440  accessHandlingInterface () const
441  {
442  IFA& bufferContents = accessEmbedded();
443  return _Traits::accessCopyHandlingInterface (bufferContents);
444  }
445 
450  template<class IMP, typename...ARGS>
451  PolymorphicValue (TypeSelector<IMP>, ARGS&&... args)
452  {
453  static_assert (siz >= sizeof(Adapter<IMP>), "insufficient inline buffer size");
454  new(&buf_) Adapter<IMP> (std::forward<ARGS>(args)...);
455  }
456 
457 
458  protected:
466  template<class IMP, typename...ARGS>
467  PolymorphicValue (IMP*, ARGS&&... args)
468  : PolymorphicValue (TypeSelector<IMP>(), std::forward<ARGS>(args)...)
469  { }
470 
471 
472  public: /* === PolymorphicValue public API === */
473 
474  typedef IFA Interface;
475 
476  Interface&
477  getPayload()
478  {
479  return accessEmbedded();
480  }
481 
482  operator Interface& ()
483  {
484  return accessEmbedded();
485  }
486  operator Interface const& () const
487  {
488  return accessEmbedded();
489  }
490  Interface*
491  operator-> () const
492  {
493  return &( accessEmbedded() );
494  }
495 
497  {
498  destroyEmbedded();
499  }
500 
502  {
503  o.accessHandlingInterface().cloneInto (&buf_);
504  }
505 
507  operator= (PolymorphicValue const& o)
508  {
509  o.accessHandlingInterface().copyInto (this->accessEmbedded());
510  return *this;
511  }
512 
513  /* === static factory functions === */
514 
515  template<class IMP, typename...ARGS>
516  static PolymorphicValue
517  build (ARGS&&... args)
518  {
519  Adapter<IMP>* type_to_build_in_buffer(0);
520  return PolymorphicValue (type_to_build_in_buffer, std::forward<ARGS>(args)...);
521  }
522 
523 
524  /* === support Equality by forwarding to embedded === */
525 
526  friend bool
527  operator== (PolymorphicValue const& v1, PolymorphicValue const& v2)
528  {
529  return v1.accessEmbedded() == v2.accessEmbedded();
530  }
531  friend bool
532  operator!= (PolymorphicValue const& v1, PolymorphicValue const& v2)
533  {
534  return not (v1 == v2);
535  }
536  };
537 
538 
539 
540 
541 } // namespace lib
542 #endif
Building block: the Interface to cause the invocation.
#define META_DETECT_MEMBER(_NAME_)
Detector for a nested member (field or function).
#define INSTANCEOF(CLASS, EXPR)
shortcut for subclass test, intended for assertions only.
Definition: util.hpp:514
A variation for limited copy support.
STL namespace.
helper to detect presence of a function to support clone operations
bool operator==(PtrDerefIter< I1 > const &il, PtrDerefIter< I2 > const &ir)
Supporting equality comparisons...
trait template to deal with different ways to support copy operations.
Implementation namespace for support and library code.
typename enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition: meta/util.hpp:83
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
Implementation Helper: add support for copy operations.
PolymorphicValue(IMP *, ARGS &&... args)
Template to build polymorphic value objects.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
helper to detect if the API supports only copy construction, but no assignment
char Yes_t
helper types to detect the overload resolution chosen by the compiler
Definition: meta/util.hpp:95
Interface for active support of copy operations by the embedded client objects.
Lumiera error handling (C++ interface).
#define META_DETECT_FUNCTION_NAME(_FUN_NAME_)
Detector for a member function with the given name.
PolymorphicValue(TypeSelector< IMP >, ARGS &&... args)
Policy class for invoking the assignment operator.
Metaprogramming helpers to check for specific properties of a type in question.