1 #ifndef ZSERIO_ANY_HOLDER_H_INC 2 #define ZSERIO_ANY_HOLDER_H_INC 23 using type_id =
const int*;
28 static int currentTypeId;
30 return ¤tTypeId;
35 template <
typename ALLOC>
39 virtual ~IHolder() =
default;
40 virtual IHolder* clone(
const ALLOC& allocator)
const = 0;
41 virtual IHolder* clone(NoInitT,
const ALLOC& allocator)
const = 0;
42 virtual IHolder* clone(
void* storage)
const = 0;
43 virtual IHolder* clone(NoInitT,
void* storage)
const = 0;
44 virtual IHolder* move(
const ALLOC& allocator) = 0;
45 virtual IHolder* move(NoInitT,
const ALLOC& allocator) = 0;
46 virtual IHolder* move(
void* storage) = 0;
47 virtual IHolder* move(NoInitT,
void* storage) = 0;
48 virtual void destroy(
const ALLOC& allocator) = 0;
49 virtual bool isType(detail::TypeIdHolder::type_id typeId)
const = 0;
53 template <
typename T,
typename ALLOC>
54 class HolderBase :
public IHolder<ALLOC>
60 m_typedHolder = std::forward<U>(value);
64 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
65 void set(NoInitT, U&& value)
68 m_typedHolder.assign(
NoInit, inplace_optional_holder<T>(
NoInit, std::forward<U>(value)));
72 typename std::enable_if<!std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
73 void set(NoInitT, U&& value)
75 m_typedHolder = std::forward<U>(value);
78 void setHolder(
const inplace_optional_holder<T>& value)
80 m_typedHolder = value;
83 void setHolder(inplace_optional_holder<T>&& value)
85 m_typedHolder = std::move(value);
89 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
90 void setHolder(NoInitT,
const inplace_optional_holder<U>& value)
92 m_typedHolder.assign(
NoInit, value);
96 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
97 void setHolder(NoInitT, inplace_optional_holder<U>&& value)
99 m_typedHolder.assign(
NoInit, std::move(value));
102 template <
typename U,
103 typename std::enable_if<!std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
104 void setHolder(NoInitT,
const inplace_optional_holder<U>& value)
106 m_typedHolder = value;
109 template <
typename U,
110 typename std::enable_if<!std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
111 void setHolder(NoInitT, inplace_optional_holder<U>&& value)
113 m_typedHolder = std::move(value);
118 return m_typedHolder.value();
123 return m_typedHolder.value();
126 bool isType(detail::TypeIdHolder::type_id typeId)
const override 128 return detail::TypeIdHolder::get<T>() == typeId;
132 inplace_optional_holder<T>& getHolder()
134 return m_typedHolder;
137 const inplace_optional_holder<T>& getHolder()
const 139 return m_typedHolder;
143 inplace_optional_holder<T> m_typedHolder;
147 template <
typename T,
typename ALLOC>
148 class HeapHolder :
public HolderBase<T, ALLOC>
151 struct ConstructTag {};
154 using this_type = HeapHolder<T, ALLOC>;
156 explicit HeapHolder(ConstructTag) noexcept {}
158 static this_type* create(
const ALLOC& allocator)
160 using AllocType = RebindAlloc<ALLOC, this_type>;
161 using AllocTraits = std::allocator_traits<AllocType>;
163 AllocType typedAlloc = allocator;
164 typename AllocTraits::pointer ptr = AllocTraits::allocate(typedAlloc, 1);
166 AllocTraits::construct(typedAlloc, std::addressof(*ptr), ConstructTag{});
170 IHolder<ALLOC>* clone(
const ALLOC& allocator)
const override 172 this_type* holder = create(allocator);
173 holder->setHolder(this->getHolder());
177 IHolder<ALLOC>* clone(NoInitT,
const ALLOC& allocator)
const override 179 this_type* holder = create(allocator);
180 holder->setHolder(
NoInit, this->getHolder());
184 IHolder<ALLOC>* clone(
void*)
const override 186 throw CppRuntimeException(
"AnyHolder: Unexpected clone call.");
189 IHolder<ALLOC>* clone(NoInitT,
void*)
const override 191 throw CppRuntimeException(
"AnyHolder: Unexpected clone call.");
194 IHolder<ALLOC>* move(
const ALLOC& allocator)
override 196 this_type* holder = create(allocator);
197 holder->setHolder(std::move(this->getHolder()));
201 IHolder<ALLOC>* move(NoInitT,
const ALLOC& allocator)
override 203 this_type* holder = create(allocator);
204 holder->setHolder(
NoInit, std::move(this->getHolder()));
208 IHolder<ALLOC>* move(
void*)
override 210 throw CppRuntimeException(
"AnyHolder: Unexpected move call.");
213 IHolder<ALLOC>* move(NoInitT,
void*)
override 215 throw CppRuntimeException(
"AnyHolder: Unexpected move call.");
218 void destroy(
const ALLOC& allocator)
override 220 using AllocType = RebindAlloc<ALLOC, this_type>;
221 using AllocTraits = std::allocator_traits<AllocType>;
223 AllocType typedAlloc = allocator;
224 AllocTraits::destroy(typedAlloc,
this);
225 AllocTraits::deallocate(typedAlloc,
this, 1);
230 template <
typename T,
typename ALLOC>
231 class NonHeapHolder :
public HolderBase<T, ALLOC>
234 using this_type = NonHeapHolder<T, ALLOC>;
236 static this_type* create(
void* storage)
238 return new (storage) this_type();
241 IHolder<ALLOC>* clone(
const ALLOC&)
const override 243 throw CppRuntimeException(
"AnyHolder: Unexpected clone call.");
246 IHolder<ALLOC>* clone(NoInitT,
const ALLOC&)
const override 248 throw CppRuntimeException(
"AnyHolder: Unexpected clone call.");
251 IHolder<ALLOC>* clone(
void* storage)
const override 253 NonHeapHolder* holder =
new (storage) NonHeapHolder();
254 holder->setHolder(this->getHolder());
258 IHolder<ALLOC>* clone(NoInitT,
void* storage)
const override 260 NonHeapHolder* holder =
new (storage) NonHeapHolder();
261 holder->setHolder(
NoInit, this->getHolder());
265 IHolder<ALLOC>* move(
const ALLOC&)
override 267 throw CppRuntimeException(
"AnyHolder: Unexpected move call.");
270 IHolder<ALLOC>* move(NoInitT,
const ALLOC&)
override 272 throw CppRuntimeException(
"AnyHolder: Unexpected move call.");
275 IHolder<ALLOC>* move(
void* storage)
override 277 NonHeapHolder* holder =
new (storage) NonHeapHolder();
278 holder->setHolder(std::move(this->getHolder()));
282 IHolder<ALLOC>* move(NoInitT,
void* storage)
override 284 NonHeapHolder* holder =
new (storage) NonHeapHolder();
285 holder->setHolder(
NoInit, std::move(this->getHolder()));
289 void destroy(
const ALLOC&)
override 291 this->~NonHeapHolder();
295 NonHeapHolder() =
default;
298 template <
typename ALLOC>
302 using MaxInPlaceType = std::aligned_storage<3 * sizeof(void*), alignof(void*)>::type;
304 detail::IHolder<ALLOC>* heap;
305 MaxInPlaceType inPlace;
308 template <
typename T,
typename ALLOC>
309 using has_non_heap_holder = std::integral_constant<bool,
310 sizeof(NonHeapHolder<T, ALLOC>) <=
sizeof(
typename UntypedHolder<ALLOC>::MaxInPlaceType) &&
311 std::is_nothrow_move_constructible<T>::value &&
312 alignof(T) <=
alignof(
typename UntypedHolder<ALLOC>::MaxInPlaceType)>;
318 template <
typename ALLOC = std::allocator<u
int8_t>>
321 using AllocTraits = std::allocator_traits<ALLOC>;
342 m_untypedHolder.heap =
nullptr;
350 template <
typename T,
351 typename std::enable_if<!std::is_same<typename std::decay<T>::type,
AnyHolder>::value &&
352 !std::is_same<typename std::decay<T>::type, ALLOC>::value,
int>::type = 0>
353 explicit AnyHolder(T&& value,
const ALLOC& allocator = ALLOC()) :
356 m_untypedHolder.heap =
nullptr;
357 set(std::forward<T>(value));
365 template <
typename T,
typename std::enable_if<
366 !std::is_same<typename std::decay<T>::type,
AnyHolder>::value,
int>::type = 0>
367 explicit AnyHolder(NoInitT, T&& value,
const ALLOC& allocator = ALLOC()) :
370 m_untypedHolder.heap =
nullptr;
371 set(
NoInit, std::forward<T>(value));
389 AllocTraits::select_on_container_copy_construction(other.get_allocator_ref()))
401 AllocTraits::select_on_container_copy_construction(other.get_allocator_ref()))
442 if (AllocTraits::propagate_on_container_copy_assignment::value)
463 if (AllocTraits::propagate_on_container_copy_assignment::value)
479 move(std::move(other));
490 move(
NoInit, std::move(other));
502 move(std::move(other));
514 move(
NoInit, std::move(other));
529 if (AllocTraits::propagate_on_container_move_assignment::value)
530 set_allocator(std::move(other.get_allocator_ref()));
531 move(std::move(other));
549 if (AllocTraits::propagate_on_container_move_assignment::value)
550 set_allocator(std::move(other.get_allocator_ref()));
551 move(
NoInit, std::move(other));
564 template <
typename T,
typename 565 std::enable_if<!std::is_same<typename std::decay<T>::type,
AnyHolder>::value,
int>::type = 0>
568 set(std::forward<T>(value));
586 template <
typename T>
589 createHolder<typename std::decay<T>::type>()->
set(std::forward<T>(value));
597 template <
typename T>
598 void set(NoInitT, T&& value)
600 createHolder<typename std::decay<T>::type>()->
set(
NoInit, std::forward<T>(value));
610 template <
typename T>
614 return getHolder<T>(detail::has_non_heap_holder<T, ALLOC>())->get();
624 template <
typename T>
628 return getHolder<T>(detail::has_non_heap_holder<T, ALLOC>())->get();
636 template <
typename T>
639 return hasHolder() && getUntypedHolder()->isType(detail::TypeIdHolder::get<T>());
655 if (other.m_isInPlace)
657 other.getUntypedHolder()->clone(&m_untypedHolder.inPlace);
660 else if (other.m_untypedHolder.heap !=
nullptr)
662 m_untypedHolder.heap = other.getUntypedHolder()->clone(get_allocator_ref());
666 m_untypedHolder.heap =
nullptr;
670 void copy(NoInitT,
const AnyHolder& other)
672 if (other.m_isInPlace)
674 other.getUntypedHolder()->clone(
NoInit, &m_untypedHolder.inPlace);
677 else if (other.m_untypedHolder.heap !=
nullptr)
679 m_untypedHolder.heap = other.getUntypedHolder()->clone(
NoInit,
680 get_allocator_ref());
684 m_untypedHolder.heap =
nullptr;
690 if (other.m_isInPlace)
692 other.getUntypedHolder()->move(&m_untypedHolder.inPlace);
696 else if (other.m_untypedHolder.heap !=
nullptr)
701 m_untypedHolder.heap = other.m_untypedHolder.heap;
702 other.m_untypedHolder.heap =
nullptr;
707 m_untypedHolder.heap = other.getUntypedHolder()->move(get_allocator_ref());
713 m_untypedHolder.heap =
nullptr;
719 if (other.m_isInPlace)
721 other.getUntypedHolder()->move(
NoInit, &m_untypedHolder.inPlace);
725 else if (other.m_untypedHolder.heap !=
nullptr)
730 m_untypedHolder.heap = other.m_untypedHolder.heap;
731 other.m_untypedHolder.heap =
nullptr;
736 m_untypedHolder.heap = other.getUntypedHolder()->move(
NoInit,
737 get_allocator_ref());
743 m_untypedHolder.heap =
nullptr;
751 getUntypedHolder()->destroy(get_allocator_ref());
753 m_untypedHolder.heap =
nullptr;
757 bool hasHolder()
const 759 return (m_isInPlace || m_untypedHolder.heap !=
nullptr);
762 template <
typename T>
763 detail::HolderBase<T, ALLOC>* createHolder()
767 if (getUntypedHolder()->isType(detail::TypeIdHolder::get<T>()))
768 return getHolder<T>(detail::has_non_heap_holder<T, ALLOC>());
773 return createHolderImpl<T>(detail::has_non_heap_holder<T, ALLOC>());
776 template <
typename T>
777 detail::HolderBase<T, ALLOC>* createHolderImpl(std::true_type)
779 detail::NonHeapHolder<T, ALLOC>* holder =
780 detail::NonHeapHolder<T, ALLOC>::create(&m_untypedHolder.inPlace);
785 template <
typename T>
786 detail::HolderBase<T, ALLOC>* createHolderImpl(std::false_type)
788 detail::HeapHolder<T, ALLOC>* holder = detail::HeapHolder<T, ALLOC>::create(get_allocator_ref());
789 m_untypedHolder.heap = holder;
793 template <
typename T>
794 void checkType()
const 801 void throwBadType()
const 806 template <
typename T>
807 detail::HeapHolder<T, ALLOC>* getHeapHolder()
809 return static_cast<detail::HeapHolder<T, ALLOC>*
>(m_untypedHolder.heap);
812 template <
typename T>
813 const detail::HeapHolder<T, ALLOC>* getHeapHolder()
const 815 return static_cast<detail::HeapHolder<T, ALLOC>*
>(m_untypedHolder.heap);
818 template <
typename T>
819 detail::NonHeapHolder<T, ALLOC>* getInplaceHolder()
821 return reinterpret_cast<detail::NonHeapHolder<T, ALLOC>*
>(&m_untypedHolder.inPlace);
824 template <
typename T>
825 const detail::NonHeapHolder<T, ALLOC>* getInplaceHolder()
const 827 return reinterpret_cast<const detail::NonHeapHolder<T, ALLOC>*
>(&m_untypedHolder.inPlace);
830 template <
typename T>
831 detail::HolderBase<T, ALLOC>* getHolder(std::true_type)
833 return static_cast<detail::HolderBase<T, ALLOC>*
>(getInplaceHolder<T>());
836 template <
typename T>
837 detail::HolderBase<T, ALLOC>* getHolder(std::false_type)
839 return static_cast<detail::HolderBase<T, ALLOC>*
>(getHeapHolder<T>());
842 template <
typename T>
843 const detail::HolderBase<T, ALLOC>* getHolder(std::true_type)
const 845 return static_cast<const detail::HolderBase<T, ALLOC>*
>(getInplaceHolder<T>());
848 template <
typename T>
849 const detail::HolderBase<T, ALLOC>* getHolder(std::false_type)
const 851 return static_cast<const detail::HolderBase<T, ALLOC>*
>(getHeapHolder<T>());
854 detail::IHolder<ALLOC>* getUntypedHolder()
856 return (m_isInPlace) ?
857 reinterpret_cast<detail::IHolder<ALLOC>*
>(&m_untypedHolder.inPlace) :
858 m_untypedHolder.heap;
861 const detail::IHolder<ALLOC>* getUntypedHolder()
const 863 return (m_isInPlace) ?
864 reinterpret_cast<const detail::IHolder<ALLOC>*
>(&m_untypedHolder.inPlace) :
865 m_untypedHolder.heap;
868 detail::UntypedHolder<ALLOC> m_untypedHolder;
869 bool m_isInPlace =
false;
874 #endif // ifndef ZSERIO_ANY_HOLDER_H_INC AnyHolder(AnyHolder &&other) noexcept
AnyHolder(AnyHolder &&other, const ALLOC &allocator)
AnyHolder & operator=(T &&value)
AnyHolder(const ALLOC &allocator)
AnyHolder(NoInitT, T &&value, const ALLOC &allocator=ALLOC())
AnyHolder & assign(NoInitT, AnyHolder &&other)
AnyHolder(T &&value, const ALLOC &allocator=ALLOC())
allocator_type & get_allocator_ref()
AnyHolder & operator=(const AnyHolder &other)
AnyHolder(NoInitT, const AnyHolder &other)
AnyHolder & operator=(AnyHolder &&other)
AnyHolder(NoInitT, const AnyHolder &other, const ALLOC &allocator)
AnyHolder(NoInitT, AnyHolder &&other) noexcept
AnyHolder(const AnyHolder &other, const ALLOC &allocator)
AnyHolder(const AnyHolder &other)
AnyHolder(NoInitT, AnyHolder &&other, const ALLOC &allocator)
AnyHolder & assign(NoInitT, const AnyHolder &other)