1 #ifndef ZSERIO_OPTIONAL_HOLDER_H_INC
2 #define ZSERIO_OPTIONAL_HOLDER_H_INC
53 template <
typename T,
typename Derived>
54 class optional_holder_base
64 bool operator==(
const optional_holder_base& other)
const
71 if (getDerived()->hasValue() != other.getDerived()->hasValue())
76 if (getDerived()->hasValue())
78 return get() == other.get();
91 bool operator<(
const optional_holder_base& other)
const
93 if (getDerived()->hasValue() && other.getDerived()->hasValue())
95 return get() < other.get();
98 return !getDerived()->hasValue() && other.getDerived()->hasValue();
106 explicit operator bool() const noexcept
108 return getDerived()->hasValue();
118 const T* operator->()
const
120 return std::addressof(get());
132 return std::addressof(get());
142 const T& value()
const
160 void checkHasValue()
const
162 if (!getDerived()->hasValue())
164 throwNonPresentException();
171 return getDerived()->operator*();
176 return getDerived()->operator*();
179 Derived* getDerived()
181 return static_cast<Derived*
>(
this);
184 const Derived* getDerived()
const
186 return static_cast<const Derived*
>(
this);
190 void throwNonPresentException()
const
192 throw CppRuntimeException(
"Trying to access value of non-present optional field!");
199 template <
typename T,
typename ALLOC>
200 class heap_optional_holder :
public optional_holder_base<T, heap_optional_holder<T, ALLOC>>
203 using allocator_type = ALLOC;
204 using allocator_traits = std::allocator_traits<allocator_type>;
205 using value_type = T;
213 allocator_type get_allocator()
const
215 return m_storage.get_deleter().get_allocator();
223 explicit constexpr heap_optional_holder(
const allocator_type& allocator = allocator_type()) noexcept :
224 m_storage(
nullptr, allocator)
232 constexpr heap_optional_holder(NullOptType,
const allocator_type& allocator = allocator_type()) noexcept :
233 m_storage(
nullptr, allocator)
242 heap_optional_holder(
const T& val,
const allocator_type& allocator = allocator_type()) :
252 heap_optional_holder(T&& val,
const allocator_type& allocator = allocator_type()) :
263 template <
typename U = T,
264 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
265 heap_optional_holder(NoInitT, T&& val,
const allocator_type& allocator = allocator_type()) :
275 template <
typename... U>
276 explicit heap_optional_holder(
const allocator_type& allocator, U&&... parameters) :
283 ~heap_optional_holder() =
default;
290 heap_optional_holder(
const heap_optional_holder& other) :
291 m_storage(copy_initialize(
292 other, allocator_traits::select_on_container_copy_construction(other.get_allocator())))
300 template <
typename U = T,
301 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
302 heap_optional_holder(NoInitT,
const heap_optional_holder& other) :
303 m_storage(copy_initialize(
NoInit, other,
304 allocator_traits::select_on_container_copy_construction(other.get_allocator())))
313 heap_optional_holder(
const heap_optional_holder& other,
const allocator_type& allocator) :
314 m_storage(copy_initialize(other, allocator))
322 heap_optional_holder(heap_optional_holder&& other) noexcept =
default;
329 template <
typename U = T,
330 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
331 heap_optional_holder(NoInitT, heap_optional_holder&& other) :
332 m_storage(move_initialize(
NoInit, std::move(other), other.get_allocator()))
341 heap_optional_holder(heap_optional_holder&& other,
const allocator_type& allocator) :
342 m_storage(move_initialize(std::move(other), allocator))
352 heap_optional_holder& operator=(
const heap_optional_holder& other)
359 m_storage = copy_initialize(other,
360 select_allocator(other.get_allocator(),
361 typename allocator_traits::propagate_on_container_copy_assignment()));
373 template <
typename U = T,
374 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
375 heap_optional_holder& assign(NoInitT,
const heap_optional_holder& other)
382 m_storage = copy_initialize(
NoInit, other,
383 select_allocator(other.get_allocator(),
384 typename allocator_traits::propagate_on_container_copy_assignment()));
396 heap_optional_holder& operator=(heap_optional_holder&& other)
403 m_storage = move_initialize(std::move(other),
404 select_allocator(other.get_allocator(),
405 typename allocator_traits::propagate_on_container_move_assignment()));
417 template <
typename U = T,
418 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
419 heap_optional_holder& assign(NoInitT, heap_optional_holder&& other)
426 m_storage = move_initialize(
NoInit, std::move(other),
427 select_allocator(other.get_allocator(),
428 typename allocator_traits::propagate_on_container_move_assignment()));
440 heap_optional_holder& operator=(
const T& val)
454 heap_optional_holder& operator=(T&& val)
464 void reset() noexcept
474 bool hasValue() const noexcept
476 return static_cast<bool>(m_storage);
486 const T& operator*()
const
488 this->checkHasValue();
489 return *m_storage.get();
501 this->checkHasValue();
502 return *m_storage.get();
506 allocator_type select_allocator(allocator_type other_allocator, std::true_type)
508 return other_allocator;
511 allocator_type select_allocator(allocator_type, std::false_type)
513 return get_allocator();
516 template <
typename U = T>
520 m_storage = zserio::allocate_unique<T, allocator_type>(get_allocator(), std::forward<U>(val));
523 static storage_type copy_initialize(
const heap_optional_holder& other,
const allocator_type& allocator)
525 if (other.hasValue())
527 return zserio::allocate_unique<T, allocator_type>(allocator, *other);
531 return storage_type(
nullptr, allocator);
535 static storage_type copy_initialize(
536 NoInitT,
const heap_optional_holder& other,
const allocator_type& allocator)
538 if (other.hasValue())
540 return zserio::allocate_unique<T, allocator_type>(allocator,
NoInit, *other);
544 return storage_type(
nullptr, allocator);
548 static storage_type move_initialize(heap_optional_holder&& other,
const allocator_type& allocator)
550 if (other.hasValue())
552 if (allocator == other.get_allocator())
554 return std::move(other.m_storage);
557 return zserio::allocate_unique<T, allocator_type>(allocator, std::move(*other));
561 return storage_type(
nullptr, allocator);
565 static storage_type move_initialize(NoInitT, heap_optional_holder&& other,
const allocator_type& allocator)
567 if (other.hasValue())
569 if (allocator == other.get_allocator())
571 return std::move(other.m_storage);
574 return zserio::allocate_unique<T, allocator_type>(allocator,
NoInit, std::move(*other));
578 return storage_type(
nullptr, allocator);
582 storage_type m_storage;
588 template <
typename T>
589 class in_place_storage
595 in_place_storage() =
default;
600 ~in_place_storage() =
default;
604 in_place_storage(
const in_place_storage&) =
delete;
605 in_place_storage& operator=(
const in_place_storage&) =
delete;
609 in_place_storage(in_place_storage&& other) =
delete;
618 in_place_storage& operator=(in_place_storage&& other)
620 new (&m_inPlace) T(std::move(*other.getObject()));
621 other.getObject()->~T();
633 in_place_storage& assign(NoInitT, in_place_storage&& other)
635 new (&m_inPlace) T(
NoInit, std::move(*other.getObject()));
636 other.getObject()->~T();
658 return reinterpret_cast<T*
>(&m_inPlace);
666 const T* getObject()
const
668 return reinterpret_cast<const T*
>(&m_inPlace);
676 static constexpr
size_t SIZEOF_T =
sizeof(T);
677 static constexpr
size_t ALIGNOF_T =
alignof(T);
678 using AlignedStorage =
typename std::aligned_storage<SIZEOF_T, ALIGNOF_T>::type;
679 AlignedStorage m_inPlace;
685 template <
typename T>
686 class inplace_optional_holder :
public optional_holder_base<T, inplace_optional_holder<T>>
689 using value_type = T;
694 constexpr inplace_optional_holder() noexcept = default;
699 constexpr inplace_optional_holder(NullOptType) noexcept
707 inplace_optional_holder(
const T& val)
709 new (m_storage.getStorage()) T(val);
718 inplace_optional_holder(T&& val)
720 new (m_storage.getStorage()) T(std::move(val));
730 template <
typename U = T,
731 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
732 inplace_optional_holder(NoInitT, T&& val)
734 new (m_storage.getStorage()) T(
NoInit, std::move(val));
743 inplace_optional_holder(
const inplace_optional_holder& other)
745 if (other.hasValue())
747 new (m_storage.getStorage()) T(*other.m_storage.getObject());
757 template <
typename U = T,
758 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
759 inplace_optional_holder(NoInitT,
const inplace_optional_holder& other)
761 if (other.hasValue())
763 new (m_storage.getStorage()) T(
NoInit, *other.m_storage.getObject());
773 inplace_optional_holder(inplace_optional_holder&& other) noexcept(
774 std::is_nothrow_move_constructible<in_place_storage<T>>::value)
776 if (other.hasValue())
778 m_storage = std::move(other.m_storage);
779 other.m_hasValue =
false;
789 template <
typename U = T,
790 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
791 inplace_optional_holder(NoInitT, inplace_optional_holder&& other) noexcept(
792 std::is_nothrow_move_constructible<in_place_storage<T>>::value)
794 if (other.hasValue())
796 m_storage.assign(
NoInit, std::move(other.m_storage));
797 other.m_hasValue =
false;
807 template <
typename... U>
808 explicit inplace_optional_holder(InPlaceT, U&&... parameters)
810 new (m_storage.getStorage()) T(std::forward<U>(parameters)...);
817 ~inplace_optional_holder()
829 inplace_optional_holder& operator=(
const inplace_optional_holder& other)
834 if (other.hasValue())
836 new (m_storage.getStorage()) T(*other.m_storage.getObject());
851 template <
typename U = T,
852 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
853 inplace_optional_holder& assign(NoInitT,
const inplace_optional_holder& other)
858 if (other.hasValue())
860 new (m_storage.getStorage()) T(
NoInit, *other.m_storage.getObject());
875 inplace_optional_holder& operator=(inplace_optional_holder&& other)
880 if (other.hasValue())
882 m_storage = std::move(other.m_storage);
883 other.m_hasValue =
false;
898 template <
typename U = T,
899 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
900 inplace_optional_holder& assign(NoInitT, inplace_optional_holder&& other)
905 if (other.hasValue())
907 m_storage.assign(
NoInit, std::move(other.m_storage));
908 other.m_hasValue =
false;
923 inplace_optional_holder& operator=(
const T& val)
937 inplace_optional_holder& operator=(T&& val)
947 void reset() noexcept
951 m_storage.getObject()->~T();
961 bool hasValue() const noexcept
973 const T& operator*()
const
975 this->checkHasValue();
976 return *m_storage.getObject();
988 this->checkHasValue();
989 return *m_storage.getObject();
993 template <
typename U = T>
997 new (m_storage.getStorage()) T(std::forward<U>(val));
1001 in_place_storage<T> m_storage;
1002 bool m_hasValue =
false;
1012 template <
typename T>
1018 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)