1 #ifndef ZSERIO_ANY_HOLDER_H_INC
2 #define ZSERIO_ANY_HOLDER_H_INC
24 using type_id =
const int*;
29 static int currentTypeId;
31 return ¤tTypeId;
36 template <
typename ALLOC>
40 virtual ~IHolder() =
default;
41 virtual IHolder* clone(
const ALLOC& allocator)
const = 0;
42 virtual IHolder* clone(NoInitT,
const ALLOC& allocator)
const = 0;
43 virtual IHolder* clone(
void* storage)
const = 0;
44 virtual IHolder* clone(NoInitT,
void* storage)
const = 0;
45 virtual IHolder* move(
const ALLOC& allocator) = 0;
46 virtual IHolder* move(NoInitT,
const ALLOC& allocator) = 0;
47 virtual IHolder* move(
void* storage) = 0;
48 virtual IHolder* move(NoInitT,
void* storage) = 0;
49 virtual void destroy(
const ALLOC& allocator) = 0;
50 virtual bool isType(detail::TypeIdHolder::type_id typeId)
const = 0;
54 template <
typename T,
typename ALLOC>
55 class HolderBase :
public IHolder<ALLOC>
61 m_typedHolder = std::forward<U>(value);
64 template <typename U, 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)));
71 template <typename U, typename std::enable_if<!std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
72 void set(NoInitT, U&& value)
74 m_typedHolder = std::forward<U>(value);
77 void setHolder(
const inplace_optional_holder<T>& value)
79 m_typedHolder = value;
82 void setHolder(inplace_optional_holder<T>&& value)
84 m_typedHolder = std::move(value);
87 template <typename U, typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
88 void setHolder(NoInitT,
const inplace_optional_holder<U>& value)
90 m_typedHolder.assign(
NoInit, value);
93 template <typename U, typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
94 void setHolder(NoInitT, inplace_optional_holder<U>&& value)
96 m_typedHolder.assign(
NoInit, std::move(value));
99 template <typename U, typename std::enable_if<!std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
100 void setHolder(NoInitT,
const inplace_optional_holder<U>& value)
102 m_typedHolder = value;
105 template <typename U, typename std::enable_if<!std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
106 void setHolder(NoInitT, inplace_optional_holder<U>&& value)
108 m_typedHolder = std::move(value);
113 return m_typedHolder.value();
118 return m_typedHolder.value();
121 bool isType(detail::TypeIdHolder::type_id typeId)
const override
123 return detail::TypeIdHolder::get<T>() == typeId;
127 inplace_optional_holder<T>& getHolder()
129 return m_typedHolder;
132 const inplace_optional_holder<T>& getHolder()
const
134 return m_typedHolder;
138 inplace_optional_holder<T> m_typedHolder;
142 template <
typename T,
typename ALLOC>
143 class HeapHolder :
public HolderBase<T, ALLOC>
150 using this_type = HeapHolder<T, ALLOC>;
152 explicit HeapHolder(ConstructTag) noexcept
155 static this_type* create(
const ALLOC& allocator)
157 using AllocType = RebindAlloc<ALLOC, this_type>;
158 using AllocTraits = std::allocator_traits<AllocType>;
160 AllocType typedAlloc = allocator;
161 typename AllocTraits::pointer ptr = AllocTraits::allocate(typedAlloc, 1);
163 AllocTraits::construct(typedAlloc, std::addressof(*ptr), ConstructTag{});
167 IHolder<ALLOC>* clone(
const ALLOC& allocator)
const override
169 this_type* holder = create(allocator);
170 holder->setHolder(this->getHolder());
174 IHolder<ALLOC>* clone(NoInitT,
const ALLOC& allocator)
const override
176 this_type* holder = create(allocator);
177 holder->setHolder(
NoInit, this->getHolder());
181 IHolder<ALLOC>* clone(
void*)
const override
183 throw CppRuntimeException(
"AnyHolder: Unexpected clone call.");
186 IHolder<ALLOC>* clone(NoInitT,
void*)
const override
188 throw CppRuntimeException(
"AnyHolder: Unexpected clone call.");
191 IHolder<ALLOC>* move(
const ALLOC& allocator)
override
193 this_type* holder = create(allocator);
194 holder->setHolder(std::move(this->getHolder()));
198 IHolder<ALLOC>* move(NoInitT,
const ALLOC& allocator)
override
200 this_type* holder = create(allocator);
201 holder->setHolder(
NoInit, std::move(this->getHolder()));
205 IHolder<ALLOC>* move(
void*)
override
207 throw CppRuntimeException(
"AnyHolder: Unexpected move call.");
210 IHolder<ALLOC>* move(NoInitT,
void*)
override
212 throw CppRuntimeException(
"AnyHolder: Unexpected move call.");
215 void destroy(
const ALLOC& allocator)
override
217 using AllocType = RebindAlloc<ALLOC, this_type>;
218 using AllocTraits = std::allocator_traits<AllocType>;
220 AllocType typedAlloc = allocator;
221 AllocTraits::destroy(typedAlloc,
this);
222 AllocTraits::deallocate(typedAlloc,
this, 1);
227 template <
typename T,
typename ALLOC>
228 class NonHeapHolder :
public HolderBase<T, ALLOC>
231 using this_type = NonHeapHolder<T, ALLOC>;
233 static this_type* create(
void* storage)
235 return new (storage) this_type();
238 IHolder<ALLOC>* clone(
const ALLOC&)
const override
240 throw CppRuntimeException(
"AnyHolder: Unexpected clone call.");
243 IHolder<ALLOC>* clone(NoInitT,
const ALLOC&)
const override
245 throw CppRuntimeException(
"AnyHolder: Unexpected clone call.");
248 IHolder<ALLOC>* clone(
void* storage)
const override
250 NonHeapHolder* holder =
new (storage) NonHeapHolder();
251 holder->setHolder(this->getHolder());
255 IHolder<ALLOC>* clone(NoInitT,
void* storage)
const override
257 NonHeapHolder* holder =
new (storage) NonHeapHolder();
258 holder->setHolder(
NoInit, this->getHolder());
262 IHolder<ALLOC>* move(
const ALLOC&)
override
264 throw CppRuntimeException(
"AnyHolder: Unexpected move call.");
267 IHolder<ALLOC>* move(NoInitT,
const ALLOC&)
override
269 throw CppRuntimeException(
"AnyHolder: Unexpected move call.");
272 IHolder<ALLOC>* move(
void* storage)
override
274 NonHeapHolder* holder =
new (storage) NonHeapHolder();
275 holder->setHolder(std::move(this->getHolder()));
279 IHolder<ALLOC>* move(NoInitT,
void* storage)
override
281 NonHeapHolder* holder =
new (storage) NonHeapHolder();
282 holder->setHolder(
NoInit, std::move(this->getHolder()));
286 void destroy(
const ALLOC&)
override
288 this->~NonHeapHolder();
292 NonHeapHolder() =
default;
295 template <
typename ALLOC>
299 using MaxInPlaceType = std::aligned_storage<3 *
sizeof(
void*),
alignof(
void*)>::type;
301 detail::IHolder<ALLOC>* heap;
302 MaxInPlaceType inPlace;
305 template <
typename T,
typename ALLOC>
306 using has_non_heap_holder = std::integral_constant<bool,
307 sizeof(NonHeapHolder<T, ALLOC>) <=
sizeof(
typename UntypedHolder<ALLOC>::MaxInPlaceType) &&
308 std::is_nothrow_move_constructible<T>::value &&
309 alignof(T) <=
alignof(
typename UntypedHolder<ALLOC>::MaxInPlaceType)>;
316 template <
typename ALLOC = std::allocator<u
int8_t>>
319 using AllocTraits = std::allocator_traits<ALLOC>;
340 m_untypedHolder.heap =
nullptr;
348 template <
typename T,
349 typename std::enable_if<!std::is_same<typename std::decay<T>::type,
AnyHolder>::value &&
350 !std::is_same<typename std::decay<T>::type, ALLOC>::value,
352 explicit AnyHolder(T&& value,
const ALLOC& allocator = ALLOC()) :
355 m_untypedHolder.heap =
nullptr;
356 set(std::forward<T>(value));
364 template <
typename T,
365 typename std::enable_if<!std::is_same<typename std::decay<T>::type,
AnyHolder>::value,
int>::type =
370 m_untypedHolder.heap =
nullptr;
443 if (AllocTraits::propagate_on_container_copy_assignment::value)
466 if (AllocTraits::propagate_on_container_copy_assignment::value)
484 move(std::move(other));
495 move(
NoInit, std::move(other));
507 move(std::move(other));
519 move(
NoInit, std::move(other));
534 if (AllocTraits::propagate_on_container_move_assignment::value)
538 move(std::move(other));
556 if (AllocTraits::propagate_on_container_move_assignment::value)
560 move(
NoInit, std::move(other));
573 template <
typename T,
574 typename std::enable_if<!std::is_same<typename std::decay<T>::type,
AnyHolder>::value,
int>::type =
578 set(std::forward<T>(value));
596 template <
typename T>
599 createHolder<typename std::decay<T>::type>()->
set(std::forward<T>(value));
607 template <
typename T>
610 createHolder<typename std::decay<T>::type>()->
set(
NoInit, std::forward<T>(value));
620 template <
typename T>
624 return getHolder<T>(detail::has_non_heap_holder<T, ALLOC>())->get();
634 template <
typename T>
638 return getHolder<T>(detail::has_non_heap_holder<T, ALLOC>())->get();
646 template <
typename T>
649 return hasHolder() && getUntypedHolder()->isType(detail::TypeIdHolder::get<T>());
665 if (other.m_isInPlace)
667 other.getUntypedHolder()->clone(&m_untypedHolder.inPlace);
670 else if (other.m_untypedHolder.heap !=
nullptr)
676 m_untypedHolder.heap =
nullptr;
680 void copy(NoInitT,
const AnyHolder& other)
682 if (other.m_isInPlace)
684 other.getUntypedHolder()->clone(
NoInit, &m_untypedHolder.inPlace);
687 else if (other.m_untypedHolder.heap !=
nullptr)
693 m_untypedHolder.heap =
nullptr;
699 if (other.m_isInPlace)
701 other.getUntypedHolder()->move(&m_untypedHolder.inPlace);
705 else if (other.m_untypedHolder.heap !=
nullptr)
710 m_untypedHolder.heap = other.m_untypedHolder.heap;
711 other.m_untypedHolder.heap =
nullptr;
722 m_untypedHolder.heap =
nullptr;
728 if (other.m_isInPlace)
730 other.getUntypedHolder()->move(
NoInit, &m_untypedHolder.inPlace);
734 else if (other.m_untypedHolder.heap !=
nullptr)
739 m_untypedHolder.heap = other.m_untypedHolder.heap;
740 other.m_untypedHolder.heap =
nullptr;
751 m_untypedHolder.heap =
nullptr;
761 m_untypedHolder.heap =
nullptr;
765 bool hasHolder()
const
767 return (m_isInPlace || m_untypedHolder.heap !=
nullptr);
770 template <
typename T>
771 detail::HolderBase<T, ALLOC>* createHolder()
775 if (getUntypedHolder()->
isType(detail::TypeIdHolder::get<T>()))
777 return getHolder<T>(detail::has_non_heap_holder<T, ALLOC>());
783 return createHolderImpl<T>(detail::has_non_heap_holder<T, ALLOC>());
786 template <
typename T>
787 detail::HolderBase<T, ALLOC>* createHolderImpl(std::true_type)
789 detail::NonHeapHolder<T, ALLOC>* holder =
790 detail::NonHeapHolder<T, ALLOC>::create(&m_untypedHolder.inPlace);
795 template <
typename T>
796 detail::HolderBase<T, ALLOC>* createHolderImpl(std::false_type)
798 detail::HeapHolder<T, ALLOC>* holder = detail::HeapHolder<T, ALLOC>::create(
get_allocator_ref());
799 m_untypedHolder.heap = holder;
803 template <
typename T>
804 void checkType()
const
813 void throwBadType()
const
815 throw CppRuntimeException(
"Bad type in AnyHolder");
818 template <
typename T>
819 detail::HeapHolder<T, ALLOC>* getHeapHolder()
821 return static_cast<detail::HeapHolder<T, ALLOC>*
>(m_untypedHolder.heap);
824 template <
typename T>
825 const detail::HeapHolder<T, ALLOC>* getHeapHolder()
const
827 return static_cast<detail::HeapHolder<T, ALLOC>*
>(m_untypedHolder.heap);
830 template <
typename T>
831 detail::NonHeapHolder<T, ALLOC>* getInplaceHolder()
833 return reinterpret_cast<detail::NonHeapHolder<T, ALLOC>*
>(&m_untypedHolder.inPlace);
836 template <
typename T>
837 const detail::NonHeapHolder<T, ALLOC>* getInplaceHolder()
const
839 return reinterpret_cast<const detail::NonHeapHolder<T, ALLOC>*
>(&m_untypedHolder.inPlace);
842 template <
typename T>
843 detail::HolderBase<T, ALLOC>* getHolder(std::true_type)
845 return static_cast<detail::HolderBase<T, ALLOC>*
>(getInplaceHolder<T>());
848 template <
typename T>
849 detail::HolderBase<T, ALLOC>* getHolder(std::false_type)
851 return static_cast<detail::HolderBase<T, ALLOC>*
>(getHeapHolder<T>());
854 template <
typename T>
855 const detail::HolderBase<T, ALLOC>* getHolder(std::true_type)
const
857 return static_cast<const detail::HolderBase<T, ALLOC>*
>(getInplaceHolder<T>());
860 template <
typename T>
861 const detail::HolderBase<T, ALLOC>* getHolder(std::false_type)
const
863 return static_cast<const detail::HolderBase<T, ALLOC>*
>(getHeapHolder<T>());
866 detail::IHolder<ALLOC>* getUntypedHolder()
869 ?
reinterpret_cast<detail::IHolder<ALLOC>*
>(&m_untypedHolder.inPlace)
870 : m_untypedHolder.heap;
873 const detail::IHolder<ALLOC>* getUntypedHolder()
const
876 ?
reinterpret_cast<const detail::IHolder<ALLOC>*
>(&m_untypedHolder.inPlace)
877 : m_untypedHolder.heap;
880 detail::UntypedHolder<ALLOC> m_untypedHolder;
881 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