1 #ifndef ZSERIO_OPTIONAL_HOLDER_H_INC 2 #define ZSERIO_OPTIONAL_HOLDER_H_INC 38 constexpr
explicit InPlaceT() =
default;
52 template <
typename T,
typename Derived>
53 class optional_holder_base
63 bool operator==(
const optional_holder_base& other)
const 68 if (getDerived()->hasValue() != other.getDerived()->hasValue())
71 if (getDerived()->hasValue())
72 return get() == other.get();
84 bool operator<(
const optional_holder_base& other)
const 86 if (getDerived()->hasValue() && other.getDerived()->hasValue())
87 return get() < other.get();
89 return !getDerived()->hasValue() && other.getDerived()->hasValue();
97 explicit operator bool()
const noexcept
99 return getDerived()->hasValue();
109 const T* operator->()
const 111 return std::addressof(
get());
123 return std::addressof(
get());
133 const T& value()
const 151 void checkHasValue()
const 153 if (!getDerived()->hasValue())
154 throwNonPresentException();
160 return getDerived()->operator*();
165 return getDerived()->operator*();
168 Derived* getDerived()
170 return static_cast<Derived*
>(
this);
173 const Derived* getDerived()
const 175 return static_cast<const Derived*
>(
this);
179 void throwNonPresentException()
const 188 template <
typename T,
typename ALLOC>
189 class heap_optional_holder :
public optional_holder_base<T, heap_optional_holder<T, ALLOC>>
192 using allocator_type = ALLOC;
193 using allocator_traits = std::allocator_traits<allocator_type>;
194 using value_type = T;
202 allocator_type get_allocator()
const 204 return m_storage.get_deleter().get_allocator();
212 explicit constexpr heap_optional_holder(
const allocator_type& allocator = allocator_type()) noexcept :
213 m_storage(
nullptr, allocator)
222 const allocator_type& allocator = allocator_type()) noexcept : m_storage(
nullptr, allocator)
231 heap_optional_holder(
const T& value,
const allocator_type& allocator = allocator_type()) :
232 m_storage(zserio::allocate_unique<T, allocator_type>(allocator, value))
241 heap_optional_holder(T&& value,
const allocator_type& allocator = allocator_type()) :
242 m_storage(zserio::allocate_unique<T, allocator_type>(allocator, std::move(value)))
252 template <
typename U = T,
253 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
254 heap_optional_holder(
NoInitT, T&& value,
const allocator_type& allocator = allocator_type()) :
255 m_storage(zserio::allocate_unique<T, allocator_type>(allocator,
NoInit, std::move(value)))
264 template <
typename ...U>
265 explicit heap_optional_holder(
const allocator_type& allocator, U&& ...u) :
266 m_storage(zserio::allocate_unique<T, allocator_type>(allocator, std::forward<U>(u)...))
272 ~heap_optional_holder() =
default;
279 heap_optional_holder(
const heap_optional_holder& other) :
280 m_storage(copy_initialize(other, allocator_traits::select_on_container_copy_construction(
281 other.get_allocator())))
289 template <
typename U = T,
290 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
291 heap_optional_holder(
NoInitT,
const heap_optional_holder& other) :
292 m_storage(copy_initialize(
NoInit, other,
293 allocator_traits::select_on_container_copy_construction(
294 other.get_allocator())))
303 heap_optional_holder(
const heap_optional_holder& other,
const allocator_type& allocator) :
304 m_storage(copy_initialize(other, allocator))
312 heap_optional_holder(heap_optional_holder&& other) noexcept =
default;
319 template <
typename U = T,
320 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
321 heap_optional_holder(
NoInitT, heap_optional_holder&& other) :
322 m_storage(move_initialize(
NoInit, std::move(other), other.get_allocator()))
332 heap_optional_holder(heap_optional_holder&& other,
const allocator_type& allocator) :
333 m_storage(move_initialize(std::move(other), allocator))
344 heap_optional_holder& operator=(
const heap_optional_holder& other)
349 m_storage = copy_initialize(other, select_allocator(other.get_allocator(),
350 typename allocator_traits::propagate_on_container_copy_assignment()));
362 template <
typename U = T,
363 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
364 heap_optional_holder& assign(
NoInitT,
const heap_optional_holder& other)
369 m_storage = copy_initialize(
NoInit, other, select_allocator(other.get_allocator(),
370 typename allocator_traits::propagate_on_container_copy_assignment()));
382 heap_optional_holder& operator=(heap_optional_holder&& other)
387 m_storage = move_initialize(std::move(other), select_allocator(other.get_allocator(),
388 typename allocator_traits::propagate_on_container_move_assignment()));
400 template <
typename U = T,
401 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
402 heap_optional_holder& assign(
NoInitT, heap_optional_holder&& other)
407 m_storage = move_initialize(
NoInit, std::move(other),
408 select_allocator(other.get_allocator(),
409 typename allocator_traits::propagate_on_container_move_assignment()));
421 heap_optional_holder& operator=(
const T& value)
435 heap_optional_holder& operator=(T&& value)
437 set(std::move(value));
445 void reset() noexcept
455 bool hasValue()
const noexcept
457 return static_cast<bool>(m_storage);
467 const T& operator*()
const 469 this->checkHasValue();
470 return *m_storage.get();
482 this->checkHasValue();
483 return *m_storage.get();
487 allocator_type select_allocator(allocator_type other_allocator, std::true_type)
489 return other_allocator;
492 allocator_type select_allocator(allocator_type, std::false_type)
494 return get_allocator();
497 template <
typename U = T>
501 m_storage = zserio::allocate_unique<T, allocator_type>(get_allocator(), std::forward<U>(value));
504 static storage_type copy_initialize(
const heap_optional_holder& other,
const allocator_type& allocator)
506 if (other.hasValue())
507 return zserio::allocate_unique<T, allocator_type>(allocator, *other);
509 return storage_type(
nullptr, allocator);
512 static storage_type copy_initialize(
NoInitT,
const heap_optional_holder& other,
513 const allocator_type& allocator)
515 if (other.hasValue())
516 return zserio::allocate_unique<T, allocator_type>(allocator,
NoInit, *other);
518 return storage_type(
nullptr, allocator);
521 static storage_type move_initialize(heap_optional_holder&& other,
const allocator_type& allocator)
523 if (other.hasValue())
525 if (allocator == other.get_allocator())
526 return std::move(other.m_storage);
528 return zserio::allocate_unique<T, allocator_type>(allocator, std::move(*other));
532 return storage_type(
nullptr, allocator);
536 static storage_type move_initialize(
NoInitT, heap_optional_holder&& other,
537 const allocator_type& allocator)
539 if (other.hasValue())
541 if (allocator == other.get_allocator())
542 return std::move(other.m_storage);
544 return zserio::allocate_unique<T, allocator_type>(allocator,
NoInit,
549 return storage_type(
nullptr, allocator);
553 storage_type m_storage;
559 template <
typename T>
560 class in_place_storage
566 in_place_storage() =
default;
571 ~in_place_storage() =
default;
575 in_place_storage(
const in_place_storage&) =
delete;
576 in_place_storage& operator=(
const in_place_storage&) =
delete;
580 in_place_storage(in_place_storage&& other) =
delete;
589 in_place_storage& operator=(in_place_storage&& other)
591 new (&m_inPlace) T(std::move(*other.getObject()));
592 other.getObject()->~T();
604 in_place_storage& assign(
NoInitT, in_place_storage&& other)
606 new (&m_inPlace) T(
NoInit, std::move(*other.getObject()));
607 other.getObject()->~T();
629 return reinterpret_cast<T*
>(&m_inPlace);
637 const T* getObject()
const 639 return reinterpret_cast<const T*
>(&m_inPlace);
647 static constexpr
size_t SIZEOF_T =
sizeof(T);
648 static constexpr
size_t ALIGNOF_T =
alignof(T);
649 using AlignedStorage =
typename std::aligned_storage<SIZEOF_T, ALIGNOF_T>::type;
650 AlignedStorage m_inPlace;
656 template <
typename T>
657 class inplace_optional_holder :
public optional_holder_base<T, inplace_optional_holder<T>>
660 using value_type = T;
665 constexpr inplace_optional_holder() noexcept =
default;
670 constexpr inplace_optional_holder(
NullOptType) noexcept
678 inplace_optional_holder(
const T& value)
680 new (m_storage.getStorage()) T(value);
689 inplace_optional_holder(T&& value)
691 new (m_storage.getStorage()) T(std::move(value));
701 template <
typename U = T,
702 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
703 inplace_optional_holder(
NoInitT, T&& value)
705 new (m_storage.getStorage()) T(
NoInit, std::move(value));
714 inplace_optional_holder(
const inplace_optional_holder& other)
716 if (other.hasValue())
718 new (m_storage.getStorage()) T(*other.m_storage.getObject());
728 template <
typename U = T,
729 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
730 inplace_optional_holder(
NoInitT,
const inplace_optional_holder& other)
732 if (other.hasValue())
734 new (m_storage.getStorage()) T(
NoInit, *other.m_storage.getObject());
744 inplace_optional_holder(inplace_optional_holder&& other)
745 noexcept(std::is_nothrow_move_constructible<in_place_storage<T>>::value)
747 if (other.hasValue())
749 m_storage = std::move(other.m_storage);
750 other.m_hasValue =
false;
760 template <
typename U = T,
761 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
762 inplace_optional_holder(
NoInitT, inplace_optional_holder&& other)
763 noexcept(std::is_nothrow_move_constructible<in_place_storage<T>>::value)
765 if (other.hasValue())
767 m_storage.assign(
NoInit, std::move(other.m_storage));
768 other.m_hasValue =
false;
778 template <
typename ...U>
779 explicit inplace_optional_holder(
InPlaceT, U&& ...u)
781 new (m_storage.getStorage()) T(std::forward<U>(u)...);
788 ~inplace_optional_holder()
800 inplace_optional_holder& operator=(
const inplace_optional_holder& other)
805 if (other.hasValue())
807 new (m_storage.getStorage()) T(*other.m_storage.getObject());
822 template <
typename U = T,
823 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
824 inplace_optional_holder& assign(
NoInitT,
const inplace_optional_holder& other)
829 if (other.hasValue())
831 new (m_storage.getStorage()) T(
NoInit, *other.m_storage.getObject());
846 inplace_optional_holder& operator=(inplace_optional_holder&& other)
851 if (other.hasValue())
853 m_storage = std::move(other.m_storage);
854 other.m_hasValue =
false;
869 template <
typename U = T,
870 typename std::enable_if<std::is_constructible<U, NoInitT, U>::value,
int>::type = 0>
871 inplace_optional_holder& assign(
NoInitT, inplace_optional_holder&& other)
876 if (other.hasValue())
878 m_storage.assign(
NoInit, std::move(other.m_storage));
879 other.m_hasValue =
false;
894 inplace_optional_holder& operator=(
const T& value)
908 inplace_optional_holder& operator=(T&& value)
910 set(std::move(value));
918 void reset() noexcept
922 m_storage.getObject()->~T();
932 bool hasValue()
const noexcept
944 const T& operator*()
const 946 this->checkHasValue();
947 return *m_storage.getObject();
959 this->checkHasValue();
960 return *m_storage.getObject();
964 template <
typename U = T>
968 new (m_storage.getStorage()) T(std::forward<U>(value));
972 in_place_storage<T> m_storage;
973 bool m_hasValue =
false;
983 template <
typename T>
989 template <
typename T,
typename ALLOC = std::allocator<T>>
994 #endif // ifndef ZSERIO_OPTIONAL_HOLDER_H_INC
std::unique_ptr< T, detail::UniquePtrDeleter< ALLOC >> unique_ptr
detail::heap_optional_holder< T, ALLOC > HeapOptionalHolder
constexpr bool operator<(BasicStringView< CharT, Traits > lhs, BasicStringView< CharT, Traits > rhs) noexcept
constexpr bool operator==(BasicStringView< CharT, Traits > lhs, BasicStringView< CharT, Traits > rhs) noexcept
detail::inplace_optional_holder< T > InplaceOptionalHolder
constexpr NullOptType(int)
constexpr NullOptType NullOpt
constexpr InPlaceT InPlace