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) Lumiera.org
5  2011, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
161 #ifndef LIB_POLYMORPHIC_VALUE_H
162 #define LIB_POLYMORPHIC_VALUE_H
163 
164 
165 #include "lib/error.hpp"
167 #include "lib/util.hpp"
168 
169 #include <cstddef>
170 #include <new>
171 
172 
173 namespace lib {
174 
175  namespace polyvalue { // implementation details...
176 
177  namespace error = lumiera::error;
178  using lib::meta::enable_if;
179  using lib::meta::Yes_t;
180  using lib::meta::No_t;
181 
182  struct EmptyBase{ };
183 
199  template<class IFA
200  ,class BA = IFA
201  >
203  : public BA
204  {
205  public:
206  virtual ~CopySupport() { };
207  virtual void cloneInto (void* targetBuffer) const =0;
208  virtual void copyInto (IFA& targetBase) const =0;
209  };
210 
217  template<class BA>
219  : public BA
220  {
221  public:
222  virtual ~CloneValueSupport() { };
223  virtual void cloneInto (void* targetBuffer) const =0;
224  };
226 
227 
232  template<typename T>
234  {
235 
236  META_DETECT_FUNCTION_NAME(cloneInto);
237 
238  public:
239  enum{ value = HasFunName_cloneInto<T>::value
240  }; // warning: match on the function name only
241  };
242 
247  template<typename T>
249  {
250  META_DETECT_MEMBER(copyInto);
251 
252  public:
253  enum{ value = exposes_CloneFunction<T>::value
254  && ! HasMember_copyInto<T>::value
255  };
256  };
257 
263  template<class API, class YES =void>
265  {
266  template<class IMP>
267  static void
268  assignEmbedded(IMP& dest,IMP const& src)
269  {
270  dest = src;
271  }
272  };
273 
281  template<class API>
282  struct AssignmentPolicy<API, enable_if< allow_Clone_but_no_Copy<API> >>
283  {
284  template<class IMP>
285  static void
286  assignEmbedded(IMP&,IMP const&)
287  {
288  throw error::Logic("attempt to overwrite unmodifiable value");
289  }
290  };
291 
292 
293 
302  template <class TY, class YES = void>
303  struct Trait
304  {
307  using AdapterAttachment = CopyAPI;
308  enum{ ADMIN_OVERHEAD = 2 * sizeof(void*) }; // need second VTable for CopyAPI mix-in
309 
310  static CopyAPI&
311  accessCopyHandlingInterface (TY& bufferContents)
312  {
313  REQUIRE (INSTANCEOF (CopyAPI, &bufferContents));
314  return dynamic_cast<CopyAPI&> (bufferContents);
315  }
316  };
317 
318 
326  template <class TY>
327  struct Trait<TY, enable_if< exposes_CloneFunction<TY> >>
328  {
329  using CopyAPI = TY;
331  using AdapterAttachment = struct{ /* irrelevant */ };
332  enum{ ADMIN_OVERHEAD = 1 * sizeof(void*) }; // just the VTable of the payload
333 
334  template<class IFA>
335  static CopyAPI&
336  accessCopyHandlingInterface (IFA& bufferContents)
337  {
338  REQUIRE (INSTANCEOF (CopyAPI, &bufferContents));
339  return static_cast<CopyAPI&> (bufferContents);
340  }
341  };
342 
343  }//(End)implementation details
344 
345 
346 
347 
348 
349 
350 
351 
352 
369  template
370  < class IFA
371  , size_t storage
372  , class CPY = IFA
373  >
375  {
376  private:
378  typedef typename _Traits::CopyAPI _CopyHandlingAdapter;
379  typedef typename _Traits::Assignment _AssignmentPolicy;
380  enum{
381  siz = storage + _Traits::ADMIN_OVERHEAD
382  };
383  // WARNING: never add any member fields here /////////////////TICKET #1204
384 
385 
386  /* === embedded object in buffer === */
387 
389  alignas(IFA) mutable
390  std::byte buf_[siz];
391 
392  IFA&
393  accessEmbedded() const
394  {
395  return * std::launder (reinterpret_cast<IFA*> (&buf_));
396  }
397 
398  void
399  destroyEmbedded()
400  {
401  accessEmbedded().~IFA();
402  }
403 
404 
415  template<class IMP>
416  class Adapter
417  : public IMP
418  , public _Traits::AdapterAttachment // mix-in, might be empty
419  {
420  virtual void
421  cloneInto (void* targetBuffer) const
422  {
423  new(targetBuffer) Adapter(*this); // forward to copy ctor
424  }
425 
426  virtual void
427  copyInto (IFA& targetBase) const
428  {
429  REQUIRE (INSTANCEOF (Adapter, &targetBase));
430  Adapter& target = static_cast<Adapter&> (targetBase);
431  _AssignmentPolicy::assignEmbedded(target,*this);
432  } // forward to assignment operator
433 
434  public: /* == forwarding ctor to implementation type == */
435 
436  template<typename...ARGS>
437  Adapter (ARGS&&... args)
438  : IMP(std::forward<ARGS>(args)...)
439  { }
440 
441  /* using default copy and assignment */
442  };
443 
444  template<typename IMP>
445  using TypeSelector = Adapter<IMP>*;
446 
447 
448  _CopyHandlingAdapter&
449  accessHandlingInterface () const
450  {
451  IFA& bufferContents = accessEmbedded();
452  return _Traits::accessCopyHandlingInterface (bufferContents);
453  }
454 
459  template<class IMP, typename...ARGS>
460  PolymorphicValue (TypeSelector<IMP>, ARGS&&... args)
461  {
462  static_assert (siz >= sizeof(Adapter<IMP>), "insufficient inline buffer size");
463  new(&buf_) Adapter<IMP> (std::forward<ARGS>(args)...);
464  }
465 
466 
467  protected:
475  template<class IMP, typename...ARGS>
476  PolymorphicValue (IMP*, ARGS&&... args)
477  : PolymorphicValue (TypeSelector<IMP>(), std::forward<ARGS>(args)...)
478  { }
479 
480 
481  public: /* === PolymorphicValue public API === */
482 
483  typedef IFA Interface;
484 
485  Interface&
486  getPayload()
487  {
488  return accessEmbedded();
489  }
490 
491  operator Interface& ()
492  {
493  return accessEmbedded();
494  }
495  operator Interface const& () const
496  {
497  return accessEmbedded();
498  }
499  Interface*
500  operator-> () const
501  {
502  return &( accessEmbedded() );
503  }
504 
506  {
507  destroyEmbedded();
508  }
509 
511  {
512  o.accessHandlingInterface().cloneInto (&buf_);
513  }
514 
516  operator= (PolymorphicValue const& o)
517  {
518  o.accessHandlingInterface().copyInto (this->accessEmbedded());
519  return *this;
520  }
521 
522  /* === static factory functions === */
523 
524  template<class IMP, typename...ARGS>
525  static PolymorphicValue
526  build (ARGS&&... args)
527  {
528  Adapter<IMP>* type_to_build_in_buffer(0);
529  return PolymorphicValue (type_to_build_in_buffer, std::forward<ARGS>(args)...);
530  }
531 
532 
533  /* === support Equality by forwarding to embedded === */
534 
535  friend bool
536  operator== (PolymorphicValue const& v1, PolymorphicValue const& v2)
537  {
538  return v1.accessEmbedded() == v2.accessEmbedded();
539  }
540  friend bool
541  operator!= (PolymorphicValue const& v1, PolymorphicValue const& v2)
542  {
543  return not (v1 == v2);
544  }
545  };
546 
547 
548 
549 
550 } // namespace lib
551 #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:492
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:92
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:199
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:104
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.