1 #ifndef ZSERIO_OPTIONAL_HOLDER_H_INC
2 #define ZSERIO_OPTIONAL_HOLDER_H_INC
52 template <
typename T,
typename Derived>
53 class optional_holder_base
63 bool operator==(
const optional_holder_base& other)
const
70 if (getDerived()->hasValue() != other.getDerived()->hasValue())
75 if (getDerived()->hasValue())
77 return get() == other.get();
90 bool operator<(
const optional_holder_base& other)
const
92 if (getDerived()->hasValue() && other.getDerived()->hasValue())
94 return get() < other.get();
97 return !getDerived()->hasValue() && other.getDerived()->hasValue();
105 explicit operator bool() const noexcept
107 return getDerived()->hasValue();
117 const T* operator->()
const
119 return std::addressof(get());
131 return std::addressof(get());
141 const T& value()
const
159 void checkHasValue()
const
161 if (!getDerived()->hasValue())
163 throwNonPresentException();
170 return getDerived()->operator*();
175 return getDerived()->operator*();
178 Derived* getDerived()
180 return static_cast<Derived*
>(
this);
183 const Derived* getDerived()
const
185 return static_cast<const Derived*
>(
this);
189 void throwNonPresentException()
const
191 throw CppRuntimeException(
"Trying to access value of non-present optional field!");
198 template <
typename T,
typename ALLOC>
199 class heap_optional_holder :
public optional_holder_base<T, heap_optional_holder<T, ALLOC>>
202 using allocator_type = ALLOC;
203 using allocator_traits = std::allocator_traits<allocator_type>;
204 using value_type = T;
212 allocator_type get_allocator()
const
214 return m_storage.get_deleter().get_allocator();
222 explicit constexpr heap_optional_holder(
const allocator_type& allocator = allocator_type()) noexcept :
223 m_storage(
nullptr, allocator)
231 constexpr heap_optional_holder(NullOptType,
const allocator_type& allocator = allocator_type()) noexcept :
232 m_storage(
nullptr, allocator)
241 heap_optional_holder(
const T& val,
const allocator_type& allocator = allocator_type()) :
251 heap_optional_holder(T&& val,
const allocator_type& allocator = allocator_type()) :
262 template <
typename U = T,
263 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
264 heap_optional_holder(NoInitT, T&& val,
const allocator_type& allocator = allocator_type()) :
274 template <
typename... U>
275 explicit heap_optional_holder(
const allocator_type& allocator, U&&... parameters) :
282 ~heap_optional_holder() =
default;
289 heap_optional_holder(
const heap_optional_holder& other) :
290 m_storage(copy_initialize(
291 other, allocator_traits::select_on_container_copy_construction(other.get_allocator())))
299 template <
typename U = T,
300 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
301 heap_optional_holder(NoInitT,
const heap_optional_holder& other) :
302 m_storage(copy_initialize(
NoInit, other,
303 allocator_traits::select_on_container_copy_construction(other.get_allocator())))
312 heap_optional_holder(
const heap_optional_holder& other,
const allocator_type& allocator) :
313 m_storage(copy_initialize(other, allocator))
321 heap_optional_holder(heap_optional_holder&& other) noexcept =
default;
328 template <
typename U = T,
329 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
330 heap_optional_holder(NoInitT, heap_optional_holder&& other) :
331 m_storage(move_initialize(
NoInit, std::move(other), other.get_allocator()))
340 heap_optional_holder(heap_optional_holder&& other,
const allocator_type& allocator) :
341 m_storage(move_initialize(std::move(other), allocator))
351 heap_optional_holder& operator=(
const heap_optional_holder& other)
358 m_storage = copy_initialize(other,
359 select_allocator(other.get_allocator(),
360 typename allocator_traits::propagate_on_container_copy_assignment()));
372 template <
typename U = T,
373 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
374 heap_optional_holder& assign(NoInitT,
const heap_optional_holder& other)
381 m_storage = copy_initialize(
NoInit, other,
382 select_allocator(other.get_allocator(),
383 typename allocator_traits::propagate_on_container_copy_assignment()));
395 heap_optional_holder& operator=(heap_optional_holder&& other)
402 m_storage = move_initialize(std::move(other),
403 select_allocator(other.get_allocator(),
404 typename allocator_traits::propagate_on_container_move_assignment()));
416 template <
typename U = T,
417 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
418 heap_optional_holder& assign(NoInitT, heap_optional_holder&& other)
425 m_storage = move_initialize(
NoInit, std::move(other),
426 select_allocator(other.get_allocator(),
427 typename allocator_traits::propagate_on_container_move_assignment()));
439 heap_optional_holder& operator=(
const T& val)
453 heap_optional_holder& operator=(T&& val)
463 void reset() noexcept
473 bool hasValue() const noexcept
475 return static_cast<bool>(m_storage);
485 const T& operator*()
const
487 this->checkHasValue();
488 return *m_storage.get();
500 this->checkHasValue();
501 return *m_storage.get();
505 allocator_type select_allocator(allocator_type other_allocator, std::true_type)
507 return other_allocator;
510 allocator_type select_allocator(allocator_type, std::false_type)
512 return get_allocator();
515 template <
typename U = T>
519 m_storage = zserio::allocate_unique<T, allocator_type>(get_allocator(), std::forward<U>(val));
522 static storage_type copy_initialize(
const heap_optional_holder& other,
const allocator_type& allocator)
524 if (other.hasValue())
526 return zserio::allocate_unique<T, allocator_type>(allocator, *other);
530 return storage_type(
nullptr, allocator);
534 static storage_type copy_initialize(
535 NoInitT,
const heap_optional_holder& other,
const allocator_type& allocator)
537 if (other.hasValue())
539 return zserio::allocate_unique<T, allocator_type>(allocator,
NoInit, *other);
543 return storage_type(
nullptr, allocator);
547 static storage_type move_initialize(heap_optional_holder&& other,
const allocator_type& allocator)
549 if (other.hasValue())
551 if (allocator == other.get_allocator())
553 return std::move(other.m_storage);
556 return zserio::allocate_unique<T, allocator_type>(allocator, std::move(*other));
560 return storage_type(
nullptr, allocator);
564 static storage_type move_initialize(NoInitT, heap_optional_holder&& other,
const allocator_type& allocator)
566 if (other.hasValue())
568 if (allocator == other.get_allocator())
570 return std::move(other.m_storage);
573 return zserio::allocate_unique<T, allocator_type>(allocator,
NoInit, std::move(*other));
577 return storage_type(
nullptr, allocator);
581 storage_type m_storage;
587 template <
typename T>
588 class in_place_storage
594 in_place_storage() =
default;
599 ~in_place_storage() =
default;
603 in_place_storage(
const in_place_storage&) =
delete;
604 in_place_storage& operator=(
const in_place_storage&) =
delete;
608 in_place_storage(in_place_storage&& other) =
delete;
617 in_place_storage& operator=(in_place_storage&& other)
619 new (&m_inPlace) T(std::move(*other.getObject()));
620 other.getObject()->~T();
632 in_place_storage& assign(NoInitT, in_place_storage&& other)
634 new (&m_inPlace) T(
NoInit, std::move(*other.getObject()));
635 other.getObject()->~T();
657 return reinterpret_cast<T*
>(&m_inPlace);
665 const T* getObject()
const
667 return reinterpret_cast<const T*
>(&m_inPlace);
675 static constexpr
size_t SIZEOF_T =
sizeof(T);
676 static constexpr
size_t ALIGNOF_T =
alignof(T);
677 using AlignedStorage =
typename std::aligned_storage<SIZEOF_T, ALIGNOF_T>::type;
678 AlignedStorage m_inPlace;
684 template <
typename T>
685 class inplace_optional_holder :
public optional_holder_base<T, inplace_optional_holder<T>>
688 using value_type = T;
693 constexpr inplace_optional_holder() noexcept = default;
698 constexpr inplace_optional_holder(NullOptType) noexcept
706 inplace_optional_holder(
const T& val)
708 new (m_storage.getStorage()) T(val);
717 inplace_optional_holder(T&& val)
719 new (m_storage.getStorage()) T(std::move(val));
729 template <
typename U = T,
730 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
731 inplace_optional_holder(NoInitT, T&& val)
733 new (m_storage.getStorage()) T(
NoInit, std::move(val));
742 inplace_optional_holder(
const inplace_optional_holder& other)
744 if (other.hasValue())
746 new (m_storage.getStorage()) T(*other.m_storage.getObject());
756 template <
typename U = T,
757 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
758 inplace_optional_holder(NoInitT,
const inplace_optional_holder& other)
760 if (other.hasValue())
762 new (m_storage.getStorage()) T(
NoInit, *other.m_storage.getObject());
772 inplace_optional_holder(inplace_optional_holder&& other) noexcept(
773 std::is_nothrow_move_constructible<in_place_storage<T>>::value)
775 if (other.hasValue())
777 m_storage = std::move(other.m_storage);
778 other.m_hasValue =
false;
788 template <
typename U = T,
789 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
790 inplace_optional_holder(NoInitT, inplace_optional_holder&& other) noexcept(
791 std::is_nothrow_move_constructible<in_place_storage<T>>::value)
793 if (other.hasValue())
795 m_storage.assign(
NoInit, std::move(other.m_storage));
796 other.m_hasValue =
false;
806 template <
typename... U>
807 explicit inplace_optional_holder(InPlaceT, U&&... parameters)
809 new (m_storage.getStorage()) T(std::forward<U>(parameters)...);
816 ~inplace_optional_holder()
828 inplace_optional_holder& operator=(
const inplace_optional_holder& other)
833 if (other.hasValue())
835 new (m_storage.getStorage()) T(*other.m_storage.getObject());
850 template <
typename U = T,
851 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
852 inplace_optional_holder& assign(NoInitT,
const inplace_optional_holder& other)
857 if (other.hasValue())
859 new (m_storage.getStorage()) T(
NoInit, *other.m_storage.getObject());
874 inplace_optional_holder& operator=(inplace_optional_holder&& other)
879 if (other.hasValue())
881 m_storage = std::move(other.m_storage);
882 other.m_hasValue =
false;
897 template <
typename U = T,
898 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
899 inplace_optional_holder& assign(NoInitT, inplace_optional_holder&& other)
904 if (other.hasValue())
906 m_storage.assign(
NoInit, std::move(other.m_storage));
907 other.m_hasValue =
false;
922 inplace_optional_holder& operator=(
const T& val)
936 inplace_optional_holder& operator=(T&& val)
946 void reset() noexcept
950 m_storage.getObject()->~T();
960 bool hasValue() const noexcept
972 const T& operator*()
const
974 this->checkHasValue();
975 return *m_storage.getObject();
987 this->checkHasValue();
988 return *m_storage.getObject();
992 template <
typename U = T>
996 new (m_storage.getStorage()) T(std::forward<U>(val));
1000 in_place_storage<T> m_storage;
1001 bool m_hasValue =
false;
1011 template <
typename T>
1017 template <
typename T,
typename ALLOC = std::allocator<T>>
std::set< T, COMPARE, PropagatingPolymorphicAllocator< T > > set
zserio::unique_ptr< T, RebindAlloc< ALLOC, T > > allocate_unique(const ALLOC &allocator, Args &&... args)
constexpr bool operator<(BasicStringView< CharT, Traits > lhs, BasicStringView< CharT, Traits > rhs) noexcept
constexpr NullOptType NullOpt
constexpr bool operator==(BasicStringView< CharT, Traits > lhs, BasicStringView< CharT, Traits > rhs) noexcept
detail::heap_optional_holder< T, ALLOC > HeapOptionalHolder
std::unique_ptr< T, detail::UniquePtrDeleter< ALLOC > > unique_ptr
constexpr InPlaceT InPlace
detail::inplace_optional_holder< T > InplaceOptionalHolder
constexpr InPlaceT()=default
constexpr NullOptType(int)