Skip to content

Instantly share code, notes, and snippets.

@EricWF
Created August 14, 2016 23:54
Show Gist options
  • Select an option

  • Save EricWF/c5cc1e2e25c858b3488b955a9b36a2bb to your computer and use it in GitHub Desktop.

Select an option

Save EricWF/c5cc1e2e25c858b3488b955a9b36a2bb to your computer and use it in GitHub Desktop.
diff --git a/include/optional b/include/optional
index 298f91a..9675ee7 100644
--- a/include/optional
+++ b/include/optional
@@ -241,7 +241,7 @@ struct __optional_destruct_base<_Tp, true>
__engaged_(true) {}
};
-template <class _Tp>
+template <class _Tp, bool = is_trivially_copyable<_Tp>::value>
struct __optional_construct_base : __optional_destruct_base<_Tp>
{
using __base = __optional_destruct_base<_Tp>;
@@ -249,66 +249,16 @@ struct __optional_construct_base : __optional_destruct_base<_Tp>
using __base::__base;
- template <class... _Args>
- _LIBCPP_INLINE_VISIBILITY
- void __construct(_Args&&... __args)
- {
- _LIBCPP_ASSERT(!has_value(), "__construct called for engaged __optional_storage");
- ::new(_VSTD::addressof(this->__val_)) value_type(_VSTD::forward<_Args>(__args)...);
- this->__engaged_ = true;
- }
+ constexpr __optional_construct_base() noexcept : __base() {}
_LIBCPP_INLINE_VISIBILITY
- void reset() noexcept
+ __optional_construct_base(const __optional_construct_base& __opt)
{
- if (this->__engaged_)
- {
- this->__val_.~value_type();
- this->__engaged_ = false;
- }
+ if (__opt.__engaged_)
+ this->__construct(__opt.__val_);
}
-};
-
-template <class _Tp, bool = is_move_constructible<_Tp>::value,
- bool = is_trivially_copyable<__optional_destruct_base<_Tp>>::value>
-struct __optional_move_base;
-
-template <class _Tp, bool _IsTC>
-struct __optional_move_base<_Tp, false, _IsTC> : __optional_construct_base<_Tp>
-{
- using __base = __optional_construct_base<_Tp>;
- using __base::__base;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_base() = default;
_LIBCPP_INLINE_VISIBILITY
- __optional_move_base(__optional_move_base&&) = delete;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_base(const __optional_move_base&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_base& operator=(__optional_move_base&&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_base& operator=(const __optional_move_base&) = default;
-};
-
-template <class _Tp>
-struct __optional_move_base<_Tp, true, true> : __optional_construct_base<_Tp>
-{
- using __base = __optional_construct_base<_Tp>;
- using __base::__base;
-};
-
-template <class _Tp>
-struct __optional_move_base<_Tp, true, false> : __optional_construct_base<_Tp>
-{
- using __base = __optional_construct_base<_Tp>;
- using typename __base::value_type;
- using __base::__base;
-
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_base() = default;
-
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_base(__optional_move_base&& __opt)
+ __optional_construct_base(__optional_construct_base&& __opt)
noexcept(is_nothrow_move_constructible<value_type>::value)
{
if (__opt.__engaged_)
@@ -316,108 +266,25 @@ struct __optional_move_base<_Tp, true, false> : __optional_construct_base<_Tp>
}
_LIBCPP_INLINE_VISIBILITY
- __optional_move_base(const __optional_move_base&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_base& operator=(__optional_move_base&&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_base& operator=(const __optional_move_base&) = default;
-};
-
-template <class _Tp, bool = is_copy_constructible<_Tp>::value,
- bool = is_trivially_copyable<__optional_destruct_base<_Tp>>::value>
-struct __optional_copy_base;
-
-template <class _Tp, bool _IsTC>
-struct __optional_copy_base<_Tp, false, _IsTC> : __optional_move_base<_Tp>
-{
- using __base = __optional_move_base<_Tp>;
- using __base::__base;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_base() = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_base(__optional_copy_base&&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_base(const __optional_copy_base&) = delete;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_base& operator=(__optional_copy_base&&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_base& operator=(const __optional_copy_base&) = default;
-};
-
-template <class _Tp>
-struct __optional_copy_base<_Tp, true, true> : __optional_move_base<_Tp>
-{
- using __base = __optional_move_base<_Tp>;
- using __base::__base;
-};
-
-template <class _Tp>
-struct __optional_copy_base<_Tp, true, false> : __optional_move_base<_Tp>
-{
- using __base = __optional_move_base<_Tp>;
- using typename __base::value_type;
- using __base::__base;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_base() = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_base(__optional_copy_base&&) = default;
-
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_base(const __optional_copy_base& __opt)
+ __optional_construct_base& operator=(const __optional_construct_base& __opt)
{
- if (__opt.__engaged_)
- this->__construct(__opt.__val_);
+ if (this->__engaged_ == __opt.__engaged_)
+ {
+ if (this->__engaged_)
+ this->__val_ = __opt.__val_;
+ }
+ else
+ {
+ if (this->__engaged_)
+ this->reset();
+ else
+ this->__construct(__opt.__val_);
+ }
+ return *this;
}
_LIBCPP_INLINE_VISIBILITY
- __optional_copy_base& operator=(__optional_copy_base&&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_base& operator=(const __optional_copy_base&) = default;
-};
-
-template <class _Tp, bool = is_move_assignable<_Tp>::value,
- bool = is_trivially_copyable<__optional_destruct_base<_Tp>>::value>
-struct __optional_move_assign_base;
-
-template <class _Tp, bool _IsTC>
-struct __optional_move_assign_base<_Tp, false, _IsTC> : __optional_copy_base<_Tp>
-{
- using __base = __optional_copy_base<_Tp>;
- using __base::__base;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_assign_base() = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_assign_base(__optional_move_assign_base&&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_assign_base(const __optional_move_assign_base&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_assign_base& operator=(__optional_move_assign_base&&) = delete;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_assign_base& operator=(const __optional_move_assign_base&) = default;
-};
-
-template <class _Tp>
-struct __optional_move_assign_base<_Tp, true, true> : __optional_copy_base<_Tp>
-{
- using __base = __optional_copy_base<_Tp>;
- using __base::__base;
-};
-
-template <class _Tp>
-struct __optional_move_assign_base<_Tp, true, false> : __optional_copy_base<_Tp>
-{
- using __base = __optional_copy_base<_Tp>;
- using typename __base::value_type;
- using __base::__base;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_assign_base() = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_assign_base(__optional_move_assign_base&&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_assign_base(const __optional_move_assign_base&) = default;
-
- _LIBCPP_INLINE_VISIBILITY
- __optional_move_assign_base& operator=(__optional_move_assign_base&& __opt)
+ __optional_construct_base& operator=(__optional_construct_base&& __opt)
noexcept(is_nothrow_move_assignable<value_type>::value &&
is_nothrow_move_constructible<value_type>::value)
{
@@ -436,77 +303,59 @@ struct __optional_move_assign_base<_Tp, true, false> : __optional_copy_base<_Tp>
return *this;
}
+ template <class... _Args>
_LIBCPP_INLINE_VISIBILITY
- __optional_move_assign_base& operator=(const __optional_move_assign_base&) = default;
-};
-
-template <class _Tp, bool = is_copy_assignable<_Tp>::value,
- bool = is_trivially_copyable<__optional_destruct_base<_Tp>>::value>
-struct __optional_copy_assign_base;
+ void __construct(_Args&&... __args)
+ {
+ _LIBCPP_ASSERT(!has_value(), "__construct called for engaged __optional_storage");
+ ::new((void*)_VSTD::addressof(this->__val_)) value_type(_VSTD::forward<_Args>(__args)...);
+ this->__engaged_ = true;
+ }
-template <class _Tp, bool _IsTC>
-struct __optional_copy_assign_base<_Tp, false, _IsTC> : __optional_move_assign_base<_Tp>
-{
- using __base = __optional_move_assign_base<_Tp>;
- using __base::__base;
_LIBCPP_INLINE_VISIBILITY
- __optional_copy_assign_base() = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_assign_base(__optional_copy_assign_base&&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_assign_base(const __optional_copy_assign_base&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_assign_base& operator=(__optional_copy_assign_base&&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_assign_base& operator=(const __optional_copy_assign_base&) = delete;
-};
-
-template <class _Tp>
-struct __optional_copy_assign_base<_Tp, true, true> : __optional_move_assign_base<_Tp>
-{
- using __base = __optional_move_assign_base<_Tp>;
- using __base::__base;
+ void reset() noexcept
+ {
+ if (this->__engaged_)
+ {
+ this->__val_.~value_type();
+ this->__engaged_ = false;
+ }
+ }
};
template <class _Tp>
-struct __optional_copy_assign_base<_Tp, true, false> : __optional_move_assign_base<_Tp>
+struct __optional_construct_base<_Tp, true> : __optional_destruct_base<_Tp>
{
- using __base = __optional_move_assign_base<_Tp>;
+ using __base = __optional_destruct_base<_Tp>;
using typename __base::value_type;
+
using __base::__base;
+
+ template <class... _Args>
_LIBCPP_INLINE_VISIBILITY
- __optional_copy_assign_base() = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_assign_base(__optional_copy_assign_base&&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_assign_base(const __optional_copy_assign_base&) = default;
- _LIBCPP_INLINE_VISIBILITY
- __optional_copy_assign_base& operator=(__optional_copy_assign_base&&) = default;
+ void __construct(_Args&&... __args)
+ {
+ _LIBCPP_ASSERT(!has_value(), "__construct called for engaged __optional_storage");
+ ::new((void*)_VSTD::addressof(this->__val_)) value_type(_VSTD::forward<_Args>(__args)...);
+ this->__engaged_ = true;
+ }
_LIBCPP_INLINE_VISIBILITY
- __optional_copy_assign_base& operator=(const __optional_copy_assign_base& __opt)
+ void reset() noexcept
{
- if (this->__engaged_ == __opt.__engaged_)
- {
- if (this->__engaged_)
- this->__val_ = __opt.__val_;
- }
- else
+ if (this->__engaged_)
{
- if (this->__engaged_)
- this->reset();
- else
- this->__construct(__opt.__val_);
+ this->__val_.~value_type();
+ this->__engaged_ = false;
}
- return *this;
}
};
template <class _Tp, class = void>
-class __optional_storage : __optional_copy_assign_base<_Tp>
+class __optional_storage : __optional_construct_base<_Tp>
{
public:
- using __base = __optional_copy_assign_base<_Tp>;
+ using __base = __optional_construct_base<_Tp>;
using typename __base::value_type;
using __base::__base;
@@ -557,9 +406,75 @@ constexpr bool _Is_specialization = false;
template <class... _Args, template <class...> class _Template>
constexpr bool _Is_specialization<_Template<_Args...>, _Template> = true;
+
+template <bool _CanCopy, bool _CanMove>
+struct __optional_sfinae_ctor_base {};
+template <>
+struct __optional_sfinae_ctor_base<false, false> {
+ __optional_sfinae_ctor_base() = default;
+ __optional_sfinae_ctor_base(__optional_sfinae_ctor_base const&) = delete;
+ __optional_sfinae_ctor_base(__optional_sfinae_ctor_base &&) = delete;
+ __optional_sfinae_ctor_base& operator=(__optional_sfinae_ctor_base const&) = default;
+ __optional_sfinae_ctor_base& operator=(__optional_sfinae_ctor_base&&) = default;
+};
+template <>
+struct __optional_sfinae_ctor_base<true, false> {
+ __optional_sfinae_ctor_base() = default;
+ __optional_sfinae_ctor_base(__optional_sfinae_ctor_base const&) = default;
+ __optional_sfinae_ctor_base(__optional_sfinae_ctor_base &&) = delete;
+ __optional_sfinae_ctor_base& operator=(__optional_sfinae_ctor_base const&) = default;
+ __optional_sfinae_ctor_base& operator=(__optional_sfinae_ctor_base&&) = default;
+};
+template <>
+struct __optional_sfinae_ctor_base<false, true> {
+ __optional_sfinae_ctor_base() = default;
+ __optional_sfinae_ctor_base(__optional_sfinae_ctor_base const&) = delete;
+ __optional_sfinae_ctor_base(__optional_sfinae_ctor_base &&) = default;
+ __optional_sfinae_ctor_base& operator=(__optional_sfinae_ctor_base const&) = default;
+ __optional_sfinae_ctor_base& operator=(__optional_sfinae_ctor_base&&) = default;
+};
+template <class _Tp>
+using __optional_sfinae_ctor_base_t = __optional_sfinae_ctor_base<
+ is_copy_constructible<_Tp>::value,
+ is_move_constructible<_Tp>::value
+>;
+template <bool _CanCopy, bool _CanMove>
+struct __optional_sfinae_assign_base {};
+template <>
+struct __optional_sfinae_assign_base<false, false> {
+ __optional_sfinae_assign_base() = default;
+ __optional_sfinae_assign_base(__optional_sfinae_assign_base const&) = default;
+ __optional_sfinae_assign_base(__optional_sfinae_assign_base &&) = default;
+ __optional_sfinae_assign_base& operator=(__optional_sfinae_assign_base const&) = delete;
+ __optional_sfinae_assign_base& operator=(__optional_sfinae_assign_base&&) = delete;
+};
+template <>
+struct __optional_sfinae_assign_base<true, false> {
+ __optional_sfinae_assign_base() = default;
+ __optional_sfinae_assign_base(__optional_sfinae_assign_base const&) = default;
+ __optional_sfinae_assign_base(__optional_sfinae_assign_base &&) = default;
+ __optional_sfinae_assign_base& operator=(__optional_sfinae_assign_base const&) = default;
+ __optional_sfinae_assign_base& operator=(__optional_sfinae_assign_base&&) = delete;
+};
+template <>
+struct __optional_sfinae_assign_base<false, true> {
+ __optional_sfinae_assign_base() = default;
+ __optional_sfinae_assign_base(__optional_sfinae_assign_base const&) = default;
+ __optional_sfinae_assign_base(__optional_sfinae_assign_base &&) = default;
+ __optional_sfinae_assign_base& operator=(__optional_sfinae_assign_base const&) = delete;
+ __optional_sfinae_assign_base& operator=(__optional_sfinae_assign_base&&) = default;
+};
+template <class _Tp>
+using __optional_sfinae_assign_base_t = __optional_sfinae_assign_base<
+ is_copy_assignable<_Tp>::value,
+ is_move_assignable<_Tp>::value
+>;
+
template <class _Tp>
class optional
- : private __optional_storage<_Tp>
+ : private __optional_storage<_Tp>,
+ private __optional_sfinae_ctor_base_t<_Tp>,
+ private __optional_sfinae_assign_base_t<_Tp>
{
template <class> friend class optional;
using __base = __optional_storage<_Tp>;
@@ -570,7 +485,7 @@ public:
"Instantiation of optional with a reference type is ill-formed.");
static_assert(!is_same<remove_cv_t<value_type>, nullopt_t>::value,
"Instantiation of optional with a nullopt_t type is ill-formed.");
- static_assert(is_reference<value_type>::value || is_object<value_type>::value,
+ static_assert(is_object<value_type>::value,
"Instantiation of optional with a non-object type is undefined behavior.");
_LIBCPP_INLINE_VISIBILITY constexpr optional() noexcept {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment