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);
63 template <typename U, typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
64 void set(NoInitT, U&& value)
67 m_typedHolder.assign(
NoInit, inplace_optional_holder<T>(
NoInit, std::forward<U>(value)));
70 template <typename U, typename std::enable_if<!std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
71 void set(NoInitT, U&& value)
73 m_typedHolder = std::forward<U>(value);
76 void setHolder(
const inplace_optional_holder<T>& value)
78 m_typedHolder = value;
81 void setHolder(inplace_optional_holder<T>&& value)
83 m_typedHolder = std::move(value);
86 template <typename U, typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
87 void setHolder(NoInitT,
const inplace_optional_holder<U>& value)
89 m_typedHolder.assign(
NoInit, value);
92 template <typename U, typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
93 void setHolder(NoInitT, inplace_optional_holder<U>&& value)
95 m_typedHolder.assign(
NoInit, std::move(value));
98 template <typename U, typename std::enable_if<!std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
99 void setHolder(NoInitT,
const inplace_optional_holder<U>& value)
101 m_typedHolder = value;
104 template <typename U, typename std::enable_if<!std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
105 void setHolder(NoInitT, inplace_optional_holder<U>&& value)
107 m_typedHolder = std::move(value);
112 return m_typedHolder.value();
117 return m_typedHolder.value();
120 bool isType(detail::TypeIdHolder::type_id typeId)
const override
122 return detail::TypeIdHolder::get<T>() == typeId;
126 inplace_optional_holder<T>& getHolder()
128 return m_typedHolder;
131 const inplace_optional_holder<T>& getHolder()
const
133 return m_typedHolder;
137 inplace_optional_holder<T> m_typedHolder;
141 template <
typename T,
typename ALLOC>
142 class HeapHolder :
public HolderBase<T, ALLOC>
149 using this_type = HeapHolder<T, ALLOC>;
151 explicit HeapHolder(ConstructTag) noexcept
154 static this_type* create(
const ALLOC& allocator)
156 using AllocType = RebindAlloc<ALLOC, this_type>;
157 using AllocTraits = std::allocator_traits<AllocType>;
159 AllocType typedAlloc = allocator;
160 typename AllocTraits::pointer ptr = AllocTraits::allocate(typedAlloc, 1);
162 AllocTraits::construct(typedAlloc, std::addressof(*ptr), ConstructTag{});
166 IHolder<ALLOC>* clone(
const ALLOC& allocator)
const override
168 this_type* holder = create(allocator);
169 holder->setHolder(this->getHolder());
173 IHolder<ALLOC>* clone(NoInitT,
const ALLOC& allocator)
const override
175 this_type* holder = create(allocator);
176 holder->setHolder(
NoInit, this->getHolder());
180 IHolder<ALLOC>* clone(
void*)
const override
182 throw CppRuntimeException(
"AnyHolder: Unexpected clone call.");
185 IHolder<ALLOC>* clone(NoInitT,
void*)
const override
187 throw CppRuntimeException(
"AnyHolder: Unexpected clone call.");
190 IHolder<ALLOC>* move(
const ALLOC& allocator)
override
192 this_type* holder = create(allocator);
193 holder->setHolder(std::move(this->getHolder()));
197 IHolder<ALLOC>* move(NoInitT,
const ALLOC& allocator)
override
199 this_type* holder = create(allocator);
200 holder->setHolder(
NoInit, std::move(this->getHolder()));
204 IHolder<ALLOC>* move(
void*)
override
206 throw CppRuntimeException(
"AnyHolder: Unexpected move call.");
209 IHolder<ALLOC>* move(NoInitT,
void*)
override
211 throw CppRuntimeException(
"AnyHolder: Unexpected move call.");
214 void destroy(
const ALLOC& allocator)
override
216 using AllocType = RebindAlloc<ALLOC, this_type>;
217 using AllocTraits = std::allocator_traits<AllocType>;
219 AllocType typedAlloc = allocator;
220 AllocTraits::destroy(typedAlloc,
this);
221 AllocTraits::deallocate(typedAlloc,
this, 1);
226 template <
typename T,
typename ALLOC>
227 class NonHeapHolder :
public HolderBase<T, ALLOC>
230 using this_type = NonHeapHolder<T, ALLOC>;
232 static this_type* create(
void* storage)
234 return new (storage) this_type();
237 IHolder<ALLOC>* clone(
const ALLOC&)
const override
239 throw CppRuntimeException(
"AnyHolder: Unexpected clone call.");
242 IHolder<ALLOC>* clone(NoInitT,
const ALLOC&)
const override
244 throw CppRuntimeException(
"AnyHolder: Unexpected clone call.");
247 IHolder<ALLOC>* clone(
void* storage)
const override
249 NonHeapHolder* holder =
new (storage) NonHeapHolder();
250 holder->setHolder(this->getHolder());
254 IHolder<ALLOC>* clone(NoInitT,
void* storage)
const override
256 NonHeapHolder* holder =
new (storage) NonHeapHolder();
257 holder->setHolder(
NoInit, this->getHolder());
261 IHolder<ALLOC>* move(
const ALLOC&)
override
263 throw CppRuntimeException(
"AnyHolder: Unexpected move call.");
266 IHolder<ALLOC>* move(NoInitT,
const ALLOC&)
override
268 throw CppRuntimeException(
"AnyHolder: Unexpected move call.");
271 IHolder<ALLOC>* move(
void* storage)
override
273 NonHeapHolder* holder =
new (storage) NonHeapHolder();
274 holder->setHolder(std::move(this->getHolder()));
278 IHolder<ALLOC>* move(NoInitT,
void* storage)
override
280 NonHeapHolder* holder =
new (storage) NonHeapHolder();
281 holder->setHolder(
NoInit, std::move(this->getHolder()));
285 void destroy(
const ALLOC&)
override
287 this->~NonHeapHolder();
291 NonHeapHolder() =
default;
294 template <
typename ALLOC>
298 using MaxInPlaceType = std::aligned_storage<3 *
sizeof(
void*),
alignof(
void*)>::type;
300 detail::IHolder<ALLOC>* heap;
301 MaxInPlaceType inPlace;
304 template <
typename T,
typename ALLOC>
305 using has_non_heap_holder = std::integral_constant<bool,
306 sizeof(NonHeapHolder<T, ALLOC>) <=
sizeof(
typename UntypedHolder<ALLOC>::MaxInPlaceType) &&
307 std::is_nothrow_move_constructible<T>::value &&
308 alignof(T) <=
alignof(
typename UntypedHolder<ALLOC>::MaxInPlaceType)>;
315 template <
typename ALLOC = std::allocator<u
int8_t>>
318 using AllocTraits = std::allocator_traits<ALLOC>;
339 m_untypedHolder.heap =
nullptr;
347 template <
typename T,
348 typename std::enable_if<!std::is_same<typename std::decay<T>::type,
AnyHolder>::value &&
349 !std::is_same<typename std::decay<T>::type, ALLOC>::value,
351 explicit AnyHolder(T&& value,
const ALLOC& allocator = ALLOC()) :
354 m_untypedHolder.heap =
nullptr;
355 set(std::forward<T>(value));
363 template <
typename T,
364 typename std::enable_if<!std::is_same<typename std::decay<T>::type,
AnyHolder>::value,
int>::type =
369 m_untypedHolder.heap =
nullptr;
442 if (AllocTraits::propagate_on_container_copy_assignment::value)
465 if (AllocTraits::propagate_on_container_copy_assignment::value)
483 move(std::move(other));
494 move(
NoInit, std::move(other));
506 move(std::move(other));
518 move(
NoInit, std::move(other));
533 if (AllocTraits::propagate_on_container_move_assignment::value)
537 move(std::move(other));
555 if (AllocTraits::propagate_on_container_move_assignment::value)
559 move(
NoInit, std::move(other));
572 template <
typename T,
573 typename std::enable_if<!std::is_same<typename std::decay<T>::type,
AnyHolder>::value,
int>::type =
577 set(std::forward<T>(value));
595 template <
typename T>
598 createHolder<typename std::decay<T>::type>()->
set(std::forward<T>(value));
606 template <
typename T>
609 createHolder<typename std::decay<T>::type>()->
set(
NoInit, std::forward<T>(value));
619 template <
typename T>
623 return getHolder<T>(detail::has_non_heap_holder<T, ALLOC>())->get();
633 template <
typename T>
637 return getHolder<T>(detail::has_non_heap_holder<T, ALLOC>())->get();
645 template <
typename T>
648 return hasHolder() && getUntypedHolder()->isType(detail::TypeIdHolder::get<T>());
664 if (other.m_isInPlace)
666 other.getUntypedHolder()->clone(&m_untypedHolder.inPlace);
669 else if (other.m_untypedHolder.heap !=
nullptr)
675 m_untypedHolder.heap =
nullptr;
679 void copy(NoInitT,
const AnyHolder& other)
681 if (other.m_isInPlace)
683 other.getUntypedHolder()->clone(
NoInit, &m_untypedHolder.inPlace);
686 else if (other.m_untypedHolder.heap !=
nullptr)
692 m_untypedHolder.heap =
nullptr;
698 if (other.m_isInPlace)
700 other.getUntypedHolder()->move(&m_untypedHolder.inPlace);
704 else if (other.m_untypedHolder.heap !=
nullptr)
709 m_untypedHolder.heap = other.m_untypedHolder.heap;
710 other.m_untypedHolder.heap =
nullptr;
721 m_untypedHolder.heap =
nullptr;
727 if (other.m_isInPlace)
729 other.getUntypedHolder()->move(
NoInit, &m_untypedHolder.inPlace);
733 else if (other.m_untypedHolder.heap !=
nullptr)
738 m_untypedHolder.heap = other.m_untypedHolder.heap;
739 other.m_untypedHolder.heap =
nullptr;
750 m_untypedHolder.heap =
nullptr;
760 m_untypedHolder.heap =
nullptr;
764 bool hasHolder()
const
766 return (m_isInPlace || m_untypedHolder.heap !=
nullptr);
769 template <
typename T>
770 detail::HolderBase<T, ALLOC>* createHolder()
774 if (getUntypedHolder()->
isType(detail::TypeIdHolder::get<T>()))
776 return getHolder<T>(detail::has_non_heap_holder<T, ALLOC>());
782 return createHolderImpl<T>(detail::has_non_heap_holder<T, ALLOC>());
785 template <
typename T>
786 detail::HolderBase<T, ALLOC>* createHolderImpl(std::true_type)
788 detail::NonHeapHolder<T, ALLOC>* holder =
789 detail::NonHeapHolder<T, ALLOC>::create(&m_untypedHolder.inPlace);
794 template <
typename T>
795 detail::HolderBase<T, ALLOC>* createHolderImpl(std::false_type)
797 detail::HeapHolder<T, ALLOC>* holder = detail::HeapHolder<T, ALLOC>::create(
get_allocator_ref());
798 m_untypedHolder.heap = holder;
802 template <
typename T>
803 void checkType()
const
812 void throwBadType()
const
814 throw CppRuntimeException(
"Bad type in AnyHolder");
817 template <
typename T>
818 detail::HeapHolder<T, ALLOC>* getHeapHolder()
820 return static_cast<detail::HeapHolder<T, ALLOC>*
>(m_untypedHolder.heap);
823 template <
typename T>
824 const detail::HeapHolder<T, ALLOC>* getHeapHolder()
const
826 return static_cast<detail::HeapHolder<T, ALLOC>*
>(m_untypedHolder.heap);
829 template <
typename T>
830 detail::NonHeapHolder<T, ALLOC>* getInplaceHolder()
832 return reinterpret_cast<detail::NonHeapHolder<T, ALLOC>*
>(&m_untypedHolder.inPlace);
835 template <
typename T>
836 const detail::NonHeapHolder<T, ALLOC>* getInplaceHolder()
const
838 return reinterpret_cast<const detail::NonHeapHolder<T, ALLOC>*
>(&m_untypedHolder.inPlace);
841 template <
typename T>
842 detail::HolderBase<T, ALLOC>* getHolder(std::true_type)
844 return static_cast<detail::HolderBase<T, ALLOC>*
>(getInplaceHolder<T>());
847 template <
typename T>
848 detail::HolderBase<T, ALLOC>* getHolder(std::false_type)
850 return static_cast<detail::HolderBase<T, ALLOC>*
>(getHeapHolder<T>());
853 template <
typename T>
854 const detail::HolderBase<T, ALLOC>* getHolder(std::true_type)
const
856 return static_cast<const detail::HolderBase<T, ALLOC>*
>(getInplaceHolder<T>());
859 template <
typename T>
860 const detail::HolderBase<T, ALLOC>* getHolder(std::false_type)
const
862 return static_cast<const detail::HolderBase<T, ALLOC>*
>(getHeapHolder<T>());
865 detail::IHolder<ALLOC>* getUntypedHolder()
868 ?
reinterpret_cast<detail::IHolder<ALLOC>*
>(&m_untypedHolder.inPlace)
869 : m_untypedHolder.heap;
872 const detail::IHolder<ALLOC>* getUntypedHolder()
const
875 ?
reinterpret_cast<const detail::IHolder<ALLOC>*
>(&m_untypedHolder.inPlace)
876 : m_untypedHolder.heap;
879 detail::UntypedHolder<ALLOC> m_untypedHolder;
880 bool m_isInPlace =
false;
allocator_type & get_allocator_ref()
void set_allocator(const allocator_type &allocator)
AnyHolder(NoInitT, T &&value, const ALLOC &allocator=ALLOC())
AnyHolder(const AnyHolder &other, const ALLOC &allocator)
AnyHolder(NoInitT, AnyHolder &&other, const ALLOC &allocator)
AnyHolder(AnyHolder &&other, const ALLOC &allocator)
AnyHolder(const ALLOC &allocator)
AnyHolder(NoInitT, AnyHolder &&other) noexcept
AnyHolder(AnyHolder &&other) noexcept
AnyHolder & operator=(T &&value)
AnyHolder(NoInitT, const AnyHolder &other, const ALLOC &allocator)
AnyHolder & operator=(const AnyHolder &other)
AnyHolder(const AnyHolder &other)
AnyHolder & operator=(AnyHolder &&other)
AnyHolder & assign(NoInitT, AnyHolder &&other)
AnyHolder(NoInitT, const AnyHolder &other)
void set(NoInitT, T &&value)
AnyHolder(T &&value, const ALLOC &allocator=ALLOC())
AnyHolder & assign(NoInitT, const AnyHolder &other)
std::set< T, COMPARE, PropagatingPolymorphicAllocator< T > > set