Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
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
164namespace lib {
165
166 namespace polyvalue { // implementation details...
167
168 namespace error = lumiera::error;
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
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 {
242
243 public:
245 and not 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 {
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:
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&
385 {
386 return * std::launder (reinterpret_cast<IFA*> (&buf_));
387 }
388
389 void
391 {
392 accessEmbedded().~IFA();
393 }
394
395
406 template<class IMP>
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>
437
438
441 {
442 IFA& bufferContents = accessEmbedded();
443 return _Traits::accessCopyHandlingInterface (bufferContents);
444 }
445
450 template<class IMP, typename...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 using Interface = IFA;
475
476 Interface&
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*
492 {
493 return &( accessEmbedded() );
494 }
495
497 {
499 }
500
505
508 {
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
528 {
529 return v1.accessEmbedded() == v2.accessEmbedded();
530 }
531 friend bool
533 {
534 return not (v1 == v2);
535 }
536 };
537
538
539
540
541} // namespace lib
542#endif
Implementation Helper: add support for copy operations.
virtual void cloneInto(void *targetBuffer) const
virtual void copyInto(IFA &targetBase) const
Template to build polymorphic value objects.
PolymorphicValue(TypeSelector< IMP >, ARGS &&... args)
Adapter< IMP > * TypeSelector
PolymorphicValue(PolymorphicValue const &o)
_Traits::Assignment _AssignmentPolicy
_CopyHandlingAdapter & accessHandlingInterface() const
polyvalue::Trait< CPY > _Traits
Interface * operator->() const
static PolymorphicValue build(ARGS &&... args)
friend bool operator!=(PolymorphicValue const &v1, PolymorphicValue const &v2)
PolymorphicValue(IMP *, ARGS &&... args)
friend bool operator==(PolymorphicValue const &v1, PolymorphicValue const &v2)
std::byte buf_[siz]
Storage for embedded objects.
_Traits::CopyAPI _CopyHandlingAdapter
PolymorphicValue & operator=(PolymorphicValue const &o)
A variation for limited copy support.
virtual void cloneInto(void *targetBuffer) const =0
Interface for active support of copy operations by the embedded client objects.
virtual void cloneInto(void *targetBuffer) const =0
virtual void copyInto(IFA &targetBase) const =0
helper to detect if the API supports only copy construction, but no assignment
helper to detect presence of a function to support clone operations
Metaprogramming helpers to check for specific properties of a type in question.
Lumiera error handling (C++ interface).
char Yes_t
helper types to detect the overload resolution chosen by the compiler
Definition meta/util.hpp:99
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
Implementation namespace for support and library code.
LumieraError< LERR_(LOGIC)> Logic
Definition error.hpp:207
STL namespace.
Policy class for invoking the assignment operator.
static void assignEmbedded(IMP &dest, IMP const &src)
trait template to deal with different ways to support copy operations.
AssignmentPolicy< CopyAPI > Assignment
CopySupport< TY, EmptyBase > CopyAPI
static CopyAPI & accessCopyHandlingInterface(TY &bufferContents)
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
#define INSTANCEOF(CLASS, EXPR)
shortcut for subclass test, intended for assertions only.
Definition util.hpp:514