1 #ifndef ZSERIO_ANY_H_INC
2 #define ZSERIO_ANY_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(
void* storage)
const = 0;
43 virtual IHolder* move(
const ALLOC& allocator) = 0;
44 virtual IHolder* move(
void* storage) = 0;
45 virtual void destroy(
const ALLOC& allocator) = 0;
46 virtual bool isType(detail::TypeIdHolder::type_id typeId)
const = 0;
50 template <
typename T,
typename ALLOC>
51 class HolderBase :
public IHolder<ALLOC>
57 m_typedHolder = std::forward<U>(value);
60 void setHolder(
const std::optional<T>& value)
62 m_typedHolder = value;
65 void setHolder(std::optional<T>&& value)
67 m_typedHolder = std::move(value);
72 return m_typedHolder.value();
77 return m_typedHolder.value();
80 bool isType(detail::TypeIdHolder::type_id typeId)
const override
82 return detail::TypeIdHolder::get<T>() == typeId;
86 std::optional<T>& getHolder()
91 const std::optional<T>& getHolder()
const
97 std::optional<T> m_typedHolder;
101 template <
typename T,
typename ALLOC>
102 class HeapHolder :
public HolderBase<T, ALLOC>
109 using this_type = HeapHolder<T, ALLOC>;
111 explicit HeapHolder(ConstructTag) noexcept
114 static this_type* create(
const ALLOC& allocator)
116 using AllocType = RebindAlloc<ALLOC, this_type>;
117 using AllocTraits = std::allocator_traits<AllocType>;
119 AllocType typedAlloc = allocator;
120 typename AllocTraits::pointer ptr = AllocTraits::allocate(typedAlloc, 1);
122 AllocTraits::construct(typedAlloc, std::addressof(*ptr), ConstructTag{});
126 IHolder<ALLOC>* clone(
const ALLOC& allocator)
const override
128 this_type* holder = create(allocator);
129 holder->setHolder(this->getHolder());
133 IHolder<ALLOC>* clone(
void*)
const override
135 throw CppRuntimeException(
"BasicAny: Unexpected clone call.");
138 IHolder<ALLOC>* move(
const ALLOC& allocator)
override
140 this_type* holder = create(allocator);
141 holder->setHolder(std::move(this->getHolder()));
145 IHolder<ALLOC>* move(
void*)
override
147 throw CppRuntimeException(
"BasicAny: Unexpected move call.");
150 void destroy(
const ALLOC& allocator)
override
152 using AllocType = RebindAlloc<ALLOC, this_type>;
153 using AllocTraits = std::allocator_traits<AllocType>;
155 AllocType typedAlloc = allocator;
156 AllocTraits::destroy(typedAlloc,
this);
157 AllocTraits::deallocate(typedAlloc,
this, 1);
162 template <
typename T,
typename ALLOC>
163 class NonHeapHolder :
public HolderBase<T, ALLOC>
166 using this_type = NonHeapHolder<T, ALLOC>;
168 static this_type* create(
void* storage)
170 return new (storage) this_type();
173 IHolder<ALLOC>* clone(
const ALLOC&)
const override
175 throw CppRuntimeException(
"BasicAny: Unexpected clone call.");
178 IHolder<ALLOC>* clone(
void* storage)
const override
180 NonHeapHolder* holder =
new (storage) NonHeapHolder();
181 holder->setHolder(this->getHolder());
185 IHolder<ALLOC>* move(
const ALLOC&)
override
187 throw CppRuntimeException(
"BasicAny: Unexpected move call.");
190 IHolder<ALLOC>* move(
void* storage)
override
192 NonHeapHolder* holder =
new (storage) NonHeapHolder();
193 holder->setHolder(std::move(this->getHolder()));
197 void destroy(
const ALLOC&)
override
199 this->~NonHeapHolder();
203 NonHeapHolder() =
default;
206 template <
typename ALLOC>
210 using MaxInPlaceType = std::aligned_storage<3 *
sizeof(
void*),
alignof(
void*)>::type;
212 detail::IHolder<ALLOC>* heap;
213 MaxInPlaceType inPlace;
216 template <
typename T,
typename ALLOC>
217 using has_non_heap_holder = std::integral_constant<bool,
218 sizeof(NonHeapHolder<T, ALLOC>) <=
sizeof(
typename UntypedHolder<ALLOC>::MaxInPlaceType) &&
219 std::is_nothrow_move_constructible<T>::value &&
220 alignof(T) <=
alignof(
typename UntypedHolder<ALLOC>::MaxInPlaceType)>;
227 template <
typename ALLOC = std::allocator<u
int8_t>>
230 using AllocTraits = std::allocator_traits<ALLOC>;
251 m_untypedHolder.heap =
nullptr;
259 template <
typename T,
260 typename std::enable_if<!std::is_same<typename std::decay<T>::type,
BasicAny>::value &&
261 !std::is_same<typename std::decay<T>::type, ALLOC>::value,
263 explicit BasicAny(T&& value,
const ALLOC& allocator = ALLOC()) :
266 m_untypedHolder.heap =
nullptr;
267 set(std::forward<T>(value));
315 if constexpr (AllocTraits::propagate_on_container_copy_assignment::value)
333 move(std::move(other));
345 move(std::move(other));
360 if constexpr (AllocTraits::propagate_on_container_move_assignment::value)
364 move(std::move(other));
377 template <
typename T,
378 typename std::enable_if<!std::is_same<typename std::decay<T>::type,
BasicAny>::value,
int>::type =
382 set(std::forward<T>(value));
400 template <
typename T>
403 createHolder<typename std::decay<T>::type>()->
set(std::forward<T>(value));
413 template <
typename T>
417 return getHolder<T>(detail::has_non_heap_holder<T, ALLOC>())->get();
427 template <
typename T>
431 return getHolder<T>(detail::has_non_heap_holder<T, ALLOC>())->get();
439 template <
typename T>
442 return hasHolder() && getUntypedHolder()->isType(detail::TypeIdHolder::get<T>());
458 if (other.m_isInPlace)
460 other.getUntypedHolder()->clone(&m_untypedHolder.inPlace);
463 else if (other.m_untypedHolder.heap !=
nullptr)
469 m_untypedHolder.heap =
nullptr;
475 if (other.m_isInPlace)
477 other.getUntypedHolder()->move(&m_untypedHolder.inPlace);
481 else if (other.m_untypedHolder.heap !=
nullptr)
486 m_untypedHolder.heap = other.m_untypedHolder.heap;
487 other.m_untypedHolder.heap =
nullptr;
498 m_untypedHolder.heap =
nullptr;
508 m_untypedHolder.heap =
nullptr;
512 bool hasHolder()
const
514 return (m_isInPlace || m_untypedHolder.heap !=
nullptr);
517 template <
typename T>
518 detail::HolderBase<T, ALLOC>* createHolder()
522 if (getUntypedHolder()->
isType(detail::TypeIdHolder::get<T>()))
524 return getHolder<T>(detail::has_non_heap_holder<T, ALLOC>());
530 return createHolderImpl<T>(detail::has_non_heap_holder<T, ALLOC>());
533 template <
typename T>
534 detail::HolderBase<T, ALLOC>* createHolderImpl(std::true_type)
536 detail::NonHeapHolder<T, ALLOC>* holder =
537 detail::NonHeapHolder<T, ALLOC>::create(&m_untypedHolder.inPlace);
542 template <
typename T>
543 detail::HolderBase<T, ALLOC>* createHolderImpl(std::false_type)
545 detail::HeapHolder<T, ALLOC>* holder = detail::HeapHolder<T, ALLOC>::create(
get_allocator_ref());
546 m_untypedHolder.heap = holder;
550 template <
typename T>
551 void checkType()
const
560 void throwBadType()
const
562 throw CppRuntimeException(
"Bad type in BasicAny");
565 template <
typename T>
566 detail::HeapHolder<T, ALLOC>* getHeapHolder()
568 return static_cast<detail::HeapHolder<T, ALLOC>*
>(m_untypedHolder.heap);
571 template <
typename T>
572 const detail::HeapHolder<T, ALLOC>* getHeapHolder()
const
574 return static_cast<detail::HeapHolder<T, ALLOC>*
>(m_untypedHolder.heap);
577 template <
typename T>
578 detail::NonHeapHolder<T, ALLOC>* getInplaceHolder()
580 return reinterpret_cast<detail::NonHeapHolder<T, ALLOC>*
>(&m_untypedHolder.inPlace);
583 template <
typename T>
584 const detail::NonHeapHolder<T, ALLOC>* getInplaceHolder()
const
586 return reinterpret_cast<const detail::NonHeapHolder<T, ALLOC>*
>(&m_untypedHolder.inPlace);
589 template <
typename T>
590 detail::HolderBase<T, ALLOC>* getHolder(std::true_type)
592 return static_cast<detail::HolderBase<T, ALLOC>*
>(getInplaceHolder<T>());
595 template <
typename T>
596 detail::HolderBase<T, ALLOC>* getHolder(std::false_type)
598 return static_cast<detail::HolderBase<T, ALLOC>*
>(getHeapHolder<T>());
601 template <
typename T>
602 const detail::HolderBase<T, ALLOC>* getHolder(std::true_type)
const
604 return static_cast<const detail::HolderBase<T, ALLOC>*
>(getInplaceHolder<T>());
607 template <
typename T>
608 const detail::HolderBase<T, ALLOC>* getHolder(std::false_type)
const
610 return static_cast<const detail::HolderBase<T, ALLOC>*
>(getHeapHolder<T>());
613 detail::IHolder<ALLOC>* getUntypedHolder()
616 ?
reinterpret_cast<detail::IHolder<ALLOC>*
>(&m_untypedHolder.inPlace)
617 : m_untypedHolder.heap;
620 const detail::IHolder<ALLOC>* getUntypedHolder()
const
623 ?
reinterpret_cast<const detail::IHolder<ALLOC>*
>(&m_untypedHolder.inPlace)
624 : m_untypedHolder.heap;
627 detail::UntypedHolder<ALLOC> m_untypedHolder;
628 bool m_isInPlace =
false;
allocator_type & get_allocator_ref()
void set_allocator(const allocator_type &allocator)
BasicAny(const BasicAny &other)
BasicAny(const BasicAny &other, const ALLOC &allocator)
BasicAny & operator=(BasicAny &&other)
BasicAny(T &&value, const ALLOC &allocator=ALLOC())
BasicAny & operator=(const BasicAny &other)
BasicAny(BasicAny &&other) noexcept
BasicAny(const ALLOC &allocator)
BasicAny & operator=(T &&value)
BasicAny(BasicAny &&other, const ALLOC &allocator)
decltype(auto) get(BasicVariant< ALLOC, INDEX, T... > &var)