From b04e60d7c128714d5daf6ab809a2018ec0e1bb41 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Thu, 18 Apr 2019 13:50:11 +0300 Subject: [PATCH 01/14] Experiment for replacing bdlb::NullableValue with std::pmr::optional --- groups/bdl/bdlb/bdlb_nullablevalue.h | 121 +- groups/bdl/bdlb/bdlb_nullablevalue.t.cpp | 38 +- groups/bdl/bdlb/memory_resource | 721 +++++++ groups/bdl/bdlb/pmroptional | 2282 ++++++++++++++++++++++ groups/bdl/bdldfp/bdldfp_decimal.t.cpp | 1 + groups/bsl/bslma/bslma_allocator.h | 16 +- groups/bsl/bslma/bslma_default.cpp | 4 +- groups/bsl/bslma/bslma_stdallocator.h | 19 + groups/bsl/bsls/bsls_exceptionutil.h | 2 +- groups/bsl/bslstl/bslstl_vector.h | 20 + 10 files changed, 3216 insertions(+), 8 deletions(-) create mode 100644 groups/bdl/bdlb/memory_resource create mode 100644 groups/bdl/bdlb/pmroptional diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.h b/groups/bdl/bdlb/bdlb_nullablevalue.h index defd9be69a..f196d7cdfe 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.h +++ b/groups/bdl/bdlb/bdlb_nullablevalue.h @@ -74,6 +74,8 @@ BSLS_IDENT("$Id: $") // assert( nullableInt.isNull()); //.. +#include + #ifndef INCLUDED_BDLSCM_VERSION #include #endif @@ -178,8 +180,122 @@ BSLS_IDENT("$Id: $") #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES +namespace BloombergLP { +namespace bslma { + template struct UsesBslmaAllocator> : bsl::true_type {}; +} +} + +namespace std { +namespace pmr { + template + int optional<_Tp>::maxSupportedBdexVersion(int versionSelector) const + { + using BloombergLP::bslx::VersionFunctions::maxSupportedBdexVersion; + + // We need to call the 'bslx::VersionFunctions' helper function, because we + // cannot guarantee that 'TYPE' implements 'maxSupportedBdexVersion' as a + // class method. + + return maxSupportedBdexVersion(reinterpret_cast<_Tp *>(0), + versionSelector); + } + + template + template + STREAM& optional::bdexStreamIn(STREAM& stream, int version) + { + using BloombergLP::bslx::InStreamFunctions::bdexStreamIn; + + char isNull = 0; // Redundant initialization to suppress -Werror. + + stream.getInt8(isNull); + + if (stream) { + if (!isNull) { + this->makeValue(); + + bdexStreamIn(stream, this->value(), version); + } + else { + this->reset(); + } + } + + return stream; + } + + template + template + STREAM& optional::bdexStreamOut(STREAM& stream, int version) const + { + using BloombergLP::bslx::OutStreamFunctions::bdexStreamOut; + + const bool isNull = this->isNull(); + + stream.putInt8(isNull ? 1 : 0); + + if (!isNull) { + bdexStreamOut(stream, this->value(), version); + } + + return stream; + } + + template + bsl::ostream& operator<<(bsl::ostream& stream, + const optional& object) + { + if (object.isNull()) { + return BloombergLP::bdlb::PrintMethods::print(stream, + "NULL", + 0, + -1); // RETURN + } + + return BloombergLP::bdlb::PrintMethods::print(stream, + object.value(), + 0, + -1); + } + + template + template + auto& optional::print(STREAM& stream, int level, + int spacesPerLevel) const + { + if (this->isNull()) { + return (bsl::ostream&)BloombergLP::bdlb::PrintMethods::print(stream, + "NULL", + 0, + -1); // RETURN + } + + return (bsl::ostream&)BloombergLP::bdlb::PrintMethods::print(stream, + this->value(), + 0, + -1); + } + + template + void hashAppend(HASHALG& hashAlg, const optional& input) + { + using namespace BloombergLP; + if (!input.isNull()) { + hashAppend(hashAlg, true); + hashAppend(hashAlg, input.value()); + } + else { + hashAppend(hashAlg, false); + } + } +} +} + namespace BloombergLP { namespace bdlb { +template +using NullableValue = std::pmr::optional; template class NullableValue_WithAllocator; @@ -187,6 +303,8 @@ class NullableValue_WithAllocator; template class NullableValue_WithoutAllocator; + +#if 0 // ========================= // class NullableValue // ========================= @@ -2393,10 +2511,11 @@ const TYPE& NullableValue_WithoutAllocator::value() const return d_buffer.object(); } - +#endif } // close package namespace } // close enterprise namespace + #endif // ---------------------------------------------------------------------------- diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp b/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp index cc55cd69d9..03c685902e 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp +++ b/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp @@ -46,6 +46,20 @@ using namespace BloombergLP; using namespace bsl; +namespace std +{ + template + struct uses_allocator : true_type {}; + template + struct uses_allocator>, _Alloc> : true_type {}; + template +struct uses_allocator : true_type {}; + template +struct uses_allocator : true_type {}; + template +struct uses_allocator : true_type {}; +} + // ============================================================================ // TEST PLAN // ---------------------------------------------------------------------------- @@ -1312,6 +1326,15 @@ struct UsesBslmaAllocator : bsl::true_type { } // close namespace bslma } // close enterprise namespace +namespace std +{ + template + struct uses_allocator : true_type {}; +; + template + struct uses_allocator, _Alloc> : true_type {}; +} + // ====================================== // class ConvertibleFromAllocatorTestType @@ -1498,6 +1521,13 @@ struct UsesBslmaAllocator : bsl::true_type { } // close namespace bslma } // close enterprise namespace +namespace std +{ + template + struct uses_allocator : true_type {}; +; +} + // ============================================================================ // GLOBAL TYPEDEFS/CONSTANTS FOR TESTING // ---------------------------------------------------------------------------- @@ -1889,8 +1919,8 @@ void TestDriver::testCase24_withoutAllocator() }; const int NUM_SPECS = sizeof SPECS / sizeof *SPECS; - Obj& (Obj::*operatorMAg) (bslmf::MovableRef) = &Obj::operator=; - (void) operatorMAg; // quash potential compiler warning + //Obj& (Obj::*operatorMAg) (bslmf::MovableRef) = &Obj::operator=; + //(void) operatorMAg; // quash potential compiler warning if (verbose) printf("\nTesting move assignment (no allocator).\n"); { @@ -3365,7 +3395,7 @@ void TestDriver::testCase21_withAllocator() ASSERTV(SPEC, CONFIG, X == W); // Verify subsequent manipulation of new object 'X'. - primaryManipulator(&mX, 'Z'); + primaryManipulator(&mX, 'Z'); ASSERTV(SPEC, X != W); ASSERTV(SPEC, X == Z); @@ -7203,7 +7233,7 @@ int main(int argc, char *argv[]) { Obj mX(&oa); const Obj& X = mX; if (veryVeryVerbose) { T_ T_ P(X) } - ASSERT(X.isNull()); + ASSERT(!mX.has_value()); ASSERT(0 == da.numBlocksTotal()); ASSERT(0 == oa.numBlocksTotal()); } diff --git a/groups/bdl/bdlb/memory_resource b/groups/bdl/bdlb/memory_resource new file mode 100644 index 0000000000..625a10af2c --- /dev/null +++ b/groups/bdl/bdlb/memory_resource @@ -0,0 +1,721 @@ +// -*- C++ -*- + +// Copyright (C) 2018-2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/memory_resource + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_MEMORY_RESOURCE +#define _GLIBCXX_MEMORY_RESOURCE 1 + +#pragma GCC system_header + +#if __cplusplus >= 201703L + +#include // numeric_limits +#include // align, allocator_arg_t, __uses_alloc +#include // pair, index_sequence +#include // vector +#include // size_t, max_align_t, byte +#include // shared_mutex +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION +namespace pmr +{ +#ifdef _GLIBCXX_HAS_GTHREADS + // Header and all contents are present. +# define __cpp_lib_memory_resource 201603 +#else + // The pmr::synchronized_pool_resource type is missing. +# define __cpp_lib_memory_resource 1 +#endif + + class memory_resource; + +#if __cplusplus == 201703L + template + class polymorphic_allocator; +#else // C++20 + template + class polymorphic_allocator; +#endif + + // Global memory resources + memory_resource* new_delete_resource() noexcept; + memory_resource* null_memory_resource() noexcept; + memory_resource* set_default_resource(memory_resource* __r) noexcept; + memory_resource* get_default_resource() noexcept + __attribute__((__returns_nonnull__)); + + // Pool resource classes + struct pool_options; +#ifdef _GLIBCXX_HAS_GTHREADS + class synchronized_pool_resource; +#endif + class unsynchronized_pool_resource; + class monotonic_buffer_resource; + + /// Class memory_resource + class memory_resource + { + static constexpr size_t _S_max_align = alignof(max_align_t); + + public: + memory_resource() = default; + memory_resource(const memory_resource&) = default; + virtual ~memory_resource() = default; + + memory_resource& operator=(const memory_resource&) = default; + + [[nodiscard]] + void* + allocate(size_t __bytes, size_t __alignment = _S_max_align) + __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3))) + { return do_allocate(__bytes, __alignment); } + + void + deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align) + __attribute__((__nonnull__)) + { return do_deallocate(__p, __bytes, __alignment); } + + bool + is_equal(const memory_resource& __other) const noexcept + { return do_is_equal(__other); } + + private: + virtual void* + do_allocate(size_t __bytes, size_t __alignment) = 0; + + virtual void + do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0; + + virtual bool + do_is_equal(const memory_resource& __other) const noexcept = 0; + }; + + inline bool + operator==(const memory_resource& __a, const memory_resource& __b) noexcept + { return &__a == &__b || __a.is_equal(__b); } + + inline bool + operator!=(const memory_resource& __a, const memory_resource& __b) noexcept + { return !(__a == __b); } + + template + struct __is_dynamic_castable + { + static constexpr bool value=false; + }; + template + struct __is_dynamic_castable<_Tp, _Up, + void_t(declval<_Up>()))>> + { + static constexpr bool value=true; + }; + + + // C++17 23.12.3 Class template polymorphic_allocator + template + class polymorphic_allocator + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2975. Missing case for pair construction in polymorphic allocators + template + struct __not_pair { using type = void; }; + + template + struct __not_pair> { }; + + public: + using value_type = _Tp; + + polymorphic_allocator() noexcept + : _M_resource(get_default_resource()) + { } + + polymorphic_allocator(memory_resource* __r) noexcept + __attribute__((__nonnull__)) + : _M_resource(__r) + { _GLIBCXX_DEBUG_ASSERT(__r); } + + polymorphic_allocator(const polymorphic_allocator& __other) = default; + + template + polymorphic_allocator(const polymorphic_allocator<_Up>& __x) noexcept + : _M_resource(__x.resource()) + { } + + polymorphic_allocator& + operator=(const polymorphic_allocator&) = delete; + + [[nodiscard]] + _Tp* + allocate(size_t __n) + __attribute__((__returns_nonnull__)) + { + if (__n > (numeric_limits::max() / sizeof(_Tp))) + std::__throw_bad_alloc(); + return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp), + alignof(_Tp))); + } + + void + deallocate(_Tp* __p, size_t __n) noexcept + __attribute__((__nonnull__)) + { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } + +#if __cplusplus > 201703L + void* + allocate_bytes(size_t __nbytes, + size_t __alignment = alignof(max_align_t)) + { return _M_resource->allocate(__nbytes, __alignment); } + + void + deallocate_bytes(void* __p, size_t __nbytes, + size_t __alignment = alignof(max_align_t)) + { _M_resource->deallocate(__p, __nbytes, __alignment); } + + template + _Up* + allocate_object(size_t __n = 1) + { + if ((std::numeric_limits::max() / sizeof(_Up)) < __n) + __throw_length_error("polymorphic_allocator::allocate_object"); + return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up), + alignof(_Up))); + } + + template + void + deallocate_object(_Up* __p, size_t __n = 1) + { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); } + + template + _Up* + new_object(_CtorArgs&&... __ctor_args) + { + _Up* __p = allocate_object<_Up>(); + __try + { + construct(__p, std::forward<_CtorArgs>(__ctor_args)...); + } + __catch (...) + { + deallocate_object(__p); + __throw_exception_again; + } + return __p; + } + + template + void + delete_object(_Up* __p) + { + destroy(__p); + deallocate_object(__p); + } +#endif // C++2a + +#if __cplusplus == 201703L + template + __attribute__((__nonnull__)) + typename __not_pair<_Tp1>::type + construct(_Tp1* __p, _Args&&... __args) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2969. polymorphic_allocator::construct() shouldn't pass resource() + using __use_tag + = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>; + if constexpr (is_base_of_v<__uses_alloc0, __use_tag>) + ::new(__p) _Tp1(std::forward<_Args>(__args)...); + else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>) + ::new(__p) _Tp1(allocator_arg, *this, + std::forward<_Args>(__args)...); + else + ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this); + } + + template + __attribute__((__nonnull__)) + void + construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t, + tuple<_Args1...> __x, tuple<_Args2...> __y) + { + auto __x_tag = + __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this); + auto __y_tag = + __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this); + index_sequence_for<_Args1...> __x_i; + index_sequence_for<_Args2...> __y_i; + + ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct, + _S_construct_p(__x_tag, __x_i, __x), + _S_construct_p(__y_tag, __y_i, __y)); + } + + template + __attribute__((__nonnull__)) + void + construct(pair<_Tp1, _Tp2>* __p) + { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); } + + template + __attribute__((__nonnull__)) + void + construct(pair<_Tp1, _Tp2>* __p, _Up&& __x, _Vp&& __y) + { + this->construct(__p, piecewise_construct, + forward_as_tuple(std::forward<_Up>(__x)), + forward_as_tuple(std::forward<_Vp>(__y))); + } + + template + __attribute__((__nonnull__)) + void + construct(pair<_Tp1, _Tp2>* __p, const std::pair<_Up, _Vp>& __pr) + { + this->construct(__p, piecewise_construct, + forward_as_tuple(__pr.first), + forward_as_tuple(__pr.second)); + } + + template + __attribute__((__nonnull__)) + void + construct(pair<_Tp1, _Tp2>* __p, pair<_Up, _Vp>&& __pr) + { + this->construct(__p, piecewise_construct, + forward_as_tuple(std::forward<_Up>(__pr.first)), + forward_as_tuple(std::forward<_Vp>(__pr.second))); + } +#else + template + __attribute__((__nonnull__)) + void + construct(_Tp1* __p, _Args&&... __args) + { + std::uninitialized_construct_using_allocator(__p, *this, + std::forward<_Args>(__args)...); + } +#endif + + template + __attribute__((__nonnull__)) + void + destroy(_Up* __p) + { __p->~_Up(); } + + polymorphic_allocator + select_on_container_copy_construction() const noexcept + { return polymorphic_allocator(); } + + template ::value + && !is_same_v<_Target, memory_resource>>> + operator _Target*() const + { + memory_resource* res = resource(); + _Target& ret = dynamic_cast<_Target&>(*res); + return &ret; + } + + memory_resource* + resource() const noexcept + __attribute__((__returns_nonnull__)) + { return _M_resource; } + + private: + using __uses_alloc1_ = __uses_alloc1; + using __uses_alloc2_ = __uses_alloc2; + + template + static tuple<_Args&&...> + _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t) + { return std::move(__t); } + + template + static tuple + _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>, + tuple<_Args...>& __t) + { + return { + allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))... + }; + } + + template + static tuple<_Args&&..., polymorphic_allocator> + _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>, + tuple<_Args...>& __t) + { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; } + + memory_resource* _M_resource; + }; + + template + inline bool + operator==(const polymorphic_allocator<_Tp1>& __a, + const polymorphic_allocator<_Tp2>& __b) noexcept + { return *__a.resource() == *__b.resource(); } + + template + inline bool + operator!=(const polymorphic_allocator<_Tp1>& __a, + const polymorphic_allocator<_Tp2>& __b) noexcept + { return !(__a == __b); } + + + /// Parameters for tuning a pool resource's behaviour. + struct pool_options + { + /** @brief Upper limit on number of blocks in a chunk. + * + * A lower value prevents allocating huge chunks that could remain mostly + * unused, but means pools will need to replenished more frequently. + */ + size_t max_blocks_per_chunk = 0; + + /* @brief Largest block size (in bytes) that should be served from pools. + * + * Larger allocations will be served directly by the upstream resource, + * not from one of the pools managed by the pool resource. + */ + size_t largest_required_pool_block = 0; + }; + + // Common implementation details for un-/synchronized pool resources. + class __pool_resource + { + friend class synchronized_pool_resource; + friend class unsynchronized_pool_resource; + + __pool_resource(const pool_options& __opts, memory_resource* __upstream); + + ~__pool_resource(); + + __pool_resource(const __pool_resource&) = delete; + __pool_resource& operator=(const __pool_resource&) = delete; + + // Allocate a large unpooled block. + void* + allocate(size_t __bytes, size_t __alignment); + + // Deallocate a large unpooled block. + void + deallocate(void* __p, size_t __bytes, size_t __alignment); + + + // Deallocate unpooled memory. + void release() noexcept; + + memory_resource* resource() const noexcept + { return _M_unpooled.get_allocator().resource(); } + + struct _Pool; + + _Pool* _M_alloc_pools(); + + const pool_options _M_opts; + + struct _BigBlock; + // Collection of blocks too big for any pool, sorted by address. + // This also stores the only copy of the upstream memory resource pointer. + _GLIBCXX_STD_C::pmr::vector<_BigBlock> _M_unpooled; + + const int _M_npools; + }; + +#ifdef _GLIBCXX_HAS_GTHREADS + /// A thread-safe memory resource that manages pools of fixed-size blocks. + class synchronized_pool_resource : public memory_resource + { + public: + synchronized_pool_resource(const pool_options& __opts, + memory_resource* __upstream) + __attribute__((__nonnull__)); + + synchronized_pool_resource() + : synchronized_pool_resource(pool_options(), get_default_resource()) + { } + + explicit + synchronized_pool_resource(memory_resource* __upstream) + __attribute__((__nonnull__)) + : synchronized_pool_resource(pool_options(), __upstream) + { } + + explicit + synchronized_pool_resource(const pool_options& __opts) + : synchronized_pool_resource(__opts, get_default_resource()) { } + + synchronized_pool_resource(const synchronized_pool_resource&) = delete; + + virtual ~synchronized_pool_resource(); + + synchronized_pool_resource& + operator=(const synchronized_pool_resource&) = delete; + + void release(); + + memory_resource* + upstream_resource() const noexcept + __attribute__((__returns_nonnull__)) + { return _M_impl.resource(); } + + pool_options options() const noexcept { return _M_impl._M_opts; } + + protected: + void* + do_allocate(size_t __bytes, size_t __alignment) override; + + void + do_deallocate(void* __p, size_t __bytes, size_t __alignment) override; + + bool + do_is_equal(const memory_resource& __other) const noexcept override + { return this == &__other; } + + public: + // Thread-specific pools (only public for access by implementation details) + struct _TPools; + + private: + _TPools* _M_alloc_tpools(lock_guard&); + _TPools* _M_alloc_shared_tpools(lock_guard&); + auto _M_thread_specific_pools() noexcept; + + __pool_resource _M_impl; + __gthread_key_t _M_key; + // Linked list of thread-specific pools. All threads share _M_tpools[0]. + _TPools* _M_tpools = nullptr; + mutable shared_mutex _M_mx; + }; +#endif + + /// A non-thread-safe memory resource that manages pools of fixed-size blocks. + class unsynchronized_pool_resource : public memory_resource + { + public: + [[__gnu__::__nonnull__]] + unsynchronized_pool_resource(const pool_options& __opts, + memory_resource* __upstream); + + unsynchronized_pool_resource() + : unsynchronized_pool_resource(pool_options(), get_default_resource()) + { } + + [[__gnu__::__nonnull__]] + explicit + unsynchronized_pool_resource(memory_resource* __upstream) + : unsynchronized_pool_resource(pool_options(), __upstream) + { } + + explicit + unsynchronized_pool_resource(const pool_options& __opts) + : unsynchronized_pool_resource(__opts, get_default_resource()) { } + + unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete; + + virtual ~unsynchronized_pool_resource(); + + unsynchronized_pool_resource& + operator=(const unsynchronized_pool_resource&) = delete; + + void release(); + + [[__gnu__::__returns_nonnull__]] + memory_resource* + upstream_resource() const noexcept + { return _M_impl.resource(); } + + pool_options options() const noexcept { return _M_impl._M_opts; } + + protected: + void* + do_allocate(size_t __bytes, size_t __alignment) override; + + void + do_deallocate(void* __p, size_t __bytes, size_t __alignment) override; + + bool + do_is_equal(const memory_resource& __other) const noexcept override + { return this == &__other; } + + private: + using _Pool = __pool_resource::_Pool; + + auto _M_find_pool(size_t) noexcept; + + __pool_resource _M_impl; + _Pool* _M_pools = nullptr; + }; + + class monotonic_buffer_resource : public memory_resource + { + public: + explicit + monotonic_buffer_resource(memory_resource* __upstream) noexcept + __attribute__((__nonnull__)) + : _M_upstream(__upstream) + { _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); } + + monotonic_buffer_resource(size_t __initial_size, + memory_resource* __upstream) noexcept + __attribute__((__nonnull__)) + : _M_next_bufsiz(__initial_size), + _M_upstream(__upstream) + { + _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); + _GLIBCXX_DEBUG_ASSERT(__initial_size > 0); + } + + monotonic_buffer_resource(void* __buffer, size_t __buffer_size, + memory_resource* __upstream) noexcept + __attribute__((__nonnull__(4))) + : _M_current_buf(__buffer), _M_avail(__buffer_size), + _M_next_bufsiz(_S_next_bufsize(__buffer_size)), + _M_upstream(__upstream), + _M_orig_buf(__buffer), _M_orig_size(__buffer_size) + { + _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); + _GLIBCXX_DEBUG_ASSERT(__buffer != nullptr || __buffer_size == 0); + } + + monotonic_buffer_resource() noexcept + : monotonic_buffer_resource(get_default_resource()) + { } + + explicit + monotonic_buffer_resource(size_t __initial_size) noexcept + : monotonic_buffer_resource(__initial_size, get_default_resource()) + { } + + monotonic_buffer_resource(void* __buffer, size_t __buffer_size) noexcept + : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource()) + { } + + monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; + + virtual ~monotonic_buffer_resource() { release(); } + + monotonic_buffer_resource& + operator=(const monotonic_buffer_resource&) = delete; + + void + release() noexcept + { + if (_M_head) + _M_release_buffers(); + + // reset to initial state at contruction: + if ((_M_current_buf = _M_orig_buf)) + { + _M_avail = _M_orig_size; + _M_next_bufsiz = _S_next_bufsize(_M_orig_size); + } + else + { + _M_avail = 0; + _M_next_bufsiz = _M_orig_size; + } + } + + memory_resource* + upstream_resource() const noexcept + __attribute__((__returns_nonnull__)) + { return _M_upstream; } + + protected: + void* + do_allocate(size_t __bytes, size_t __alignment) override + { + if (__bytes == 0) + __bytes = 1; // Ensures we don't return the same pointer twice. + + void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail); + if (!__p) + { + _M_new_buffer(__bytes, __alignment); + __p = _M_current_buf; + } + _M_current_buf = (char*)_M_current_buf + __bytes; + _M_avail -= __bytes; + return __p; + } + + void + do_deallocate(void*, size_t, size_t) override + { } + + bool + do_is_equal(const memory_resource& __other) const noexcept override + { return this == &__other; } + + private: + // Update _M_current_buf and _M_avail to refer to a new buffer with + // at least the specified size and alignment, allocated from upstream. + void + _M_new_buffer(size_t __bytes, size_t __alignment); + + // Deallocate all buffers obtained from upstream. + void + _M_release_buffers() noexcept; + + static size_t + _S_next_bufsize(size_t __buffer_size) noexcept + { + if (__buffer_size == 0) + __buffer_size = 1; + return __buffer_size * _S_growth_factor; + } + + static constexpr size_t _S_init_bufsize = 128 * sizeof(void*); + static constexpr float _S_growth_factor = 1.5; + + void* _M_current_buf = nullptr; + size_t _M_avail = 0; + size_t _M_next_bufsiz = _S_init_bufsize; + + // Initial values set at construction and reused by release(): + memory_resource* const _M_upstream; + void* const _M_orig_buf = nullptr; + size_t const _M_orig_size = _M_next_bufsiz; + + class _Chunk; + _Chunk* _M_head = nullptr; + }; + +} // namespace pmr +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++17 +#endif // _GLIBCXX_MEMORY_RESOURCE diff --git a/groups/bdl/bdlb/pmroptional b/groups/bdl/bdlb/pmroptional new file mode 100644 index 0000000000..cd66ce9bcc --- /dev/null +++ b/groups/bdl/bdlb/pmroptional @@ -0,0 +1,2282 @@ +// -*- C++ -*- + +// Copyright (C) 2013-2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/pmroptional + * This is an extension header. + */ + +#ifndef _GLIBCXX_PMROPTIONAL +#define _GLIBCXX_PMROPTIONAL 1 + +#pragma GCC system_header + +#if __cplusplus >= 201703L + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION +namespace pmr { + /** + * @addtogroup utilities + * @{ + */ + +#define __cpp_lib_pmroptional 201810 + + template + class optional; + + // Payload for optionals with non-trivial destructor. + template , + bool /*_HasTrivialCopyAssignment*/ = + is_trivially_copy_assignable_v<_Tp>, + bool /*_HasTrivialMoveAssignment*/ = + is_trivially_move_assignable_v<_Tp>> + struct _Optional_payload + { + constexpr _Optional_payload() noexcept : _M_empty() { } + + template + constexpr + _Optional_payload(in_place_t, _Args&&... __args) + : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { } + + template + constexpr + _Optional_payload(std::initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(__il, std::forward<_Args>(__args)...), + _M_engaged(true) + { } + + template + constexpr + _Optional_payload(memory_resource* __pmr, _Args&&... __args) + { + if (!__pmr) + _M_pmr = std::pmr::get_default_resource(); + else + _M_pmr = __pmr; + _M_construct(std::forward<_Args>(__args)...); + } + + template + constexpr + _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, + _Args&&... __args) + { + if (!__pmr) + _M_pmr = std::pmr::get_default_resource(); + else + _M_pmr = __pmr; + _M_construct(__il, std::forward<_Args>(__args)...); + } + + constexpr + _Optional_payload(bool __engaged, const _Optional_payload& __other) + : _Optional_payload(__other) + { } + + constexpr + _Optional_payload(bool __engaged, _Optional_payload&& __other) + : _Optional_payload(std::move(__other)) + { } + + constexpr + _Optional_payload(const _Optional_payload& __other) + { + _M_pmr = __other._M_pmr; + if (__other._M_engaged) + this->_M_construct(__other._M_payload); + } + + constexpr + _Optional_payload(_Optional_payload&& __other) + { + _M_pmr = __other._M_pmr; + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_payload)); + } + + _Optional_payload& + operator=(const _Optional_payload& __other) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = __other._M_get(); + else + { + if (__other._M_engaged) + this->_M_construct(__other._M_get()); + else + this->_M_reset(); + } + return *this; + } + + _Optional_payload& + operator=(_Optional_payload&& __other) + noexcept(__and_v, + is_nothrow_move_assignable<_Tp>>) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = std::move(__other._M_get()); + else + { + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_get())); + else + this->_M_reset(); + } + return *this; + } + + using _Stored_type = remove_const_t<_Tp>; + + struct _Empty_byte { }; + + union { + _Empty_byte _M_empty; + _Stored_type _M_payload; + }; + bool _M_engaged = false; + memory_resource* _M_pmr = nullptr; + + ~_Optional_payload() + { + if (_M_engaged) + _M_payload.~_Stored_type(); + } + + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + if (_M_pmr) + { + __uses_allocator_construct(polymorphic_allocator<_Stored_type>(_M_pmr), + std::__addressof(this->_M_payload), + std::forward<_Args>(__args)...); + } + else + { + ::new ((void *) std::__addressof(this->_M_payload)) + _Stored_type(std::forward<_Args>(__args)...); + } + this->_M_engaged = true; + } + + // The _M_get operations have _M_engaged as a precondition. + constexpr _Tp& + _M_get() noexcept + { return this->_M_payload; } + + constexpr const _Tp& + _M_get() const noexcept + { return this->_M_payload; } + + // _M_reset is a 'safe' operation with no precondition. + void + _M_reset() noexcept + { + if (this->_M_engaged) + { + this->_M_engaged = false; + this->_M_payload.~_Stored_type(); + } + } + }; + + // Payload for potentially-constexpr optionals. + template + struct _Optional_payload<_Tp, true, true, true> + { + constexpr _Optional_payload() noexcept + : _M_empty(), _M_engaged(false), _M_pmr(nullptr) { } + + template + constexpr + _Optional_payload(in_place_t, _Args&&... __args) + : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true), + _M_pmr(nullptr) + { } + + template + constexpr + _Optional_payload(std::initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(__il, std::forward<_Args>(__args)...), + _M_engaged(true), + _M_pmr(nullptr) + { } + + template + constexpr + _Optional_payload(memory_resource* __pmr, _Args&&... __args) + : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true), + _M_pmr(__pmr ? __pmr : std::pmr::get_default_resource()) + { } + + template + constexpr + _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(__il, std::forward<_Args>(__args)...), + _M_engaged(true), + _M_pmr(__pmr ? __pmr : std::pmr::get_default_resource()) + { } + + template struct __ctor_tag {}; + + constexpr + _Optional_payload(__ctor_tag, const _Tp& __other) + : _M_payload(__other), _M_engaged(true), _M_pmr(__other._M_pmr) + { } + + constexpr _Optional_payload(__ctor_tag) noexcept + : _M_empty(), _M_engaged(false), _M_pmr(nullptr) + { } + + constexpr _Optional_payload(__ctor_tag, _Tp&& __other) + : _M_payload(std::move(__other)), _M_engaged(true), _M_pmr(__other._M_pmr) + { } + + constexpr + _Optional_payload(bool __engaged, const _Optional_payload& __other) + : _Optional_payload(__engaged ? + _Optional_payload(__ctor_tag{}, + __other._M_payload) : + _Optional_payload(__ctor_tag{})) + { _M_pmr = __other._M_pmr; } + + constexpr + _Optional_payload(bool __engaged, _Optional_payload&& __other) + : _Optional_payload(__engaged + ? _Optional_payload(__ctor_tag{}, + std::move(__other._M_payload)) + : _Optional_payload(__ctor_tag{})) + { _M_pmr = __other._M_pmr; } + + using _Stored_type = remove_const_t<_Tp>; + + struct _Empty_byte { }; + + union { + _Empty_byte _M_empty; + _Stored_type _M_payload; + }; + bool _M_engaged; + memory_resource* _M_pmr; + }; + + // Payload for optionals with non-trivial copy assignment. + template + struct _Optional_payload<_Tp, true, false, true> + { + constexpr _Optional_payload() noexcept + : _M_empty(), _M_engaged(false), _M_pmr(nullptr) { } + + template + constexpr + _Optional_payload(in_place_t, _Args&&... __args) + : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true), + _M_pmr(nullptr) + { } + + template + constexpr + _Optional_payload(std::initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(__il, std::forward<_Args>(__args)...), + _M_engaged(true), + _M_pmr(nullptr) + { } + + template + constexpr + _Optional_payload(memory_resource* __pmr, _Args&&... __args) + { + if (!__pmr) + _M_pmr = std::pmr::get_default_resource(); + else + _M_pmr = __pmr; + + _M_construct(std::forward<_Args>(__args)...); + } + + template + constexpr + _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, + _Args&&... __args) + { + if (!__pmr) + _M_pmr = std::pmr::get_default_resource(); + else + _M_pmr = __pmr; + _M_construct(__il, std::forward<_Args>(__args)...); + } + + template struct __ctor_tag {}; + + constexpr _Optional_payload(__ctor_tag, const _Tp& __other) + : _M_payload(__other), + _M_engaged(true), + _M_pmr(__other._M_pmr) + { } + + constexpr _Optional_payload(__ctor_tag) noexcept + : _M_empty(), _M_engaged(false), _M_pmr(nullptr) + { } + + constexpr _Optional_payload(__ctor_tag, _Tp&& __other) + : _M_payload(std::move(__other)), + _M_engaged(true), + _M_pmr(__other._M_pmr) + { } + + constexpr + _Optional_payload(bool __engaged, const _Optional_payload& __other) + : _Optional_payload(__engaged ? + _Optional_payload(__ctor_tag{}, + __other._M_payload) : + _Optional_payload(__ctor_tag{})) + { } + + constexpr + _Optional_payload(bool __engaged, _Optional_payload&& __other) + : _Optional_payload(__engaged + ? _Optional_payload(__ctor_tag{}, + std::move(__other._M_payload)) + : _Optional_payload(__ctor_tag{})) + { } + + _Optional_payload(const _Optional_payload&) = default; + _Optional_payload(_Optional_payload&&) = default; + + _Optional_payload& + operator=(const _Optional_payload& __other) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = __other._M_get(); + else + { + if (__other._M_engaged) + this->_M_construct(__other._M_get()); + else + this->_M_reset(); + } + return *this; + } + + _Optional_payload& + operator=(_Optional_payload&& __other) = default; + + using _Stored_type = remove_const_t<_Tp>; + + struct _Empty_byte { }; + + union { + _Empty_byte _M_empty; + _Stored_type _M_payload; + }; + bool _M_engaged; + memory_resource* _M_pmr; + + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + if (_M_pmr) + { + __uses_allocator_construct(polymorphic_allocator<_Stored_type>(_M_pmr), + std::__addressof(this->_M_payload), + std::forward<_Args>(__args)...); + } + else + { + ::new ((void *) std::__addressof(this->_M_payload)) + _Stored_type(std::forward<_Args>(__args)...); + } + this->_M_engaged = true; + } + + // The _M_get operations have _M_engaged as a precondition. + constexpr _Tp& + _M_get() noexcept + { return this->_M_payload; } + + constexpr const _Tp& + _M_get() const noexcept + { return this->_M_payload; } + + // _M_reset is a 'safe' operation with no precondition. + void + _M_reset() noexcept + { + if (this->_M_engaged) + { + this->_M_engaged = false; + this->_M_payload.~_Stored_type(); + } + } + }; + + // Payload for optionals with non-trivial move assignment. + template + struct _Optional_payload<_Tp, true, true, false> + { + constexpr _Optional_payload() noexcept + : _M_empty(), _M_engaged(false), _M_pmr(nullptr) { } + + template + constexpr + _Optional_payload(in_place_t, _Args&&... __args) + : _M_payload(std::forward<_Args>(__args)...), + _M_engaged(true), + _M_pmr(nullptr) + { } + + template + constexpr + _Optional_payload(std::initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(__il, std::forward<_Args>(__args)...), + _M_engaged(true), + _M_pmr(nullptr) + { } + + template + constexpr + _Optional_payload(memory_resource* __pmr, _Args&&... __args) + { + if (!__pmr) + _M_pmr = std::pmr::get_default_resource(); + else + _M_pmr = __pmr; + _M_construct(std::forward<_Args>(__args)...); + } + + template + constexpr + _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, + _Args&&... __args) + { + if (!__pmr) + _M_pmr = std::pmr::get_default_resource(); + else + _M_pmr = __pmr; + _M_construct(__il, std::forward<_Args>(__args)...); + } + + template struct __ctor_tag {}; + + constexpr + _Optional_payload(__ctor_tag, const _Tp& __other) + : _M_payload(__other), + _M_engaged(true), + _M_pmr(__other._M_pmr) + { } + + constexpr _Optional_payload(__ctor_tag) noexcept + : _M_empty(), _M_engaged(false) + { } + + constexpr _Optional_payload(__ctor_tag, _Tp&& __other) + : _M_payload(std::move(__other)), + _M_engaged(true), + _M_pmr(__other._M_pmr) + { } + + constexpr + _Optional_payload(bool __engaged, const _Optional_payload& __other) + : _Optional_payload(__engaged ? + _Optional_payload(__ctor_tag{}, + __other._M_payload) : + _Optional_payload(__ctor_tag{})) + { } + + constexpr + _Optional_payload(bool __engaged, _Optional_payload&& __other) + : _Optional_payload(__engaged + ? _Optional_payload(__ctor_tag{}, + std::move(__other._M_payload)) + : _Optional_payload(__ctor_tag{})) + { } + + _Optional_payload(const _Optional_payload&) = default; + _Optional_payload(_Optional_payload&&) = default; + + _Optional_payload& + operator=(const _Optional_payload& __other) = default; + + _Optional_payload& + operator=(_Optional_payload&& __other) + noexcept(__and_v, + is_nothrow_move_assignable<_Tp>>) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = std::move(__other._M_get()); + else + { + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_get())); + else + this->_M_reset(); + } + return *this; + } + + using _Stored_type = remove_const_t<_Tp>; + + struct _Empty_byte { }; + + union { + _Empty_byte _M_empty; + _Stored_type _M_payload; + }; + bool _M_engaged; + memory_resource* _M_pmr; + + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + if (_M_pmr) + { + __uses_allocator_construct(polymorphic_allocator<_Stored_type>(_M_pmr), + std::__addressof(this->_M_payload), + std::forward<_Args>(__args)...); + } + else + { + ::new ((void *) std::__addressof(this->_M_payload)) + _Stored_type(std::forward<_Args>(__args)...); + } + this->_M_engaged = true; + } + + // The _M_get operations have _M_engaged as a precondition. + constexpr _Tp& + _M_get() noexcept + { return this->_M_payload; } + + constexpr const _Tp& + _M_get() const noexcept + { return this->_M_payload; } + + // _M_reset is a 'safe' operation with no precondition. + void + _M_reset() noexcept + { + if (this->_M_engaged) + { + this->_M_engaged = false; + this->_M_payload.~_Stored_type(); + } + } + }; + + // Payload for optionals with non-trivial copy and move assignment. + template + struct _Optional_payload<_Tp, true, false, false> + { + constexpr _Optional_payload() noexcept + : _M_empty(), _M_engaged(false), _M_pmr(nullptr) {} + + template + constexpr + _Optional_payload(in_place_t, _Args&&... __args) + : _M_payload(std::forward<_Args>(__args)...), + _M_engaged(true), + _M_pmr(nullptr) + { } + + template + constexpr + _Optional_payload(std::initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(__il, std::forward<_Args>(__args)...), + _M_engaged(true), + _M_pmr(nullptr) + { } + + template + constexpr + _Optional_payload(memory_resource* __pmr, _Args&&... __args) + { + if (!__pmr) + _M_pmr = std::pmr::get_default_resource(); + else + _M_pmr = __pmr; + _M_construct(std::forward<_Args>(__args)...); + } + + template + constexpr + _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, + _Args&&... __args) + { + if (!__pmr) + _M_pmr = std::pmr::get_default_resource(); + else + _M_pmr = __pmr; + _M_construct(__il, std::forward<_Args>(__args)...); + } + + template struct __ctor_tag {}; + + constexpr _Optional_payload(__ctor_tag, const _Tp& __other) + : _M_payload(__other), + _M_engaged(true), + _M_pmr(__other._M_pmr) + { } + + constexpr _Optional_payload(__ctor_tag) noexcept + : _M_empty(), _M_engaged(false), _M_pmr(nullptr) + { } + + constexpr _Optional_payload(__ctor_tag, _Tp&& __other) + : _M_payload(std::move(__other)), + _M_engaged(true), + _M_pmr(__other._M_pmr) + { } + + constexpr + _Optional_payload(bool __engaged, const _Optional_payload& __other) + : _Optional_payload(__engaged ? + _Optional_payload(__ctor_tag{}, + __other._M_payload) : + _Optional_payload(__ctor_tag{})) + { } + + constexpr + _Optional_payload(bool __engaged, _Optional_payload&& __other) + : _Optional_payload(__engaged + ? _Optional_payload(__ctor_tag{}, + std::move(__other._M_payload)) + : _Optional_payload(__ctor_tag{})) + { } + + _Optional_payload(const _Optional_payload&) = default; + _Optional_payload(_Optional_payload&&) = default; + + _Optional_payload& + operator=(const _Optional_payload& __other) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = __other._M_get(); + else + { + if (__other._M_engaged) + this->_M_construct(__other._M_get()); + else + this->_M_reset(); + } + return *this; + } + + _Optional_payload& + operator=(_Optional_payload&& __other) + noexcept(__and_v, + is_nothrow_move_assignable<_Tp>>) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = std::move(__other._M_get()); + else + { + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_get())); + else + this->_M_reset(); + } + return *this; + } + + using _Stored_type = remove_const_t<_Tp>; + + struct _Empty_byte { }; + + union { + _Empty_byte _M_empty; + _Stored_type _M_payload; + }; + bool _M_engaged; + memory_resource* _M_pmr; + + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + if (_M_pmr) + { + __uses_allocator_construct(polymorphic_allocator<_Stored_type>(_M_pmr), + std::__addressof(this->_M_payload), + std::forward<_Args>(__args)...); + } + else + { + ::new ((void *) std::__addressof(this->_M_payload)) + _Stored_type(std::forward<_Args>(__args)...); + } + this->_M_engaged = true; + } + + // The _M_get operations have _M_engaged as a precondition. + constexpr _Tp& + _M_get() noexcept + { return this->_M_payload; } + + constexpr const _Tp& + _M_get() const noexcept + { return this->_M_payload; } + + // _M_reset is a 'safe' operation with no precondition. + void + _M_reset() noexcept + { + if (this->_M_engaged) + { + this->_M_engaged = false; + this->_M_payload.~_Stored_type(); + } + } + }; + + template + class _Optional_base_impl + { + protected: + using _Stored_type = remove_const_t<_Tp>; + + // The _M_construct operation has !_M_engaged as a precondition + // while _M_destruct has _M_engaged as a precondition. + template + void + _M_construct(memory_resource* __pmr, _Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + __uses_allocator_construct(polymorphic_allocator(__pmr), + std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload), + std::forward<_Args>(__args)...); + static_cast<_Dp*>(this)->_M_payload._M_engaged = true; + } + + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + if (static_cast<_Dp*>(this)->_M_payload._M_pmr) + { + __uses_allocator_construct(polymorphic_allocator(static_cast<_Dp*>(this)->_M_payload._M_pmr), + std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload), + std::forward<_Args>(__args)...); + } + else + { + ::new + (std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload)) + _Stored_type(std::forward<_Args>(__args)...); + } + static_cast<_Dp*>(this)->_M_payload._M_engaged = true; + } + + void + _M_destruct() noexcept + { + static_cast<_Dp*>(this)->_M_payload._M_engaged = false; + static_cast<_Dp*>(this)->_M_payload._M_payload.~_Stored_type(); + } + + // _M_reset is a 'safe' operation with no precondition. + void + _M_reset() noexcept + { + if (static_cast<_Dp*>(this)->_M_payload._M_engaged) + static_cast<_Dp*>(this)->_M_destruct(); + } + + void _M_set_allocator(memory_resource* __pmr) noexcept + { + if (__pmr) + static_cast<_Dp*>(this)->_M_payload._M_pmr = __pmr; + else + static_cast<_Dp*>(this)->_M_payload._M_pmr = std::pmr::get_default_resource(); + } + memory_resource* _M_get_allocator() noexcept + { + return static_cast<_Dp*>(this)->_M_payload._M_pmr; + } + }; + + /** + * @brief Class template that takes care of copy/move constructors + of optional + * + * Such a separate base class template is necessary in order to + * conditionally make copy/move constructors trivial. + * @see optional, _Enable_special_members + */ + template, + bool = is_trivially_move_constructible_v<_Tp>> + class _Optional_base + // protected inheritance because optional needs to reach that base too + : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> + { + friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; + + public: + // Constructors for disengaged optionals. + constexpr _Optional_base() = default; + + // Constructors for engaged optionals. + template, bool> = false> + constexpr explicit _Optional_base(in_place_t, _Args&&... __args) + : _M_payload(in_place, + std::forward<_Args>(__args)...) { } + + // Constructors for engaged optionals. + template, _Args&&...>, bool> = false> + constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) + : _M_payload(__pmr, + std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>, bool> = false> + constexpr explicit _Optional_base(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(in_place, + __il, std::forward<_Args>(__args)...) + { } + + // Copy and move constructors. + constexpr _Optional_base(const _Optional_base& __other) + : _M_payload(__other._M_payload._M_engaged, + __other._M_payload) + { } + + constexpr _Optional_base(_Optional_base&& __other) + noexcept(is_nothrow_move_constructible_v<_Tp>) + : _M_payload(__other._M_payload._M_engaged, + std::move(__other._M_payload)) + { } + + // Assignment operators. + _Optional_base& operator=(const _Optional_base&) = default; + _Optional_base& operator=(_Optional_base&&) = default; + + protected: + + constexpr bool _M_is_engaged() const noexcept + { return this->_M_payload._M_engaged; } + + // The _M_get operations have _M_engaged as a precondition. + constexpr _Tp& + _M_get() noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return this->_M_payload._M_payload; + } + + constexpr const _Tp& + _M_get() const noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return this->_M_payload._M_payload; + } + + private: + _Optional_payload<_Tp> _M_payload; + }; + + template + class _Optional_base<_Tp, false, true> + : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> + { + friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; + public: + + // Constructors for disengaged optionals. + constexpr _Optional_base() = default; + + // Constructors for engaged optionals. + template, bool> = false> + constexpr explicit _Optional_base(in_place_t, _Args&&... __args) + : _M_payload(in_place, + std::forward<_Args>(__args)...) { } + + // Constructors for engaged optionals. + template, _Args&&...>, bool> = false> + constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) + : _M_payload(__pmr, + std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>, bool> = false> + constexpr explicit _Optional_base(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(in_place, + __il, std::forward<_Args>(__args)...) + { } + + // Copy and move constructors. + constexpr _Optional_base(const _Optional_base& __other) + : _M_payload(__other._M_payload._M_engaged, + __other._M_payload) + { } + + constexpr _Optional_base(_Optional_base&& __other) = default; + + // Assignment operators. + _Optional_base& operator=(const _Optional_base&) = default; + _Optional_base& operator=(_Optional_base&&) = default; + + protected: + + constexpr bool _M_is_engaged() const noexcept + { return this->_M_payload._M_engaged; } + + // The _M_get operations have _M_engaged as a precondition. + constexpr _Tp& + _M_get() noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return this->_M_payload._M_payload; + } + + constexpr const _Tp& + _M_get() const noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return this->_M_payload._M_payload; + } + + private: + _Optional_payload<_Tp> _M_payload; + }; + + template + class _Optional_base<_Tp, true, false> + : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> + { + friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; + public: + + // Constructors for disengaged optionals. + constexpr _Optional_base() = default; + + // Constructors for engaged optionals. + template, bool> = false> + constexpr explicit _Optional_base(in_place_t, _Args&&... __args) + : _M_payload(in_place, + std::forward<_Args>(__args)...) { } + + template, _Args&&...>, bool> = false> + constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) + : _M_payload(__pmr, + std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>, bool> = false> + constexpr explicit _Optional_base(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(in_place, + __il, std::forward<_Args>(__args)...) + { } + + // Copy and move constructors. + constexpr _Optional_base(const _Optional_base& __other) = default; + + constexpr _Optional_base(_Optional_base&& __other) + noexcept(is_nothrow_move_constructible_v<_Tp>) + : _M_payload(__other._M_payload._M_engaged, + std::move(__other._M_payload)) + { } + + // Assignment operators. + _Optional_base& operator=(const _Optional_base&) = default; + _Optional_base& operator=(_Optional_base&&) = default; + + protected: + + constexpr bool _M_is_engaged() const noexcept + { return this->_M_payload._M_engaged; } + + // The _M_get operations have _M_engaged as a precondition. + constexpr _Tp& + _M_get() noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return this->_M_payload._M_payload; + } + + constexpr const _Tp& + _M_get() const noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return this->_M_payload._M_payload; + } + + private: + _Optional_payload<_Tp> _M_payload; + }; + + template + class _Optional_base<_Tp, true, true> + : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> + { + friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; + public: + + // Constructors for disengaged optionals. + constexpr _Optional_base() = default; + + // Constructors for engaged optionals. + template, bool> = false> + constexpr explicit _Optional_base(in_place_t, _Args&&... __args) + : _M_payload(in_place, + std::forward<_Args>(__args)...) { } + + template, _Args&&...>, bool> = false> + constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) + : _M_payload(__pmr, + std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>, bool> = false> + constexpr explicit _Optional_base(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(in_place, + __il, std::forward<_Args>(__args)...) + { } + + // Copy and move constructors. + constexpr _Optional_base(const _Optional_base& __other) = default; + constexpr _Optional_base(_Optional_base&& __other) = default; + + // Assignment operators. + _Optional_base& operator=(const _Optional_base&) = default; + _Optional_base& operator=(_Optional_base&&) = default; + + protected: + + constexpr bool _M_is_engaged() const noexcept + { return this->_M_payload._M_engaged; } + + // The _M_get operations have _M_engaged as a precondition. + constexpr _Tp& + _M_get() noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return this->_M_payload._M_payload; + } + + constexpr const _Tp& + _M_get() const noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return this->_M_payload._M_payload; + } + + private: + _Optional_payload<_Tp> _M_payload; + }; + + template + class optional; + + template + using __converts_from_optional = + __or_&>, + is_constructible<_Tp, optional<_Up>&>, + is_constructible<_Tp, const optional<_Up>&&>, + is_constructible<_Tp, optional<_Up>&&>, + is_convertible&, _Tp>, + is_convertible&, _Tp>, + is_convertible&&, _Tp>, + is_convertible&&, _Tp>, + is_constructible<_Tp, const std::optional<_Up>&>, + is_constructible<_Tp, std::optional<_Up>&>, + is_constructible<_Tp, const std::optional<_Up>&&>, + is_constructible<_Tp, std::optional<_Up>&&>, + is_convertible&, _Tp>, + is_convertible&, _Tp>, + is_convertible&&, _Tp>, + is_convertible&&, _Tp>>; + + template + using __assigns_from_optional = + __or_&>, + is_assignable<_Tp&, optional<_Up>&>, + is_assignable<_Tp&, const optional<_Up>&&>, + is_assignable<_Tp&, optional<_Up>&&>, + is_assignable<_Tp&, const std::optional<_Up>&>, + is_assignable<_Tp&, std::optional<_Up>&>, + is_assignable<_Tp&, const std::optional<_Up>&&>, + is_assignable<_Tp&, std::optional<_Up>&&>>; + /* + template + struct __has_allocator_type + { + using __alloc_param_type = __nonesuch; + }; + + template + struct __has_allocator_type<_Tp, __void_t> + { + using __alloc_param_type = + typename __remove_cvref_t<_Tp>::allocator_type; + }; + */ + /** + * @brief Class template for optional values. + */ + template + class optional + : private _Optional_base<_Tp>, + private _Enable_copy_move< + // Copy constructor. + is_copy_constructible_v<_Tp>, + // Copy assignment. + __and_v, is_copy_assignable<_Tp>>, + // Move constructor. + is_move_constructible_v<_Tp>, + // Move assignment. + __and_v, is_move_assignable<_Tp>>, + // Unique tag type. + optional<_Tp>> + { + static_assert(!is_same_v, nullopt_t>); + static_assert(!is_same_v, in_place_t>); + static_assert(!is_reference_v<_Tp>); + + private: + using _Base = _Optional_base<_Tp>; + + // SFINAE helpers + template + using __not_self = __not_>>; + template + using __not_tag = __not_>>; + template + using _Requires = enable_if_t<__and_v<_Cond...>, bool>; + + public: + /* + using __alloc_param_type = + typename __has_allocator_type<_Tp>::__alloc_param_type; + */ + using value_type = _Tp; + + constexpr optional() = default; + + constexpr optional(nullopt_t) noexcept { } + + // Converting constructors for engaged optionals. + template, __not_tag<_Up>, + __not_>>>, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>> = true> + constexpr + optional(_Up&& __t) + : _Base(std::in_place, std::forward<_Up>(__t)) { } + + template, __not_tag<_Up>, + __not_>>>, + is_constructible<_Tp, _Up&&>, + __not_>> = false> + explicit constexpr + optional(_Up&& __t) + : _Base(std::in_place, std::forward<_Up>(__t)) { } + + template>, + is_constructible<_Tp, const _Up&>, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(const optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template>, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(const optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + template>, + is_constructible<_Tp, const _Up&>, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(const std::optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template>, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(const std::optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(std::optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(std::optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + constexpr + optional(const std::optional<_Tp>& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + constexpr + optional(std::optional<_Tp>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + // Converting memory-resource-constructors for engaged optionals. + + optional(memory_resource* __pmr) + { + if (!__pmr) + this->_M_set_allocator(std::pmr::get_default_resource()); + else + this->_M_set_allocator(__pmr); + } + template, __not_tag<_Up>, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>> = true> + constexpr + optional(_Up&& __t, memory_resource* __pmr) + { + memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + this->_M_set_allocator(__actual_alloc); + __emplace_alloc(__actual_alloc, std::forward<_Up>(__t)); + } + + template, __not_tag<_Up>, + is_constructible<_Tp, _Up&&>, + __not_>> = false> + explicit constexpr + optional(_Up&& __t, memory_resource* __pmr) + { + memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + this->_M_set_allocator(__actual_alloc); + __emplace_alloc(__actual_alloc, std::forward<_Up>(__t)); + } + + template>, + is_constructible<_Tp, const _Up&>, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(const optional<_Up>& __t, memory_resource* __pmr) + { + memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + this->_M_set_allocator(__actual_alloc); + __emplace_alloc(__actual_alloc, *__t); + } + + template>, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(const optional<_Up>& __t, memory_resource* __pmr) + { + memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + if (__t) + this->_M_set_allocator(__actual_alloc); + __emplace_alloc(__actual_alloc, *__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(optional<_Up>&& __t, memory_resource* __pmr) + { + memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + this->_M_set_allocator(__actual_alloc); + if (__t) + __emplace_alloc(__actual_alloc, std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(optional<_Up>&& __t, memory_resource* __pmr) + { + memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + this->_M_set_allocator(__actual_alloc); + if (__t) + __emplace_alloc(__actual_alloc, std::move(*__t)); + } + + constexpr + optional(const optional& __t, memory_resource* __pmr) + { + memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + this->_M_set_allocator(__actual_alloc); + if (__t) + __emplace_alloc(__actual_alloc, *__t); + } + + constexpr + optional(optional&& __t, memory_resource* __pmr) + { + memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + this->_M_set_allocator(__actual_alloc); + if (__t) + __emplace_alloc(__actual_alloc, std::move(*__t)); + } + + template, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(const std::optional<_Up>& __t, memory_resource* __pmr) + { + memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + this->_M_set_allocator(__actual_alloc); + if (__t) + __emplace_alloc(__actual_alloc, *__t); + } + + template, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(const std::optional<_Up>& __t, memory_resource* __pmr) + { + memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + this->_M_set_allocator(__actual_alloc); + if (__t) + __emplace_alloc(__actual_alloc, *__t); + } + + template , + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(std::optional<_Up>&& __t, memory_resource* __pmr) + { + memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + this->_M_set_allocator(__actual_alloc); + if (__t) + __emplace_alloc(__actual_alloc, std::move(*__t)); + } + + template , + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(std::optional<_Up>&& __t, memory_resource* __pmr) + { + memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + this->_M_set_allocator(__actual_alloc); + if (__t) + __emplace_alloc(__actual_alloc, std::move(*__t)); + } + + // Converting allocator-constructors for engaged optionals. + template, __not_tag<_Up>, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>> = true> + constexpr + optional(_Up&& __t, const polymorphic_allocator& __pmr) + : _Base(__pmr.resource(), std::forward<_Up>(__t)) { } + + template, __not_tag<_Up>, + is_constructible<_Tp, _Up&&>, + __not_>> = false> + explicit constexpr + optional(_Up&& __t, const polymorphic_allocator& __pmr) + : _Base(__pmr.resource(), std::forward<_Up>(__t)) { } + + template>, + is_constructible<_Tp, const _Up&>, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(const optional<_Up>& __t, const polymorphic_allocator& __pmr) + { + this->_M_set_allocator(__pmr.resource()); + if (__t) + __emplace_alloc(__pmr, *__t); + } + + template>, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(const optional<_Up>& __t, const polymorphic_allocator& __pmr) + { + this->_M_set_allocator(__pmr.resource()); + if (__t) + __emplace_alloc(__pmr, *__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(optional<_Up>&& __t, const polymorphic_allocator& __pmr) + { + this->_M_set_allocator(__pmr.resource()); + if (__t) + __emplace_alloc(__pmr, std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(optional<_Up>&& __t, const polymorphic_allocator& __pmr) + { + this->_M_set_allocator(__pmr.resource()); + if (__t) + __emplace_alloc(__pmr, std::move(*__t)); + } + + template, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(const std::optional<_Up>& __t, const polymorphic_allocator& __pmr) + { + this->_M_set_allocator(__pmr.resource()); + if (__t) + __emplace_alloc(__pmr, *__t); + } + + template, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(const std::optional<_Up>& __t, const polymorphic_allocator& __pmr) + { + this->_M_set_allocator(__pmr.resource()); + if (__t) + __emplace_alloc(__pmr, *__t); + } + + template , + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(std::optional<_Up>&& __t, const polymorphic_allocator& __pmr) + { + this->_M_set_allocator(__pmr.resource()); + if (__t) + __emplace_alloc(__pmr, std::move(*__t)); + } + + template , + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(std::optional<_Up>&& __t, const polymorphic_allocator& __pmr) + { + this->_M_set_allocator(__pmr.resource()); + if (__t) + __emplace_alloc(__pmr, std::move(*__t)); + } + + constexpr + optional(const optional& __t, const polymorphic_allocator& __pmr) + { + this->_M_set_allocator(__pmr.resource()); + if (__t) + __emplace_alloc(__pmr, *__t); + } + + constexpr + optional(optional&& __t, const polymorphic_allocator& __pmr) + { + this->_M_set_allocator(__pmr.resource()); + if (__t) + __emplace_alloc(__pmr, std::move(*__t)); + } + + template> = false> + explicit constexpr + optional(in_place_t, _Args&&... __args) + : _Base(std::in_place, std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>> = false> + explicit constexpr + optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) + : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { } + + // Assignment operators. + optional& + operator=(nullopt_t) noexcept + { + this->_M_reset(); + return *this; + } + + template + enable_if_t<__and_v<__not_self<_Up>, + __not_<__and_, + is_same<_Tp, decay_t<_Up>>>>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>>, + optional&> + operator=(_Up&& __u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::forward<_Up>(__u); + else + this->_M_construct(std::forward<_Up>(__u)); + + return *this; + } + + template + enable_if_t<__and_v<__not_>, + is_constructible<_Tp, const _Up&>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + optional&> + operator=(const optional<_Up>& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = *__u; + else + this->_M_construct(*__u); + } + else + { + this->_M_reset(); + } + return *this; + } + + template + enable_if_t<__and_v<__not_>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + optional&> + operator=(optional<_Up>&& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::move(*__u); + else + this->_M_construct(std::move(*__u)); + } + else + { + this->_M_reset(); + } + + return *this; + } + + template + enable_if_t<__and_v, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + optional&> + operator=(const std::optional<_Up>& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = *__u; + else + this->_M_construct(*__u); + } + else + { + this->_M_reset(); + } + return *this; + } + + template + enable_if_t<__and_v, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + optional&> + operator=(std::optional<_Up>&& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::move(*__u); + else + this->_M_construct(std::move(*__u)); + } + else + { + this->_M_reset(); + } + + return *this; + } + + + template + enable_if_t, _Tp&> + emplace(_Args&&... __args) + { + this->_M_reset(); + this->_M_construct(std::forward<_Args>(__args)...); + return this->_M_get(); + } + + template + //enable_if_t<__is_uses_allocator_constructible_v<_Tp, polymorphic_allocator, _Args&&...>, _Tp&> + _Tp& + __emplace_alloc(memory_resource* __pmr, _Args&&... __args) + { + this->_M_reset(); + this->_M_construct(__pmr, std::forward<_Args>(__args)...); + return this->_M_get(); + } + + template + //enable_if_t<__is_uses_allocator_constructible_v<_Tp, polymorphic_allocator, _Args&&...>, _Tp&> + _Tp& + __emplace_alloc(const polymorphic_allocator& __pmr, _Args&&... __args) + { + this->_M_reset(); + this->_M_construct(__pmr.resource(), std::forward<_Args>(__args)...); + return this->_M_get(); + } + + template + enable_if_t&, + _Args&&...>, _Tp&> + emplace(initializer_list<_Up> __il, _Args&&... __args) + { + this->_M_reset(); + this->_M_construct(__il, std::forward<_Args>(__args)...); + return this->_M_get(); + } + + // Destructor is implicit, implemented in _Optional_base. + + // Swap. + void + swap(optional& __other) + noexcept(is_nothrow_move_constructible_v<_Tp> + && is_nothrow_swappable_v<_Tp>) + { + using std::swap; + + if (this->_M_is_engaged() && __other._M_is_engaged()) + swap(this->_M_get(), __other._M_get()); + else if (this->_M_is_engaged()) + { + __other._M_construct(std::move(this->_M_get())); + this->_M_destruct(); + } + else if (__other._M_is_engaged()) + { + this->_M_construct(std::move(__other._M_get())); + __other._M_destruct(); + } + } + + // Observers. + constexpr const _Tp* + operator->() const + { return std::__addressof(this->_M_get()); } + + _Tp* + operator->() + { return std::__addressof(this->_M_get()); } + + constexpr const _Tp& + operator*() const& + { return this->_M_get(); } + + constexpr _Tp& + operator*()& + { return this->_M_get(); } + + constexpr _Tp&& + operator*()&& + { return std::move(this->_M_get()); } + + constexpr const _Tp&& + operator*() const&& + { return std::move(this->_M_get()); } + + constexpr explicit operator bool() const noexcept + { return this->_M_is_engaged(); } + + constexpr bool has_value() const noexcept + { return this->_M_is_engaged(); } + + constexpr const _Tp& + value() const& + { + return this->_M_is_engaged() + ? this->_M_get() + : (__throw_bad_optional_access(), + this->_M_get()); + } + + constexpr _Tp& + value()& + { + return this->_M_is_engaged() + ? this->_M_get() + : (__throw_bad_optional_access(), + this->_M_get()); + } + + constexpr _Tp&& + value()&& + { + return this->_M_is_engaged() + ? std::move(this->_M_get()) + : (__throw_bad_optional_access(), + std::move(this->_M_get())); + } + + constexpr const _Tp&& + value() const&& + { + return this->_M_is_engaged() + ? std::move(this->_M_get()) + : (__throw_bad_optional_access(), + std::move(this->_M_get())); + } + + template + constexpr _Tp + value_or(_Up&& __u) const& + { + static_assert(is_copy_constructible_v<_Tp>); + static_assert(is_convertible_v<_Up&&, _Tp>); + + return this->_M_is_engaged() + ? this->_M_get() + : static_cast<_Tp>(std::forward<_Up>(__u)); + } + + template + _Tp + value_or(_Up&& __u) && + { + static_assert(is_move_constructible_v<_Tp>); + static_assert(is_convertible_v<_Up&&, _Tp>); + + return this->_M_is_engaged() + ? std::move(this->_M_get()) + : static_cast<_Tp>(std::forward<_Up>(__u)); + } + + void reset() noexcept { this->_M_reset(); } + + // bloomberg extensions start here + template + _Tp& makeValue(_Up&& __u) + { + memory_resource* __actual_alloc = this->_M_get_allocator(); + if (__actual_alloc) { + this->__emplace_alloc(__actual_alloc, std::forward<_Up>(__u)); + } + else + this->emplace(std::forward<_Up>(__u)); + + return *(*this); + } + + _Tp& makeValue() + { + memory_resource* __actual_alloc = this->_M_get_allocator(); + if (__actual_alloc) { + this->__emplace_alloc(__actual_alloc); + } + else + this->emplace(); + return *(*this); + } + + template + _Tp& makeValueInplace(_Args&&... __args) + { + memory_resource* __actual_alloc = this->_M_get_allocator(); + if (__actual_alloc) + return this->__emplace_alloc(__actual_alloc, + std::forward<_Args>(__args)...); + else + return this->emplace(std::forward<_Args>(__args)...); + } + + bool isNull() const + { + return !this->has_value(); + } + + int maxSupportedBdexVersion(int versionSelector) const; + + template + _Stream& bdexStreamIn(_Stream& stream, int version); + + template + _Stream& bdexStreamOut(_Stream& stream, int version) const; + + template + auto& print(_Stream& stream, int level = 0, + int spacesPerLevel = 4) const; + + typedef _Tp ValueType; + + const _Tp* addressOr(const _Tp* __value) const + { + return this->isNull() ? __value : &this->value(); + } + + const _Tp* valueOrNull() const + { + return this->isNull() ? 0 : &this->value(); + } + + _Tp valueOr(const _Tp& __value) const + { + return this->isNull() ? __value : this->value(); + } + + const _Tp* valueOr(const _Tp* __value) const + { + return this->isNull() ? __value : &this->value(); + } + + }; + + template + using __optional_relop_t = + enable_if_t::value, bool>; + + // Comparisons between optional values. + template + constexpr auto + operator==(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() == declval<_Up>())> + { + return static_cast(__lhs) == static_cast(__rhs) + && (!__lhs || *__lhs == *__rhs); + } + + template + constexpr auto + operator!=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() != declval<_Up>())> + { + return static_cast(__lhs) != static_cast(__rhs) + || (static_cast(__lhs) && *__lhs != *__rhs); + } + + template + constexpr auto + operator<(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { + return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); + } + + template + constexpr auto + operator>(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { + return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); + } + + template + constexpr auto + operator<=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { + return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); + } + + template + constexpr auto + operator>=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { + return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs); + } + + // Comparisons with nullopt. + template + constexpr bool + operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept + { return !__lhs; } + + template + constexpr bool + operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept + { return !__rhs; } + + template + constexpr bool + operator!=(const optional<_Tp>& __lhs, nullopt_t) noexcept + { return static_cast(__lhs); } + + template + constexpr bool + operator!=(nullopt_t, const optional<_Tp>& __rhs) noexcept + { return static_cast(__rhs); } + + template + constexpr bool + operator<(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept + { return false; } + + template + constexpr bool + operator<(nullopt_t, const optional<_Tp>& __rhs) noexcept + { return static_cast(__rhs); } + + template + constexpr bool + operator>(const optional<_Tp>& __lhs, nullopt_t) noexcept + { return static_cast(__lhs); } + + template + constexpr bool + operator>(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept + { return false; } + + template + constexpr bool + operator<=(const optional<_Tp>& __lhs, nullopt_t) noexcept + { return !__lhs; } + + template + constexpr bool + operator<=(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept + { return true; } + + template + constexpr bool + operator>=(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept + { return true; } + + template + constexpr bool + operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept + { return !__rhs; } + + // Comparisons with value type. + template + constexpr auto + operator==(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() == declval<_Up>())> + { return __lhs && *__lhs == __rhs; } + + template + constexpr auto + operator==(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() == declval<_Tp>())> + { return __rhs && __lhs == *__rhs; } + + template + constexpr auto + operator!=(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() != declval<_Up>())> + { return !__lhs || *__lhs != __rhs; } + + template + constexpr auto + operator!=(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() != declval<_Tp>())> + { return !__rhs || __lhs != *__rhs; } + + template + constexpr auto + operator<(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { return !__lhs || *__lhs < __rhs; } + + template + constexpr auto + operator<(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() < declval<_Tp>())> + { return __rhs && __lhs < *__rhs; } + + template + constexpr auto + operator>(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { return __lhs && *__lhs > __rhs; } + + template + constexpr auto + operator>(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() > declval<_Tp>())> + { return !__rhs || __lhs > *__rhs; } + + template + constexpr auto + operator<=(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { return !__lhs || *__lhs <= __rhs; } + + template + constexpr auto + operator<=(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() <= declval<_Tp>())> + { return __rhs && __lhs <= *__rhs; } + + template + constexpr auto + operator>=(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { return __lhs && *__lhs >= __rhs; } + + template + constexpr auto + operator>=(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() >= declval<_Tp>())> + { return !__rhs || __lhs >= *__rhs; } + + + template + constexpr optional> + make_optional(_Tp&& __t) + { return optional> { std::forward<_Tp>(__t) }; } + + template + constexpr optional<_Tp> + make_optional(_Args&&... __args) + { return optional<_Tp> { in_place, std::forward<_Args>(__args)... }; } + + template + constexpr optional<_Tp> + make_optional(initializer_list<_Up> __il, _Args&&... __args) + { return optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; } + + + /// @} + +#if __cpp_deduction_guides >= 201606 + template optional(_Tp) -> optional<_Tp>; +#endif +} // namespace pmr + // Swap and creation functions. + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2748. swappable traits for optionals + template + inline enable_if_t && is_swappable_v<_Tp>> + swap(pmr::optional<_Tp>& __lhs, pmr::optional<_Tp>& __rhs) + noexcept(noexcept(__lhs.swap(__rhs))) + { __lhs.swap(__rhs); } + + template + enable_if_t && is_swappable_v<_Tp>)> + swap(pmr::optional<_Tp>&, pmr::optional<_Tp>&) = delete; + + // Hash. + template, + bool = __poison_hash<_Up>::__enable_hash_call> + struct __pmr_optional_hash_call_base + { + size_t + operator()(const pmr::optional<_Tp>& __t) const + noexcept(noexcept(hash<_Up>{}(*__t))) + { + // We pick an arbitrary hash for disengaged optionals which hopefully + // usual values of _Tp won't typically hash to. + constexpr size_t __magic_disengaged_hash = static_cast(-3333); + return __t ? hash<_Up>{}(*__t) : __magic_disengaged_hash; + } + }; + + template + struct __pmr_optional_hash_call_base<_Tp, _Up, false> {}; + + template + struct hash> + : private __poison_hash>, + public __pmr_optional_hash_call_base<_Tp> + { + using result_type [[__deprecated__]] = size_t; + using argument_type [[__deprecated__]] = pmr::optional<_Tp>; + }; + + template + struct __is_fast_hash>> : __is_fast_hash> + { }; + + template + struct uses_allocator, _Alloc> : true_type {}; +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++17 + +#endif // _GLIBCXX_OPTIONAL diff --git a/groups/bdl/bdldfp/bdldfp_decimal.t.cpp b/groups/bdl/bdldfp/bdldfp_decimal.t.cpp index 3aa681a34c..2ef3b00083 100644 --- a/groups/bdl/bdldfp/bdldfp_decimal.t.cpp +++ b/groups/bdl/bdldfp/bdldfp_decimal.t.cpp @@ -20,6 +20,7 @@ #include #include // CHAR_BIT #include +#include #include diff --git a/groups/bsl/bslma/bslma_allocator.h b/groups/bsl/bslma/bslma_allocator.h index 80dd77958f..efef6f70b8 100644 --- a/groups/bsl/bslma/bslma_allocator.h +++ b/groups/bsl/bslma/bslma_allocator.h @@ -420,6 +420,8 @@ BSLS_IDENT("$Id: $") #define INCLUDED_CSTDDEF #endif +#include + namespace BloombergLP { namespace bslma { @@ -428,7 +430,7 @@ namespace bslma { // class Allocator // =============== -class Allocator { +class Allocator : public std::pmr::memory_resource { // This protocol class provides a pure abstract interface and contract for // clients and suppliers of raw memory. If the requested memory cannot be // returned, the contract requires that an 'std::bad_alloc' exception be @@ -450,6 +452,10 @@ class Allocator { // allocator while memory is allocated from it is not specified. // (Unless you *know* that it is valid to do so, don't!) + void* do_allocate(std::size_t size, std::size_t /*alignment*/) override + { + return allocate(size); + } // MANIPULATORS virtual void *allocate(size_type size) = 0; // Return a newly allocated block of memory of (at least) the specified @@ -462,6 +468,14 @@ class Allocator { // conforms to the platform requirement for any object of the specified // 'size'. + void do_deallocate(void* address, std::size_t /*size*/, std::size_t /*alignment */) override + { + return deallocate(address); + } + bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override + { + return this == &other; + } virtual void deallocate(void *address) = 0; // Return the memory block at the specified 'address' back to this // allocator. If 'address' is 0, this function has no effect. The diff --git a/groups/bsl/bslma/bslma_default.cpp b/groups/bsl/bslma/bslma_default.cpp index 53bb8bb445..95575e716d 100644 --- a/groups/bsl/bslma/bslma_default.cpp +++ b/groups/bsl/bslma/bslma_default.cpp @@ -1,4 +1,5 @@ // bslma_default.cpp -*-C++-*- +#include #include #include @@ -38,9 +39,9 @@ int Default::setDefaultAllocator(Allocator *basicAllocator) if (!bsls::AtomicOperations::getIntRelaxed(&s_locked)) { bsls::AtomicOperations::setPtrRelease(&s_allocator, basicAllocator); + std::pmr::set_default_resource(basicAllocator); return 0; // success // RETURN } - return -1; // locked -- 'set' fails } @@ -49,6 +50,7 @@ void Default::setDefaultAllocatorRaw(Allocator *basicAllocator) BSLS_ASSERT(0 != basicAllocator); bsls::AtomicOperations::setPtrRelease(&s_allocator, basicAllocator); + std::pmr::set_default_resource(basicAllocator); } // *** global allocator *** diff --git a/groups/bsl/bslma/bslma_stdallocator.h b/groups/bsl/bslma/bslma_stdallocator.h index 11974c6304..69a7f9b2c3 100644 --- a/groups/bsl/bslma/bslma_stdallocator.h +++ b/groups/bsl/bslma/bslma_stdallocator.h @@ -430,6 +430,8 @@ BSL_OVERRIDES_STD mode" #define INCLUDED_CSTDDEF #endif +#include + namespace bsl { template struct allocator_traits; @@ -822,6 +824,14 @@ class allocator { // Return a pointer to the mechanism object to which this proxy // forwards allocation and deallocation calls. + operator std::pmr::memory_resource*() const + { + return d_mechanism; + } + + template + allocator(const std::pmr::polymorphic_allocator other) + : allocator(static_cast(other.resource())) { } allocator select_on_container_copy_construction() const; // TBD: add comment }; @@ -899,6 +909,15 @@ class allocator { // Return a pointer to the mechanism object to which this proxy // forwards allocation and deallocation calls. + operator std::pmr::memory_resource*() const + { + return d_mechanism; + } + template + allocator(const std::pmr::polymorphic_allocator other) + : allocator(static_cast(other.resource())) { } + + allocator select_on_container_copy_construction() const; // TBD: add comment }; diff --git a/groups/bsl/bsls/bsls_exceptionutil.h b/groups/bsl/bsls/bsls_exceptionutil.h index 381a3f97d6..b486548f8b 100644 --- a/groups/bsl/bsls/bsls_exceptionutil.h +++ b/groups/bsl/bsls/bsls_exceptionutil.h @@ -256,7 +256,7 @@ BSLS_IDENT("$Id: $") // Exceptions enabled: 'throw' // Exceptions disabled: abort with a message -# define BSLS_EXCEPTION_SPEC(SPEC) throw SPEC +# define BSLS_EXCEPTION_SPEC(SPEC) // Declare the exception specification for a function. // Usage: //.. diff --git a/groups/bsl/bslstl/bslstl_vector.h b/groups/bsl/bslstl/bslstl_vector.h index a7dbcf17e4..fa1f630dfc 100644 --- a/groups/bsl/bslstl/bslstl_vector.h +++ b/groups/bsl/bslstl/bslstl_vector.h @@ -6233,6 +6233,26 @@ void swap(vector& a, pa->swap(*pb); } + template struct is_bsl_allocator : std::false_type {}; + template struct is_bsl_allocator> + : std::true_type {}; + + template struct StandardizeAlloc + { + using type = typename std::conditional< + is_bsl_allocator::value + && (std::uses_allocator>::value + || !BloombergLP::bslma::UsesBslmaAllocator::value), + std::pmr::polymorphic_allocator, + ALLOC + >::type; + }; + + template > + using stdvector = + std::vector::type>; + } // close namespace bsl // ============================================================================ From fc556320e12c7a24ef355c27ed20fbef2dd013c1 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Thu, 18 Apr 2019 15:09:55 +0300 Subject: [PATCH 02/14] Fix test failures --- groups/bdl/bdlb/bdlb_nullablevalue.t.cpp | 4 ++++ groups/bdl/bdlb/pmroptional | 17 ++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp b/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp index 03c685902e..15cf2c94c2 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp +++ b/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp @@ -57,6 +57,10 @@ struct uses_allocator : true_type {}; template struct uses_allocator : true_type {}; template +struct uses_allocator : true_type {}; + template +struct uses_allocator : true_type {}; + template struct uses_allocator : true_type {}; } diff --git a/groups/bdl/bdlb/pmroptional b/groups/bdl/bdlb/pmroptional index cd66ce9bcc..2ee81ae419 100644 --- a/groups/bdl/bdlb/pmroptional +++ b/groups/bdl/bdlb/pmroptional @@ -374,7 +374,7 @@ namespace pmr { _Optional_payload(__ctor_tag{}, __other._M_payload) : _Optional_payload(__ctor_tag{})) - { } + { _M_pmr = __other._M_pmr; } constexpr _Optional_payload(bool __engaged, _Optional_payload&& __other) @@ -382,7 +382,7 @@ namespace pmr { ? _Optional_payload(__ctor_tag{}, std::move(__other._M_payload)) : _Optional_payload(__ctor_tag{})) - { } + { _M_pmr = __other._M_pmr; } _Optional_payload(const _Optional_payload&) = default; _Optional_payload(_Optional_payload&&) = default; @@ -528,7 +528,7 @@ namespace pmr { _Optional_payload(__ctor_tag{}, __other._M_payload) : _Optional_payload(__ctor_tag{})) - { } + { _M_pmr = __other._M_pmr; } constexpr _Optional_payload(bool __engaged, _Optional_payload&& __other) @@ -536,7 +536,7 @@ namespace pmr { ? _Optional_payload(__ctor_tag{}, std::move(__other._M_payload)) : _Optional_payload(__ctor_tag{})) - { } + { _M_pmr = __other._M_pmr; } _Optional_payload(const _Optional_payload&) = default; _Optional_payload(_Optional_payload&&) = default; @@ -683,7 +683,7 @@ namespace pmr { _Optional_payload(__ctor_tag{}, __other._M_payload) : _Optional_payload(__ctor_tag{})) - { } + { _M_pmr = __other._M_pmr; } constexpr _Optional_payload(bool __engaged, _Optional_payload&& __other) @@ -691,7 +691,7 @@ namespace pmr { ? _Optional_payload(__ctor_tag{}, std::move(__other._M_payload)) : _Optional_payload(__ctor_tag{})) - { } + { _M_pmr = __other._M_pmr; } _Optional_payload(const _Optional_payload&) = default; _Optional_payload(_Optional_payload&&) = default; @@ -1226,7 +1226,10 @@ namespace pmr { */ using value_type = _Tp; - constexpr optional() = default; + constexpr optional() + { + this->_M_set_allocator(std::pmr::get_default_resource()); + } constexpr optional(nullopt_t) noexcept { } From ebdafbdd2ad0bbf3e95b1c6a5a9677aad79a92ed Mon Sep 17 00:00:00 2001 From: nina Queen of Awesome Date: Mon, 24 Jun 2019 11:04:40 +0100 Subject: [PATCH 03/14] making tests pass --- groups/bdl/bdldfp/bdldfp_decimal.t.cpp | 2 ++ groups/bdl/bdls/bdls_testutil.t.cpp | 31 ++++++++++++++------------ groups/bsl/bslim/bslim_testutil.t.cpp | 4 ++-- groups/bsl/bsls/bsls_exceptionutil.h | 3 ++- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/groups/bdl/bdldfp/bdldfp_decimal.t.cpp b/groups/bdl/bdldfp/bdldfp_decimal.t.cpp index 3aa681a34c..06ac287419 100644 --- a/groups/bdl/bdldfp/bdldfp_decimal.t.cpp +++ b/groups/bdl/bdldfp/bdldfp_decimal.t.cpp @@ -21,6 +21,8 @@ #include // CHAR_BIT #include +#include + #include using namespace BloombergLP; diff --git a/groups/bdl/bdls/bdls_testutil.t.cpp b/groups/bdl/bdls/bdls_testutil.t.cpp index 2e6abce0ba..b58d13d606 100644 --- a/groups/bdl/bdls/bdls_testutil.t.cpp +++ b/groups/bdl/bdls/bdls_testutil.t.cpp @@ -121,6 +121,9 @@ using namespace BloombergLP::bsltf; static int realTestStatus = 0; +//offset between the line number in expected vs actual output +static int lineOffset = 1; + static void realaSsErT(bool b, const char *s, int i) { if (b) { @@ -761,8 +764,8 @@ int OutputRedirector::compare(const char *expected, size_t expectedLength) // Use 'memcmp' instead of 'strncmp' to compare 'd_outputBuffer' to // 'expected', because 'expected' is allowed to contain embedded nulls. - return d_outputSize != static_cast(expectedLength) || - memcmp(d_outputBuffer, expected, expectedLength); + return (d_outputSize != static_cast(expectedLength)) || + memcmp(d_outputBuffer, expected, expectedLength); } const struct stat& OutputRedirector::originalStdoutStat() @@ -1045,7 +1048,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 1; + const int LINE = __LINE__ + lineOffset; BDLS_TESTUTIL_LOOP_ASSERT(I, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1073,7 +1076,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 1; + const int LINE = __LINE__ + lineOffset; BDLS_TESTUTIL_ASSERTV(I, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1122,7 +1125,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 1; + const int LINE = __LINE__ + lineOffset; BDLS_TESTUTIL_LOOP2_ASSERT(I, J, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1151,7 +1154,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 1; + const int LINE = __LINE__ + lineOffset; BDLS_TESTUTIL_ASSERTV(I, J, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1202,7 +1205,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 1; + const int LINE = __LINE__ + lineOffset; BDLS_TESTUTIL_LOOP3_ASSERT(I, J, K, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1232,7 +1235,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 1; + const int LINE = __LINE__ + lineOffset; BDLS_TESTUTIL_ASSERTV(I, J, K, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1285,7 +1288,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 1; + const int LINE = __LINE__ + lineOffset; BDLS_TESTUTIL_LOOP4_ASSERT(I, J, K, L, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1317,7 +1320,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 1; + const int LINE = __LINE__ + lineOffset; BDLS_TESTUTIL_ASSERTV(I, J, K, L, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1373,7 +1376,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 2; + const int LINE = __LINE__ + lineOffset; BDLS_TESTUTIL_LOOP5_ASSERT(I, J, K, L, M, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, @@ -1417,7 +1420,7 @@ int main(int argc, char *argv[]) // here, we make sure that the call to 'BDLS_TESTUTIL_ASSERTV' // fit on a single line to make sure that the output is the // same on all platforms. - const int LINE = __LINE__ + 1; + const int LINE = __LINE__ + lineOffset; BDLS_TESTUTIL_ASSERTV(I, J, K, L, M, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1476,7 +1479,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 2; + const int LINE = __LINE__ + lineOffset; BDLS_TESTUTIL_LOOP6_ASSERT(I, J, K, L, M, N, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, @@ -1511,7 +1514,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 1; + const int LINE = __LINE__ + lineOffset; BDLS_TESTUTIL_ASSERTV(I, J, K, L, M, N, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); diff --git a/groups/bsl/bslim/bslim_testutil.t.cpp b/groups/bsl/bslim/bslim_testutil.t.cpp index af9530f51f..a6a1382512 100644 --- a/groups/bsl/bslim/bslim_testutil.t.cpp +++ b/groups/bsl/bslim/bslim_testutil.t.cpp @@ -1818,7 +1818,7 @@ int main(int argc, char *argv[]) if (veryVerbose) { REALP(idx); } output.reset(); - const int LINE = __LINE__ + 2; + const int LINE = __LINE__ + 1; BSLIM_TESTUTIL_LOOP5_ASSERT(I, J, K, L, M, idx > NUM_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1914,7 +1914,7 @@ int main(int argc, char *argv[]) if (veryVerbose) { REALP(idx); } output.reset(); - const int LINE = __LINE__ + 2; + const int LINE = __LINE__ + 1; BSLIM_TESTUTIL_LOOP6_ASSERT(I, J, K, L, M, N, idx > NUM_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); diff --git a/groups/bsl/bsls/bsls_exceptionutil.h b/groups/bsl/bsls/bsls_exceptionutil.h index 381a3f97d6..0796b2319f 100644 --- a/groups/bsl/bsls/bsls_exceptionutil.h +++ b/groups/bsl/bsls/bsls_exceptionutil.h @@ -256,7 +256,8 @@ BSLS_IDENT("$Id: $") // Exceptions enabled: 'throw' // Exceptions disabled: abort with a message -# define BSLS_EXCEPTION_SPEC(SPEC) throw SPEC +//# define BSLS_EXCEPTION_SPEC(SPEC) throw SPEC +#define BSLS_EXCEPTION_SPEC(SPEC) // Declare the exception specification for a function. // Usage: //.. From 34c2cc65d5964e7751baa884b47f1c6bd37d80bd Mon Sep 17 00:00:00 2001 From: nina Queen of Awesome Date: Wed, 26 Jun 2019 15:30:21 +0100 Subject: [PATCH 04/14] clean up test changes --- groups/bdl/bdldfp/bdldfp_decimal.t.cpp | 2 -- groups/bdl/bdls/bdls_testutil.t.cpp | 35 ++++++++++++-------------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/groups/bdl/bdldfp/bdldfp_decimal.t.cpp b/groups/bdl/bdldfp/bdldfp_decimal.t.cpp index c57d695002..2ef3b00083 100644 --- a/groups/bdl/bdldfp/bdldfp_decimal.t.cpp +++ b/groups/bdl/bdldfp/bdldfp_decimal.t.cpp @@ -22,8 +22,6 @@ #include #include -#include - #include using namespace BloombergLP; diff --git a/groups/bdl/bdls/bdls_testutil.t.cpp b/groups/bdl/bdls/bdls_testutil.t.cpp index b58d13d606..e20767e356 100644 --- a/groups/bdl/bdls/bdls_testutil.t.cpp +++ b/groups/bdl/bdls/bdls_testutil.t.cpp @@ -121,9 +121,6 @@ using namespace BloombergLP::bsltf; static int realTestStatus = 0; -//offset between the line number in expected vs actual output -static int lineOffset = 1; - static void realaSsErT(bool b, const char *s, int i) { if (b) { @@ -764,8 +761,8 @@ int OutputRedirector::compare(const char *expected, size_t expectedLength) // Use 'memcmp' instead of 'strncmp' to compare 'd_outputBuffer' to // 'expected', because 'expected' is allowed to contain embedded nulls. - return (d_outputSize != static_cast(expectedLength)) || - memcmp(d_outputBuffer, expected, expectedLength); + return d_outputSize != static_cast(expectedLength) || + memcmp(d_outputBuffer, expected, expectedLength); } const struct stat& OutputRedirector::originalStdoutStat() @@ -1048,7 +1045,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + lineOffset; + const int LINE = __LINE__ + 1; BDLS_TESTUTIL_LOOP_ASSERT(I, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1076,7 +1073,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + lineOffset; + const int LINE = __LINE__ + 1; BDLS_TESTUTIL_ASSERTV(I, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1125,7 +1122,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + lineOffset; + const int LINE = __LINE__ + 1; BDLS_TESTUTIL_LOOP2_ASSERT(I, J, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1154,7 +1151,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + lineOffset; + const int LINE = __LINE__ + 1; BDLS_TESTUTIL_ASSERTV(I, J, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1205,7 +1202,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + lineOffset; + const int LINE = __LINE__ + 1; BDLS_TESTUTIL_LOOP3_ASSERT(I, J, K, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1235,7 +1232,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + lineOffset; + const int LINE = __LINE__ + 1; BDLS_TESTUTIL_ASSERTV(I, J, K, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1288,7 +1285,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + lineOffset; + const int LINE = __LINE__ + 1; BDLS_TESTUTIL_LOOP4_ASSERT(I, J, K, L, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1320,7 +1317,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + lineOffset; + const int LINE = __LINE__ + 1; BDLS_TESTUTIL_ASSERTV(I, J, K, L, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1376,8 +1373,8 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + lineOffset; - BDLS_TESTUTIL_LOOP5_ASSERT(I, J, K, L, M, + const int LINE = __LINE__ + 1; + BDLS_TESTUTIL_LOOP5_ASSERT(I, J, K, L, M, \ idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1420,7 +1417,7 @@ int main(int argc, char *argv[]) // here, we make sure that the call to 'BDLS_TESTUTIL_ASSERTV' // fit on a single line to make sure that the output is the // same on all platforms. - const int LINE = __LINE__ + lineOffset; + const int LINE = __LINE__ + 1; BDLS_TESTUTIL_ASSERTV(I, J, K, L, M, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1479,8 +1476,8 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + lineOffset; - BDLS_TESTUTIL_LOOP6_ASSERT(I, J, K, L, M, N, + const int LINE = __LINE__ + 1; + BDLS_TESTUTIL_LOOP6_ASSERT(I, J, K, L, M, N, \ idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1514,7 +1511,7 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + lineOffset; + const int LINE = __LINE__ + 1; BDLS_TESTUTIL_ASSERTV(I, J, K, L, M, N, idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); From 28e6b112cca93fe5640849baa1139ac316a0a913 Mon Sep 17 00:00:00 2001 From: nina Queen of Awesome Date: Wed, 26 Jun 2019 15:48:13 +0100 Subject: [PATCH 05/14] first version of NullableValue inheriting from std::pmr::optional --- groups/bdl/bdlb/bdlb_nullablevalue.h | 872 ++++++++++++++++++++++++--- groups/bdl/bdlb/pmroptional | 62 +- 2 files changed, 777 insertions(+), 157 deletions(-) diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.h b/groups/bdl/bdlb/bdlb_nullablevalue.h index f196d7cdfe..1be75b65bb 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.h +++ b/groups/bdl/bdlb/bdlb_nullablevalue.h @@ -186,124 +186,783 @@ namespace bslma { } } -namespace std { -namespace pmr { - template - int optional<_Tp>::maxSupportedBdexVersion(int versionSelector) const - { - using BloombergLP::bslx::VersionFunctions::maxSupportedBdexVersion; + +namespace BloombergLP { +namespace bdlb { + +template +class NullableValue_WithAllocator; + +template +class NullableValue_WithoutAllocator; + + +// ========================= +// class NullableValue +// ========================= + + +template +class NullableValue : public std::pmr::optional +{ + + // This template class extends the set of values of its value-semantic + // 'TYPE' parameter to include the notion of a "null" value. If 'TYPE' is + // fully value-semantic, then the augmented type 'Nullable' will be + // as well. In addition to supporting all homogeneous value-semantic + // operations, conversions between comparable underlying value types is + // also supported. Two nullable objects with different underlying types + // compare equal if their underlying types are comparable and either (1) + // both objects are null or (2) the non-null values compare equal. A null + // nullable object is considered ordered before any non-null nullable + // object. Attempts to copy construct, copy assign, or compare + // incompatible values types will fail to compile. The 'NullableValue' + // template cannot be instantiated on an incomplete type or on a type that + // overloads 'operator&'. + + // PRIVATE TYPES + typedef bslmf::MovableRefUtil MoveUtil; + +public: + // TYPES + typedef TYPE ValueType; + // 'ValueType' is an alias for the underlying 'TYPE' upon which this + // template class is instantiated, and represents the type of the + // managed object. + + + + // TRAITS + BSLMF_NESTED_TRAIT_DECLARATION_IF(NullableValue, + bslma::UsesBslmaAllocator, + bslma::UsesBslmaAllocator::value); + BSLMF_NESTED_TRAIT_DECLARATION_IF(NullableValue, + bsl::is_trivially_copyable, + bsl::is_trivially_copyable::value); + BSLMF_NESTED_TRAIT_DECLARATION_IF(NullableValue, + bslmf::IsBitwiseMoveable, + bslmf::IsBitwiseMoveable::value); + BSLMF_NESTED_TRAIT_DECLARATION(NullableValue, bdlb::HasPrintMethod); + // 'UsesBslmaAllocator', 'IsBitwiseCopyable', and 'IsBitwiseMoveable' + // are true for 'NullableValue' only if the corresponding trait is true + // for 'TYPE'. 'HasPrintMethod' is always true for 'NullableValue'. + + // CREATORS + using std::pmr::optional::optional; + + constexpr NullableValue(const NullableValue&) = default; + constexpr NullableValue(NullableValue&&) = default; + + // MANIPULATORS + NullableValue& operator=(const NullableValue& rhs); + // Assign to this object the value of the specified 'rhs', and return a + // reference providing modifiable access to this object. + + NullableValue& operator=(bslmf::MovableRef rhs); + // Assign to this object the value of the specified 'rhs', and return a + // reference providing modifiable access to this object. The contents + // of 'rhs' are either move-inserted into or move-assigned to this + // object. 'rhs' is left in a valid but unspecified state. + + template + NullableValue& operator=(const NullableValue& rhs); + // Assign to this object the null value if the specified 'rhs' object + // is null, and the value of 'rhs.value()' (of 'BDE_OTHER_TYPE') + // converted to 'TYPE' otherwise. Return a reference providing + // modifiable access to this object. Note that this method will fail + // to compile if 'TYPE and 'BDE_OTHER_TYPE' are not compatible. + + NullableValue& operator=(const TYPE& rhs); + // Assign to this object the value of the specified 'rhs', and return a + // reference providing modifiable access to this object. + + NullableValue& operator=(bslmf::MovableRef rhs); + // Assign to this object the value of the specified 'rhs', and return a + // reference providing modifiable access to this object. The contents + // of 'rhs' are either move-inserted into or move-assigned to this + // object. 'rhs' is left in a valid but unspecified state. + + template + NullableValue& operator=(const BDE_OTHER_TYPE& rhs); + // Assign to this object the value of the specified 'rhs' object (of + // 'BDE_OTHER_TYPE') converted to 'TYPE', and return a reference + // providing modifiable access to this object. Note that this method + // will fail to compile if 'TYPE and 'BDE_OTHER_TYPE' are not + // compatible. + + + template + TYPE& makeValue(BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value); + // Assign to this object the specified 'value' (of 'BDE_OTHER_TYPE') + // converted to 'TYPE', and return a reference providing modifiable + // access to the underlying 'TYPE' object. Note that this method will + // fail to compile if 'TYPE and 'BDE_OTHER_TYPE' are not compatible. + + TYPE& makeValue(); + // Assign to this object the default value for 'TYPE', and return a + // reference providing modifiable access to the underlying 'TYPE' + // object. + + template + STREAM& bdexStreamIn(STREAM& stream, int version); + // Assign to this object the value read from the specified input + // 'stream' using the specified 'version' format, and return a + // reference to 'stream'. If 'stream' is initially invalid, this + // operation has no effect. If 'version' is not supported, this object + // is unaltered and 'stream' is invalidated, but otherwise unmodified. + // If 'version' is supported but 'stream' becomes invalid during this + // operation, this object has an undefined, but valid, state. Note + // that no version is read from 'stream'. See the 'bslx' package-level + // documentation for more information on BDEX streaming of + // value-semantic types and containers. + + //void reset(); + // Reset this object to the default constructed state (i.e., to have + // the null value). + // Provided by std::pmr::optional base class. + + //TYPE& value(); + // Return a reference providing modifiable access to the underlying + // 'TYPE' object. The behavior is undefined unless this object is + // non-null. + // Provided by std::pmr::optional base class. + + +// ACCESSORS + template + STREAM& bdexStreamOut(STREAM& stream, int version) const; + // Write the value of this object, using the specified 'version' + // format, to the specified output 'stream', and return a reference to + // 'stream'. If 'stream' is initially invalid, this operation has no + // effect. If 'version' is not supported, 'stream' is invalidated, but + // otherwise unmodified. Note that 'version' is not written to + // 'stream'. See the 'bslx' package-level documentation for more + // information on BDEX streaming of value-semantic types and + // containers. + + bool isNull() const; + // Return 'true' if this object is null, and 'false' otherwise. + + int maxSupportedBdexVersion(int versionSelector) const; + // Return the maximum valid BDEX format version, as indicated by the + // specified 'versionSelector', to be passed to the 'bdexStreamOut' + // method. Note that it is highly recommended that 'versionSelector' + // be formatted as "YYYYMMDD", a date representation. Also note that + // 'versionSelector' should be a *compile*-time-chosen value that + // selects a format version supported by both externalizer and + // unexternalizer. See the 'bslx' package-level documentation for more + // information on BDEX streaming of value-semantic types and + // containers. + + + bsl::ostream& print(bsl::ostream& stream, + int level = 0, + int spacesPerLevel = 4) const; + // Format this object to the specified output 'stream' at the (absolute + // value of) the optionally specified indentation 'level' and return a + // reference to 'stream'. If 'level' is specified, optionally specify + // 'spacesPerLevel', the number of spaces per indentation level for + // this and all of its nested objects. If 'level' is negative, + // suppress indentation of the first line. If 'spacesPerLevel' is + // negative, format the entire output on one line, suppressing all but + // the initial indentation (as governed by 'level'). If 'stream' is + // not valid on entry, this operation has no effect. + + //const TYPE& value() const; + // Return a reference providing non-modifiable access to the underlying + // object of a (template parameter) 'TYPE'. The behavior is undefined + // unless this object is non-null. + // provided by std::pmr::optional base class. + + TYPE valueOr(const TYPE& value) const; + // Return the value of the underlying object of a (template parameter) + // 'TYPE' if this object is non-null, and the specified 'value' + // otherwise. Note that this method returns *by* *value*, so may be + // inefficient in some contexts. + + #if BSLS_DEPRECATE_IS_ACTIVE(BDL, 3, 5) + BSLS_DEPRECATE + #endif + const TYPE *valueOr(const TYPE *value) const; + // !DEPRECATED!: Use 'addressOr' instead. + // + // Return an address providing non-modifiable access to the underlying + // object of a (template parameter) 'TYPE' if this object is non-null, + // and the specified 'value' otherwise. + + const TYPE *addressOr(const TYPE *address) const; + // Return an address providing non-modifiable access to the underlying + // object of a (template parameter) 'TYPE' if this object is non-null, + // and the specified 'address' otherwise. + + const TYPE *valueOrNull() const; + // Return an address providing non-modifiable access to the underlying + // object of a (template parameter) 'TYPE' if this object is non-null, + // and 0 otherwise. + +private: + constexpr explicit operator bool() const noexcept; + // base class is convertable to bool, but NullableValue shouldn't be. +}; +// FREE OPERATORS +template +bool operator==(const NullableValue& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' and 'rhs' nullable objects have the + // same value, and 'false' otherwise. Two nullable objects have the same + // value if both are null, or if both are non-null and the values of their + // underlying objects compare equal. Note that this function will fail to + // compile if 'LHS_TYPE' and 'RHS_TYPE' are not compatible. + +template +bool operator!=(const NullableValue& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' and 'rhs' nullable objects do not + // have the same value, and 'false' otherwise. Two nullable objects do not + // have the same value if one is null and the other is non-null, or if both + // are non-null and the values of their underlying objects do not compare + // equal. Note that this function will fail to compile if 'LHS_TYPE' and + // 'RHS_TYPE' are not compatible. + +template +bool operator==(const NullableValue& lhs, + const TYPE& rhs); +template +bool operator==(const TYPE& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' and 'rhs' objects have the same + // value, and 'false' otherwise. A nullable object and a value of the + // underlying 'TYPE' have the same value if the nullable object is non-null + // and its underlying value compares equal to the other value. + +template +bool operator!=(const NullableValue& lhs, + const TYPE& rhs); +template +bool operator!=(const TYPE& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' and 'rhs' objects do not have the + // same value, and 'false' otherwise. A nullable object and a value of the + // underlying 'TYPE' do not have the same value if either the nullable + // object is null, or its underlying value does not compare equal to the + // other value. + +// There is at least one instance of client code having already defined +// 'operator<' on 'bdlb::NullableValue' (see bde_extended.h in DPKG +// crm-integration). The following macro facilitates client migration to the +// comparison operators defined here. +#define BDLB_NULLABLEVALUE_SUPPORTS_LESS_THAN + +template +bool operator<(const NullableValue& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered before + // the specified 'rhs' nullable object, and 'false' otherwise. 'lhs' is + // ordered before 'rhs' if 'lhs' is null and 'rhs' is non-null or if both + // are non-null and 'lhs.value()' is ordered before 'rhs.value()'. Note + // that this function will fail to compile if 'LHS_TYPE' and 'RHS_TYPE' are + // not compatible. + +template +bool operator<(const NullableValue& lhs, + const TYPE& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered before + // the specified 'rhs', and 'false' otherwise. 'lhs' is ordered before + // 'rhs' if 'lhs' is null or 'lhs.value()' is ordered before 'rhs'. + +template +bool operator<(const TYPE& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' is ordered before the specified + // 'rhs' nullable object, and 'false' otherwise. 'lhs' is ordered before + // 'rhs' if 'rhs' is not null and 'lhs' is ordered before 'rhs.value()'. + +template +bool operator>(const NullableValue& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered after + // the specified 'rhs' nullable object, and 'false' otherwise. 'lhs' is + // ordered after 'rhs' if 'lhs' is non-null and 'rhs' is null or if both + // are non-null and 'lhs.value()' is ordered after 'rhs.value()'. Note + // that this operator returns 'rhs < lhs'. Also note that this function + // will fail to compile if 'LHS_TYPE' and 'RHS_TYPE' are not compatible. + +template +bool operator>(const NullableValue& lhs, + const TYPE& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered after + // the specified 'rhs', and 'false' otherwise. 'lhs' is ordered after + // 'rhs' if 'lhs' is not null and 'lhs.value()' is ordered after 'rhs'. + // Note that this operator returns 'rhs < lhs'. + +template +bool operator>(const TYPE& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' is ordered after the specified + // 'rhs' nullable object, and 'false' otherwise. 'lhs' is ordered after + // 'rhs' if 'rhs' is null or 'lhs' is ordered after 'rhs.value()'. Note + // that this operator returns 'rhs < lhs'. + + +template +bool operator<=(const NullableValue& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered before + // the specified 'rhs' nullable object or 'lhs' and 'rhs' have the same + // value, and 'false' otherwise. (See 'operator<' and 'operator=='.) Note + // that this operator returns '!(rhs < lhs)'. Also note that this function + // will fail to compile if 'LHS_TYPE' and 'RHS_TYPE' are not compatible. + +template +bool operator<=(const NullableValue& lhs, + const TYPE& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered before + // the specified 'rhs' or 'lhs' and 'rhs' have the same value, and 'false' + // otherwise. (See 'operator<' and 'operator=='.) Note that this operator + // returns '!(rhs < lhs)'. + +template +bool operator<=(const TYPE& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' is ordered before the specified + // 'rhs' nullable object or 'lhs' and 'rhs' have the same value, and + // 'false' otherwise. (See 'operator<' and 'operator=='.) Note that this + // operator returns '!(rhs < lhs)'. + +template +bool operator>=(const NullableValue& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered after + // the specified 'rhs' nullable object or 'lhs' and 'rhs' have the same + // value, and 'false' otherwise. (See 'operator>' and 'operator=='.) Note + // that this operator returns '!(lhs < rhs)'. Also note that this function + // will fail to compile if 'LHS_TYPE' and 'RHS_TYPE' are not compatible. + +template +bool operator>=(const NullableValue& lhs, + const TYPE& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered after + // the specified 'rhs' or 'lhs' and 'rhs' have the same value, and 'false' + // otherwise. (See 'operator>' and 'operator=='.) Note that this operator + // returns '!(lhs < rhs)'. + +template +bool operator>=(const TYPE& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' is ordered after the specified + // 'rhs' nullable object or 'lhs' and 'rhs' have the same value, and + // 'false' otherwise. (See 'operator>' and 'operator=='.) Note that this + // operator returns '!(lhs < rhs)'. + +template +bsl::ostream& operator<<(bsl::ostream& stream, + const NullableValue& object); + // Write the value of the specified 'object' to the specified output + // 'stream' in a single-line format, and return a reference to 'stream'. + // If 'stream' is not valid on entry, this operation has no effect. Note + // that this human-readable format is not fully specified, can change + // without notice, and is logically equivalent to: + //.. + // print(stream, 0, -1); + //.. + +// FREE FUNCTIONS +template +void hashAppend(HASHALG& hashAlg, const NullableValue& input); + // Pass the boolean value of whether the specified 'input' contains a value + // to the specified 'hashAlg' hashing algorithm of (template parameter) + // type 'HASHALG'. If 'input' contains a value, additionally pass that + // value to 'hashAlg'. + +template +void swap(NullableValue& a, NullableValue& b); + // Efficiently exchange the values of the specified 'a' and 'b' objects. + // This method provides the no-throw exception-safety guarantee if the + // template parameter 'TYPE' provides that guarantee and the result of the + // 'isNull' method for 'a' and 'b' is the same. The behavior is undefined + // unless both objects were created with the same allocator, if any. + + + +template +template +STREAM& NullableValue::bdexStreamIn(STREAM& stream, int version) +{ + using bslx::InStreamFunctions::bdexStreamIn; + + char isNull = 0; // Redundant initialization to suppress -Werror. + + stream.getInt8(isNull); + + if (stream) { + if (!isNull) { + this->makeValue(); + + bdexStreamIn(stream, this->value(), version); + } + else { + this->reset(); + } + } + + return stream; +} + +// ACCESSORS +template +template +STREAM& NullableValue::bdexStreamOut(STREAM& stream, int version) const +{ + using bslx::OutStreamFunctions::bdexStreamOut; + + const bool isNull = this->isNull(); + + stream.putInt8(isNull ? 1 : 0); + + if (!isNull) { + bdexStreamOut(stream, this->value(), version); + } + + return stream; +} + +template +inline +bool NullableValue::isNull() const +{ + return !this->has_value(); +} + +template +inline +int NullableValue::maxSupportedBdexVersion(int versionSelector) const +{ + using bslx::VersionFunctions::maxSupportedBdexVersion; // We need to call the 'bslx::VersionFunctions' helper function, because we // cannot guarantee that 'TYPE' implements 'maxSupportedBdexVersion' as a // class method. - - return maxSupportedBdexVersion(reinterpret_cast<_Tp *>(0), + + return maxSupportedBdexVersion(reinterpret_cast(0), versionSelector); - } +} + + +template +bsl::ostream& NullableValue::print(bsl::ostream& stream, + int level, + int spacesPerLevel) const +{ + if (this->isNull()) { + return bdlb::PrintMethods::print(stream, + "NULL", + level, + spacesPerLevel); // RETURN + } + + return bdlb::PrintMethods::print(stream, + this->value(), + level, + spacesPerLevel); +} +// MANIPULATORS +template +inline +NullableValue& NullableValue::operator=(const NullableValue& rhs) +{ + std::pmr::optional::operator=(rhs); + return *this; +} + +template +inline +NullableValue& +NullableValue::operator=(bslmf::MovableRef rhs) +{ + std::pmr::optional& rhs_base = rhs; + std::pmr::optional::operator=(MoveUtil::move(rhs_base)); + return *this; +} + +template +template +NullableValue& NullableValue::operator=( + const NullableValue& rhs) +{ + const std::pmr::optional& rhs_base = rhs; + if (rhs.isNull()) { + this->reset(); + } + else { + this->makeValue(rhs_base.value()); + } + return *this; +} + +template +inline +NullableValue& NullableValue::operator=(const TYPE& rhs) +{ + this->makeValue(rhs); + + return *this; +} + +template +inline +NullableValue& +NullableValue::operator=(bslmf::MovableRef rhs) +{ + this->makeValue(MoveUtil::move(rhs)); + + return *this; +} + +template +template +inline +NullableValue& NullableValue::operator=(const BDE_OTHER_TYPE& rhs) +{ + this->makeValue(rhs); + + return *this; +} + +template +template +inline +TYPE& NullableValue::makeValue( + BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value) +{ + this->emplace(BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)); + return *(*this); +} - template - template - STREAM& optional::bdexStreamIn(STREAM& stream, int version) - { - using BloombergLP::bslx::InStreamFunctions::bdexStreamIn; +template +inline +TYPE& NullableValue::makeValue() +{ + this->emplace(); + return *(*this); +} - char isNull = 0; // Redundant initialization to suppress -Werror. +template +inline +const TYPE *NullableValue::valueOrNull() const +{ + return this->isNull() ? 0 : &this->value(); +} - stream.getInt8(isNull); +template +inline +TYPE NullableValue::valueOr(const TYPE& value) const +{ + return this->isNull() ? value : this->value(); +} - if (stream) { - if (!isNull) { - this->makeValue(); +template +inline +const TYPE *NullableValue::valueOr(const TYPE *value) const +{ + return this->isNull() ? value : &this->value(); +} - bdexStreamIn(stream, this->value(), version); - } - else { - this->reset(); - } - } +template +inline +const TYPE *NullableValue::addressOr(const TYPE *value) const +{ + return this->isNull() ? value : &this->value(); +} - return stream; - } - - template - template - STREAM& optional::bdexStreamOut(STREAM& stream, int version) const - { - using BloombergLP::bslx::OutStreamFunctions::bdexStreamOut; - - const bool isNull = this->isNull(); - - stream.putInt8(isNull ? 1 : 0); - - if (!isNull) { - bdexStreamOut(stream, this->value(), version); - } - - return stream; - } - - template - bsl::ostream& operator<<(bsl::ostream& stream, - const optional& object) - { - if (object.isNull()) { - return BloombergLP::bdlb::PrintMethods::print(stream, - "NULL", - 0, - -1); // RETURN - } - - return BloombergLP::bdlb::PrintMethods::print(stream, - object.value(), - 0, - -1); - } - - template - template - auto& optional::print(STREAM& stream, int level, - int spacesPerLevel) const - { - if (this->isNull()) { - return (bsl::ostream&)BloombergLP::bdlb::PrintMethods::print(stream, - "NULL", - 0, - -1); // RETURN + +} // close package namespace + +// FREE OPERATORS +template +inline +bool bdlb::operator==(const NullableValue& lhs, + const NullableValue& rhs) +{ + if (!lhs.isNull() && !rhs.isNull()) { + return lhs.value() == rhs.value(); // RETURN } - - return (bsl::ostream&)BloombergLP::bdlb::PrintMethods::print(stream, - this->value(), - 0, - -1); - } - - template - void hashAppend(HASHALG& hashAlg, const optional& input) - { - using namespace BloombergLP; - if (!input.isNull()) { - hashAppend(hashAlg, true); - hashAppend(hashAlg, input.value()); + + return lhs.isNull() == rhs.isNull(); +} + +template +inline +bool bdlb::operator==(const NullableValue& lhs, + const TYPE& rhs) +{ + return !lhs.isNull() && lhs.value() == rhs; +} + +template +inline +bool bdlb::operator==(const TYPE& lhs, + const NullableValue& rhs) +{ + return !rhs.isNull() && rhs.value() == lhs; +} + +template +inline +bool bdlb::operator!=(const NullableValue& lhs, + const NullableValue& rhs) +{ + if (!lhs.isNull() && !rhs.isNull()) { + return lhs.value() != rhs.value(); // RETURN } - else { - hashAppend(hashAlg, false); + + return lhs.isNull() != rhs.isNull(); +} + +template +inline +bool bdlb::operator!=(const NullableValue& lhs, + const TYPE& rhs) +{ + return lhs.isNull() || lhs.value() != rhs; +} + +template +inline +bool bdlb::operator!=(const TYPE& lhs, + const NullableValue& rhs) +{ + return rhs.isNull() || rhs.value() != lhs; +} + +template +inline +bool bdlb::operator<(const NullableValue& lhs, + const NullableValue& rhs) +{ + if (rhs.isNull()) { + return false; // RETURN } - } + + return lhs.isNull() || lhs.value() < rhs.value(); } + +template +inline +bool bdlb::operator<(const NullableValue& lhs, + const TYPE& rhs) +{ + return lhs.isNull() || lhs.value() < rhs; } -namespace BloombergLP { -namespace bdlb { template -using NullableValue = std::pmr::optional; +inline +bool bdlb::operator<(const TYPE& lhs, + const NullableValue& rhs) +{ + return !rhs.isNull() && lhs < rhs.value(); +} + +template +inline +bool bdlb::operator>(const NullableValue& lhs, + const NullableValue& rhs) +{ + return rhs < lhs; +} template -class NullableValue_WithAllocator; +inline +bool bdlb::operator>(const NullableValue& lhs, + const TYPE& rhs) +{ + return rhs < lhs; +} template -class NullableValue_WithoutAllocator; +inline +bool bdlb::operator>(const TYPE& lhs, + const NullableValue& rhs) +{ + return rhs < lhs; +} + +template +inline +bool bdlb::operator<=(const NullableValue& lhs, + const NullableValue& rhs) +{ + return !(rhs < lhs); +} + +template +inline +bool bdlb::operator<=(const NullableValue& lhs, + const TYPE& rhs) +{ + return !(rhs < lhs); +} + +template +inline +bool bdlb::operator<=(const TYPE& lhs, + const NullableValue& rhs) +{ + return !(rhs < lhs); +} + +template +inline +bool bdlb::operator>=(const NullableValue& lhs, + const NullableValue& rhs) +{ + return !(lhs < rhs); +} + +template +inline +bool bdlb::operator>=(const NullableValue& lhs, + const TYPE& rhs) +{ + return !(lhs < rhs); +} + +template +inline +bool bdlb::operator>=(const TYPE& lhs, + const NullableValue& rhs) +{ + return !(lhs < rhs); +} + +template +inline +bsl::ostream& bdlb::operator<<(bsl::ostream& stream, + const NullableValue& object) +{ + return object.print(stream, 0, -1); +} + +// FREE FUNCTIONS +template +void bdlb::hashAppend(HASHALG& hashAlg, const NullableValue& input) +{ + if (!input.isNull()) { + hashAppend(hashAlg, true); + hashAppend(hashAlg, input.value()); + } + else { + hashAppend(hashAlg, false); + } +} +template +inline +void bdlb::swap(NullableValue& a, NullableValue& b) +{ + a.swap(b); +} +} // close enterprise namespace #if 0 // ========================= // class NullableValue @@ -670,6 +1329,7 @@ class NullableValue { // and 0 otherwise. }; + // FREE OPERATORS template bool operator==(const NullableValue& lhs, @@ -848,6 +1508,7 @@ void swap(NullableValue& a, NullableValue& b); // 'isNull' method for 'a' and 'b' is the same. The behavior is undefined // unless both objects were created with the same allocator, if any. + // ======================================= // class NullableValue_WithAllocator // ======================================= @@ -1532,6 +2193,7 @@ TYPE& NullableValue::value() return d_imp.value(); } + // ACCESSORS template template @@ -1627,6 +2289,22 @@ const TYPE *NullableValue::addressOr(const TYPE *value) const } // close package namespace +template +inline +int NullableValue::maxSupportedBdexVersion(int versionSelector) const +{ + using bslx::VersionFunctions::maxSupportedBdexVersion; + + // We need to call the 'bslx::VersionFunctions' helper function, because we + // cannot guarantee that 'TYPE' implements 'maxSupportedBdexVersion' as a + // class method. + + return maxSupportedBdexVersion(reinterpret_cast(0), + versionSelector); +} + + +} // FREE OPERATORS template inline @@ -1812,6 +2490,7 @@ void bdlb::swap(NullableValue& a, NullableValue& b) a.swap(b); } + namespace bdlb { // --------------------------------------- @@ -2511,13 +3190,14 @@ const TYPE& NullableValue_WithoutAllocator::value() const return d_buffer.object(); } -#endif + } // close package namespace } // close enterprise namespace -#endif +#endif // 0 +#endif // INCLUDED_BDLB_NULLABLEVALUE // ---------------------------------------------------------------------------- // Copyright 2016 Bloomberg Finance L.P. // diff --git a/groups/bdl/bdlb/pmroptional b/groups/bdl/bdlb/pmroptional index 2ee81ae419..b50d0e4a98 100644 --- a/groups/bdl/bdlb/pmroptional +++ b/groups/bdl/bdlb/pmroptional @@ -1941,29 +1941,7 @@ namespace pmr { void reset() noexcept { this->_M_reset(); } // bloomberg extensions start here - template - _Tp& makeValue(_Up&& __u) - { - memory_resource* __actual_alloc = this->_M_get_allocator(); - if (__actual_alloc) { - this->__emplace_alloc(__actual_alloc, std::forward<_Up>(__u)); - } - else - this->emplace(std::forward<_Up>(__u)); - - return *(*this); - } - - _Tp& makeValue() - { - memory_resource* __actual_alloc = this->_M_get_allocator(); - if (__actual_alloc) { - this->__emplace_alloc(__actual_alloc); - } - else - this->emplace(); - return *(*this); - } + template _Tp& makeValueInplace(_Args&&... __args) @@ -1975,45 +1953,7 @@ namespace pmr { else return this->emplace(std::forward<_Args>(__args)...); } - - bool isNull() const - { - return !this->has_value(); - } - int maxSupportedBdexVersion(int versionSelector) const; - - template - _Stream& bdexStreamIn(_Stream& stream, int version); - - template - _Stream& bdexStreamOut(_Stream& stream, int version) const; - - template - auto& print(_Stream& stream, int level = 0, - int spacesPerLevel = 4) const; - - typedef _Tp ValueType; - - const _Tp* addressOr(const _Tp* __value) const - { - return this->isNull() ? __value : &this->value(); - } - - const _Tp* valueOrNull() const - { - return this->isNull() ? 0 : &this->value(); - } - - _Tp valueOr(const _Tp& __value) const - { - return this->isNull() ? __value : this->value(); - } - - const _Tp* valueOr(const _Tp* __value) const - { - return this->isNull() ? __value : &this->value(); - } }; From a1df58c29081a40c5f82eb3553c2f2a8eff123c4 Mon Sep 17 00:00:00 2001 From: nina Queen of Awesome Date: Tue, 2 Jul 2019 14:38:07 +0100 Subject: [PATCH 06/14] nullable value inherits from pmr::optional; pmr::optional stripped down to basic, non constexpr functionality --- groups/bdl/bdlb/bdlb_nullablevalue.h | 210 +++- groups/bdl/bdlb/bdlb_nullablevalue.t.cpp | 2 - groups/bdl/bdlb/pmroptional | 1298 +++------------------- 3 files changed, 356 insertions(+), 1154 deletions(-) diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.h b/groups/bdl/bdlb/bdlb_nullablevalue.h index 1be75b65bb..d4e4dc1e96 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.h +++ b/groups/bdl/bdlb/bdlb_nullablevalue.h @@ -248,10 +248,102 @@ class NullableValue : public std::pmr::optional // for 'TYPE'. 'HasPrintMethod' is always true for 'NullableValue'. // CREATORS - using std::pmr::optional::optional; - - constexpr NullableValue(const NullableValue&) = default; - constexpr NullableValue(NullableValue&&) = default; + NullableValue(); + // Create a nullable object having the null value. If 'TYPE' takes an + // optional allocator at construction, use the currently installed + // default allocator to supply memory. + + explicit NullableValue(bslma::Allocator *basicAllocator); + // Create a nullable object that has the null value and that uses the + // specified 'basicAllocator' to supply memory. Note that this method + // will fail to compile if 'TYPE' does not take an optional allocator + // at construction. + + NullableValue(const NullableValue&) = default; + NullableValue(NullableValue&&) = default; +/* NullableValue(const NullableValue& original); + // Create a nullable object having the value of the specified + // 'original' object. If 'TYPE' takes an optional allocator at + // construction, use the currently installed default allocator to + // supply memory. + + NullableValue(bslmf::MovableRef original); + // Create a nullable object having the same value as the specified + // 'original' object by moving the contents of 'original' to the + // newly-created object. If 'TYPE' takes an optional allocator at + // construction, the allocator associated with 'original' is propagated + // for use in the newly-created object. 'original' is left in a valid + // but unspecified state. +*/ + NullableValue(const NullableValue& original, + bslma::Allocator *basicAllocator); + // Create a nullable object that has the value of the specified + // 'original' object and that uses the specified 'basicAllocator' to + // supply memory. Note that this method will fail to compile if 'TYPE' + // does not take an optional allocator at construction. + + NullableValue(bslmf::MovableRef original, + bslma::Allocator *basicAllocator); + // Create a nullable object having the same value as the specified + // 'original' object that uses the specified 'basicAllocator' to supply + // memory. If 'basicAllocator' is 0, the default allocator is used. + // The contents of 'original' are moved to the newly-created object. + // 'original' is left in a valid but unspecified state. Note that this + // method will fail to compile if 'TYPE' does not take an optional + // allocator at construction. + + template + NullableValue(BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value, + typename bsl::enable_if< + bsl::is_convertible::value + && + !bsl::is_convertible::value, + void>::type * = 0); // IMPLICIT + // Create a nullable object having the specified 'value' (of + // 'BDE_OTHER_TYPE') converted to 'TYPE'. If 'TYPE' takes an optional + // allocator at construction, use the currently installed default + // allocator to supply memory. Note that this constructor does not + // participate in overload resolution unless 'BDE_OTHER_TYPE' is + // convertible to 'TYPE' and not convertible to 'bslma::Allocator *'. + + template + NullableValue( + BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value, + bslma::Allocator *basicAllocator, + typename bsl::enable_if< + bsl::is_convertible::value, + void>::type * = 0); + // Create a nullable object that has the specified 'value' (of + // 'BDE_OTHER_TYPE') converted to 'TYPE', and that uses the specified + // 'basicAllocator' to supply memory. Note that this method will fail + // to compile if 'TYPE' does not take an optional allocator at + // construction. Also note that this constructor does not participate + // in overload resolution unless 'BDE_OTHER_TYPE' is convertible to + // 'TYPE'. + + template + explicit NullableValue(const NullableValue& original); + // Create a nullable object having the null value if the specified + // 'original' object is null, and the value of 'original.value()' (of + // 'BDE_OTHER_TYPE') converted to 'TYPE' otherwise. If 'TYPE' takes an + // optional allocator at construction, use the currently installed + // default allocator to supply memory. Note that this method will fail + // to compile if 'TYPE and 'BDE_OTHER_TYPE' are not compatible. + + template + NullableValue(const NullableValue& original, + bslma::Allocator *basicAllocator); + // Create a nullable object that has the null value if the specified + // 'original' object is null, and the value of 'original.value()' (of + // 'BDE_OTHER_TYPE') converted to 'TYPE' otherwise; use the specified + // 'basicAllocator' to supply memory. Note that this method will fail + // to compile if 'TYPE' does not take an optional allocator at + // construction, or if 'TYPE and 'BDE_OTHER_TYPE' are not compatible. + + // ~NullableValue(); + // Destroy this object. Note that this destructor is generated by the + // compiler. // MANIPULATORS NullableValue& operator=(const NullableValue& rhs); @@ -607,6 +699,113 @@ STREAM& NullableValue::bdexStreamIn(STREAM& stream, int version) return stream; } +// ============================================================================ +// INLINE DEFINITIONS +// ============================================================================ + + // ------------------------- + // class NullableValue + // ------------------------- + +// CREATORS +template +inline +NullableValue::NullableValue() +:std::pmr::optional(std::allocator_arg_t{}, + std::pmr::polymorphic_allocator( + (std::pmr::memory_resource*)(bslma::Default::allocator(nullptr)))) +{ +} + +template +inline +NullableValue::NullableValue(bslma::Allocator *basicAllocator) +: std::pmr::optional(std::allocator_arg_t{}, + std::pmr::polymorphic_allocator( + (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) +{ +} + +template +inline +NullableValue::NullableValue(const NullableValue& original, + bslma::Allocator *basicAllocator) +: std::pmr::optional(std::allocator_arg_t{}, + (std::pmr::polymorphic_allocator)( + (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) +{ + if (!original.isNull()) { + this->makeValue(original.value()); + } +} + +template +inline +NullableValue::NullableValue( + bslmf::MovableRef original, + bslma::Allocator *basicAllocator) +: std::pmr::optional(std::allocator_arg_t{}, + std::pmr::polymorphic_allocator( + (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) +{ + if (!original.isNull()) { + this->makeValue( MoveUtil::move(original.value())); + } +} + +template +template +inline +NullableValue::NullableValue( + BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value, + typename bsl::enable_if::value + && + !bsl::is_convertible::value, + void>::type *) +: std::pmr::optional(BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) +{ +} + +template +template +inline +NullableValue::NullableValue( + BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value, + bslma::Allocator *basicAllocator, + typename bsl::enable_if::value, + void>::type *) +: std::pmr::optional(std::allocator_arg_t{}, + std::pmr::polymorphic_allocator((std::pmr::memory_resource*) + (bslma::Default::allocator(basicAllocator))), + BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) +{ +} + +template +template +inline +NullableValue::NullableValue( + const NullableValue& original) +: std::pmr::optional((std::pmr::optional)original) +{ +} + +template +template +inline +NullableValue::NullableValue( + const NullableValue& original, + bslma::Allocator *basicAllocator) +: std::pmr::optional(std::allocator_arg_t{}, + std::pmr::polymorphic_allocator((std::pmr::memory_resource*) + (bslma::Default::allocator(basicAllocator)))) +{ + if (!original.isNull()) { + this->makeValue( MoveUtil::move(original.value())); + } +} + // ACCESSORS template @@ -689,12 +888,11 @@ template NullableValue& NullableValue::operator=( const NullableValue& rhs) { - const std::pmr::optional& rhs_base = rhs; if (rhs.isNull()) { this->reset(); } else { - this->makeValue(rhs_base.value()); + this->makeValue(rhs.value()); } return *this; } diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp b/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp index 15cf2c94c2..21c51e902e 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp +++ b/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp @@ -59,8 +59,6 @@ struct uses_allocator : true_type {}; template struct uses_allocator : true_type {}; template -struct uses_allocator : true_type {}; - template struct uses_allocator : true_type {}; } diff --git a/groups/bdl/bdlb/pmroptional b/groups/bdl/bdlb/pmroptional index b50d0e4a98..6f5375f15e 100644 --- a/groups/bdl/bdlb/pmroptional +++ b/groups/bdl/bdlb/pmroptional @@ -59,39 +59,26 @@ namespace pmr { class optional; // Payload for optionals with non-trivial destructor. - template , - bool /*_HasTrivialCopyAssignment*/ = - is_trivially_copy_assignable_v<_Tp>, - bool /*_HasTrivialMoveAssignment*/ = - is_trivially_move_assignable_v<_Tp>> + template struct _Optional_payload { constexpr _Optional_payload() noexcept : _M_empty() { } - template - constexpr - _Optional_payload(in_place_t, _Args&&... __args) - : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { } template constexpr _Optional_payload(std::initializer_list<_Up> __il, _Args&&... __args) - : _M_payload(__il, std::forward<_Args>(__args)...), - _M_engaged(true) - { } + { + _M_construct(__il, std::forward<_Args>(__args)...); + } template constexpr _Optional_payload(memory_resource* __pmr, _Args&&... __args) { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(std::forward<_Args>(__args)...); + _M_pmr = __pmr; + _M_construct(std::forward<_Args>(__args)...); } template @@ -99,22 +86,12 @@ namespace pmr { _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, _Args&&... __args) { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; + + _M_pmr = __pmr; _M_construct(__il, std::forward<_Args>(__args)...); } - constexpr - _Optional_payload(bool __engaged, const _Optional_payload& __other) - : _Optional_payload(__other) - { } - - constexpr - _Optional_payload(bool __engaged, _Optional_payload&& __other) - : _Optional_payload(std::move(__other)) - { } + constexpr _Optional_payload(const _Optional_payload& __other) @@ -201,916 +178,117 @@ namespace pmr { } // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { return this->_M_payload; } - - constexpr const _Tp& - _M_get() const noexcept - { return this->_M_payload; } - - // _M_reset is a 'safe' operation with no precondition. - void - _M_reset() noexcept - { - if (this->_M_engaged) - { - this->_M_engaged = false; - this->_M_payload.~_Stored_type(); - } - } - }; - - // Payload for potentially-constexpr optionals. - template - struct _Optional_payload<_Tp, true, true, true> - { - constexpr _Optional_payload() noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) { } - - template - constexpr - _Optional_payload(in_place_t, _Args&&... __args) - : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(std::initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(__il, std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(memory_resource* __pmr, _Args&&... __args) - : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true), - _M_pmr(__pmr ? __pmr : std::pmr::get_default_resource()) - { } - - template - constexpr - _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(__il, std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(__pmr ? __pmr : std::pmr::get_default_resource()) - { } - - template struct __ctor_tag {}; - - constexpr - _Optional_payload(__ctor_tag, const _Tp& __other) - : _M_payload(__other), _M_engaged(true), _M_pmr(__other._M_pmr) - { } - - constexpr _Optional_payload(__ctor_tag) noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) - { } - - constexpr _Optional_payload(__ctor_tag, _Tp&& __other) - : _M_payload(std::move(__other)), _M_engaged(true), _M_pmr(__other._M_pmr) - { } - - constexpr - _Optional_payload(bool __engaged, const _Optional_payload& __other) - : _Optional_payload(__engaged ? - _Optional_payload(__ctor_tag{}, - __other._M_payload) : - _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - constexpr - _Optional_payload(bool __engaged, _Optional_payload&& __other) - : _Optional_payload(__engaged - ? _Optional_payload(__ctor_tag{}, - std::move(__other._M_payload)) - : _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - using _Stored_type = remove_const_t<_Tp>; - - struct _Empty_byte { }; - - union { - _Empty_byte _M_empty; - _Stored_type _M_payload; - }; - bool _M_engaged; - memory_resource* _M_pmr; - }; - - // Payload for optionals with non-trivial copy assignment. - template - struct _Optional_payload<_Tp, true, false, true> - { - constexpr _Optional_payload() noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) { } - - template - constexpr - _Optional_payload(in_place_t, _Args&&... __args) - : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(std::initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(__il, std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(memory_resource* __pmr, _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - - _M_construct(std::forward<_Args>(__args)...); - } - - template - constexpr - _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, - _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(__il, std::forward<_Args>(__args)...); - } - - template struct __ctor_tag {}; - - constexpr _Optional_payload(__ctor_tag, const _Tp& __other) - : _M_payload(__other), - _M_engaged(true), - _M_pmr(__other._M_pmr) - { } - - constexpr _Optional_payload(__ctor_tag) noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) - { } - - constexpr _Optional_payload(__ctor_tag, _Tp&& __other) - : _M_payload(std::move(__other)), - _M_engaged(true), - _M_pmr(__other._M_pmr) - { } - - constexpr - _Optional_payload(bool __engaged, const _Optional_payload& __other) - : _Optional_payload(__engaged ? - _Optional_payload(__ctor_tag{}, - __other._M_payload) : - _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - constexpr - _Optional_payload(bool __engaged, _Optional_payload&& __other) - : _Optional_payload(__engaged - ? _Optional_payload(__ctor_tag{}, - std::move(__other._M_payload)) - : _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - _Optional_payload(const _Optional_payload&) = default; - _Optional_payload(_Optional_payload&&) = default; - - _Optional_payload& - operator=(const _Optional_payload& __other) - { - if (this->_M_engaged && __other._M_engaged) - this->_M_get() = __other._M_get(); - else - { - if (__other._M_engaged) - this->_M_construct(__other._M_get()); - else - this->_M_reset(); - } - return *this; - } - - _Optional_payload& - operator=(_Optional_payload&& __other) = default; - - using _Stored_type = remove_const_t<_Tp>; - - struct _Empty_byte { }; - - union { - _Empty_byte _M_empty; - _Stored_type _M_payload; - }; - bool _M_engaged; - memory_resource* _M_pmr; - - template - void - _M_construct(_Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - if (_M_pmr) - { - __uses_allocator_construct(polymorphic_allocator<_Stored_type>(_M_pmr), - std::__addressof(this->_M_payload), - std::forward<_Args>(__args)...); - } - else - { - ::new ((void *) std::__addressof(this->_M_payload)) - _Stored_type(std::forward<_Args>(__args)...); - } - this->_M_engaged = true; - } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { return this->_M_payload; } - - constexpr const _Tp& - _M_get() const noexcept - { return this->_M_payload; } - - // _M_reset is a 'safe' operation with no precondition. - void - _M_reset() noexcept - { - if (this->_M_engaged) - { - this->_M_engaged = false; - this->_M_payload.~_Stored_type(); - } - } - }; - - // Payload for optionals with non-trivial move assignment. - template - struct _Optional_payload<_Tp, true, true, false> - { - constexpr _Optional_payload() noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) { } - - template - constexpr - _Optional_payload(in_place_t, _Args&&... __args) - : _M_payload(std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(std::initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(__il, std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(memory_resource* __pmr, _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(std::forward<_Args>(__args)...); - } - - template - constexpr - _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, - _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(__il, std::forward<_Args>(__args)...); - } - - template struct __ctor_tag {}; - - constexpr - _Optional_payload(__ctor_tag, const _Tp& __other) - : _M_payload(__other), - _M_engaged(true), - _M_pmr(__other._M_pmr) - { } - - constexpr _Optional_payload(__ctor_tag) noexcept - : _M_empty(), _M_engaged(false) - { } - - constexpr _Optional_payload(__ctor_tag, _Tp&& __other) - : _M_payload(std::move(__other)), - _M_engaged(true), - _M_pmr(__other._M_pmr) - { } - - constexpr - _Optional_payload(bool __engaged, const _Optional_payload& __other) - : _Optional_payload(__engaged ? - _Optional_payload(__ctor_tag{}, - __other._M_payload) : - _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - constexpr - _Optional_payload(bool __engaged, _Optional_payload&& __other) - : _Optional_payload(__engaged - ? _Optional_payload(__ctor_tag{}, - std::move(__other._M_payload)) - : _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - _Optional_payload(const _Optional_payload&) = default; - _Optional_payload(_Optional_payload&&) = default; - - _Optional_payload& - operator=(const _Optional_payload& __other) = default; - - _Optional_payload& - operator=(_Optional_payload&& __other) - noexcept(__and_v, - is_nothrow_move_assignable<_Tp>>) - { - if (this->_M_engaged && __other._M_engaged) - this->_M_get() = std::move(__other._M_get()); - else - { - if (__other._M_engaged) - this->_M_construct(std::move(__other._M_get())); - else - this->_M_reset(); - } - return *this; - } - - using _Stored_type = remove_const_t<_Tp>; - - struct _Empty_byte { }; - - union { - _Empty_byte _M_empty; - _Stored_type _M_payload; - }; - bool _M_engaged; - memory_resource* _M_pmr; - - template - void - _M_construct(_Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - if (_M_pmr) - { - __uses_allocator_construct(polymorphic_allocator<_Stored_type>(_M_pmr), - std::__addressof(this->_M_payload), - std::forward<_Args>(__args)...); - } - else - { - ::new ((void *) std::__addressof(this->_M_payload)) - _Stored_type(std::forward<_Args>(__args)...); - } - this->_M_engaged = true; - } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { return this->_M_payload; } - - constexpr const _Tp& - _M_get() const noexcept - { return this->_M_payload; } - - // _M_reset is a 'safe' operation with no precondition. - void - _M_reset() noexcept - { - if (this->_M_engaged) - { - this->_M_engaged = false; - this->_M_payload.~_Stored_type(); - } - } - }; - - // Payload for optionals with non-trivial copy and move assignment. - template - struct _Optional_payload<_Tp, true, false, false> - { - constexpr _Optional_payload() noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) {} - - template - constexpr - _Optional_payload(in_place_t, _Args&&... __args) - : _M_payload(std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(std::initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(__il, std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(memory_resource* __pmr, _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(std::forward<_Args>(__args)...); - } - - template - constexpr - _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, - _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(__il, std::forward<_Args>(__args)...); - } - - template struct __ctor_tag {}; - - constexpr _Optional_payload(__ctor_tag, const _Tp& __other) - : _M_payload(__other), - _M_engaged(true), - _M_pmr(__other._M_pmr) - { } - - constexpr _Optional_payload(__ctor_tag) noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) - { } - - constexpr _Optional_payload(__ctor_tag, _Tp&& __other) - : _M_payload(std::move(__other)), - _M_engaged(true), - _M_pmr(__other._M_pmr) - { } - - constexpr - _Optional_payload(bool __engaged, const _Optional_payload& __other) - : _Optional_payload(__engaged ? - _Optional_payload(__ctor_tag{}, - __other._M_payload) : - _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - constexpr - _Optional_payload(bool __engaged, _Optional_payload&& __other) - : _Optional_payload(__engaged - ? _Optional_payload(__ctor_tag{}, - std::move(__other._M_payload)) - : _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - _Optional_payload(const _Optional_payload&) = default; - _Optional_payload(_Optional_payload&&) = default; - - _Optional_payload& - operator=(const _Optional_payload& __other) - { - if (this->_M_engaged && __other._M_engaged) - this->_M_get() = __other._M_get(); - else - { - if (__other._M_engaged) - this->_M_construct(__other._M_get()); - else - this->_M_reset(); - } - return *this; - } - - _Optional_payload& - operator=(_Optional_payload&& __other) - noexcept(__and_v, - is_nothrow_move_assignable<_Tp>>) - { - if (this->_M_engaged && __other._M_engaged) - this->_M_get() = std::move(__other._M_get()); - else - { - if (__other._M_engaged) - this->_M_construct(std::move(__other._M_get())); - else - this->_M_reset(); - } - return *this; - } - - using _Stored_type = remove_const_t<_Tp>; - - struct _Empty_byte { }; - - union { - _Empty_byte _M_empty; - _Stored_type _M_payload; - }; - bool _M_engaged; - memory_resource* _M_pmr; - - template - void - _M_construct(_Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - if (_M_pmr) - { - __uses_allocator_construct(polymorphic_allocator<_Stored_type>(_M_pmr), - std::__addressof(this->_M_payload), - std::forward<_Args>(__args)...); - } - else - { - ::new ((void *) std::__addressof(this->_M_payload)) - _Stored_type(std::forward<_Args>(__args)...); - } - this->_M_engaged = true; - } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { return this->_M_payload; } - - constexpr const _Tp& - _M_get() const noexcept - { return this->_M_payload; } - - // _M_reset is a 'safe' operation with no precondition. - void - _M_reset() noexcept - { - if (this->_M_engaged) - { - this->_M_engaged = false; - this->_M_payload.~_Stored_type(); - } - } - }; - - template - class _Optional_base_impl - { - protected: - using _Stored_type = remove_const_t<_Tp>; - - // The _M_construct operation has !_M_engaged as a precondition - // while _M_destruct has _M_engaged as a precondition. - template - void - _M_construct(memory_resource* __pmr, _Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - __uses_allocator_construct(polymorphic_allocator(__pmr), - std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload), - std::forward<_Args>(__args)...); - static_cast<_Dp*>(this)->_M_payload._M_engaged = true; - } - - template - void - _M_construct(_Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - if (static_cast<_Dp*>(this)->_M_payload._M_pmr) - { - __uses_allocator_construct(polymorphic_allocator(static_cast<_Dp*>(this)->_M_payload._M_pmr), - std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload), - std::forward<_Args>(__args)...); - } - else - { - ::new - (std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload)) - _Stored_type(std::forward<_Args>(__args)...); - } - static_cast<_Dp*>(this)->_M_payload._M_engaged = true; - } - - void - _M_destruct() noexcept - { - static_cast<_Dp*>(this)->_M_payload._M_engaged = false; - static_cast<_Dp*>(this)->_M_payload._M_payload.~_Stored_type(); - } - - // _M_reset is a 'safe' operation with no precondition. - void - _M_reset() noexcept - { - if (static_cast<_Dp*>(this)->_M_payload._M_engaged) - static_cast<_Dp*>(this)->_M_destruct(); - } - - void _M_set_allocator(memory_resource* __pmr) noexcept - { - if (__pmr) - static_cast<_Dp*>(this)->_M_payload._M_pmr = __pmr; - else - static_cast<_Dp*>(this)->_M_payload._M_pmr = std::pmr::get_default_resource(); - } - memory_resource* _M_get_allocator() noexcept - { - return static_cast<_Dp*>(this)->_M_payload._M_pmr; - } - }; - - /** - * @brief Class template that takes care of copy/move constructors - of optional - * - * Such a separate base class template is necessary in order to - * conditionally make copy/move constructors trivial. - * @see optional, _Enable_special_members - */ - template, - bool = is_trivially_move_constructible_v<_Tp>> - class _Optional_base - // protected inheritance because optional needs to reach that base too - : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> - { - friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; - - public: - // Constructors for disengaged optionals. - constexpr _Optional_base() = default; - - // Constructors for engaged optionals. - template, bool> = false> - constexpr explicit _Optional_base(in_place_t, _Args&&... __args) - : _M_payload(in_place, - std::forward<_Args>(__args)...) { } - - // Constructors for engaged optionals. - template, _Args&&...>, bool> = false> - constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) - : _M_payload(__pmr, - std::forward<_Args>(__args)...) { } - - template&, - _Args&&...>, bool> = false> - constexpr explicit _Optional_base(in_place_t, - initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(in_place, - __il, std::forward<_Args>(__args)...) - { } - - // Copy and move constructors. - constexpr _Optional_base(const _Optional_base& __other) - : _M_payload(__other._M_payload._M_engaged, - __other._M_payload) - { } - - constexpr _Optional_base(_Optional_base&& __other) - noexcept(is_nothrow_move_constructible_v<_Tp>) - : _M_payload(__other._M_payload._M_engaged, - std::move(__other._M_payload)) - { } - - // Assignment operators. - _Optional_base& operator=(const _Optional_base&) = default; - _Optional_base& operator=(_Optional_base&&) = default; - - protected: - - constexpr bool _M_is_engaged() const noexcept - { return this->_M_payload._M_engaged; } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } - - constexpr const _Tp& - _M_get() const noexcept - { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } - - private: - _Optional_payload<_Tp> _M_payload; - }; - - template - class _Optional_base<_Tp, false, true> - : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> - { - friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; - public: - - // Constructors for disengaged optionals. - constexpr _Optional_base() = default; - - // Constructors for engaged optionals. - template, bool> = false> - constexpr explicit _Optional_base(in_place_t, _Args&&... __args) - : _M_payload(in_place, - std::forward<_Args>(__args)...) { } - - // Constructors for engaged optionals. - template, _Args&&...>, bool> = false> - constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) - : _M_payload(__pmr, - std::forward<_Args>(__args)...) { } - - template&, - _Args&&...>, bool> = false> - constexpr explicit _Optional_base(in_place_t, - initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(in_place, - __il, std::forward<_Args>(__args)...) - { } - - // Copy and move constructors. - constexpr _Optional_base(const _Optional_base& __other) - : _M_payload(__other._M_payload._M_engaged, - __other._M_payload) - { } - - constexpr _Optional_base(_Optional_base&& __other) = default; - - // Assignment operators. - _Optional_base& operator=(const _Optional_base&) = default; - _Optional_base& operator=(_Optional_base&&) = default; - - protected: - - constexpr bool _M_is_engaged() const noexcept - { return this->_M_payload._M_engaged; } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } + constexpr _Tp& + _M_get() noexcept + { return this->_M_payload; } constexpr const _Tp& - _M_get() const noexcept + _M_get() const noexcept + { return this->_M_payload; } + + // _M_reset is a 'safe' operation with no precondition. + void + _M_reset() noexcept { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; + if (this->_M_engaged) + { + this->_M_engaged = false; + this->_M_payload.~_Stored_type(); + } } - - private: - _Optional_payload<_Tp> _M_payload; }; - template - class _Optional_base<_Tp, true, false> - : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> + template + class _Optional_base_impl { - friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; - public: - - // Constructors for disengaged optionals. - constexpr _Optional_base() = default; - - // Constructors for engaged optionals. - template, bool> = false> - constexpr explicit _Optional_base(in_place_t, _Args&&... __args) - : _M_payload(in_place, - std::forward<_Args>(__args)...) { } - - template, _Args&&...>, bool> = false> - constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) - : _M_payload(__pmr, - std::forward<_Args>(__args)...) { } - - template&, - _Args&&...>, bool> = false> - constexpr explicit _Optional_base(in_place_t, - initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(in_place, - __il, std::forward<_Args>(__args)...) - { } - - // Copy and move constructors. - constexpr _Optional_base(const _Optional_base& __other) = default; - - constexpr _Optional_base(_Optional_base&& __other) - noexcept(is_nothrow_move_constructible_v<_Tp>) - : _M_payload(__other._M_payload._M_engaged, - std::move(__other._M_payload)) - { } - - // Assignment operators. - _Optional_base& operator=(const _Optional_base&) = default; - _Optional_base& operator=(_Optional_base&&) = default; - protected: + using _Stored_type = remove_const_t<_Tp>; + + // The _M_construct operation has !_M_engaged as a precondition + // while _M_destruct has _M_engaged as a precondition. + + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + if (static_cast<_Dp*>(this)->_M_payload._M_pmr) + { + __uses_allocator_construct(polymorphic_allocator(static_cast<_Dp*>(this)->_M_payload._M_pmr), + std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload), + std::forward<_Args>(__args)...); + } + else + { + ::new + (std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload)) + _Stored_type(std::forward<_Args>(__args)...); + } + static_cast<_Dp*>(this)->_M_payload._M_engaged = true; + } - constexpr bool _M_is_engaged() const noexcept - { return this->_M_payload._M_engaged; } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept + void + _M_destruct() noexcept { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; + static_cast<_Dp*>(this)->_M_payload._M_engaged = false; + static_cast<_Dp*>(this)->_M_payload._M_payload.~_Stored_type(); } - - constexpr const _Tp& - _M_get() const noexcept + + // _M_reset is a 'safe' operation with no precondition. + void + _M_reset() noexcept { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; + if (static_cast<_Dp*>(this)->_M_payload._M_engaged) + static_cast<_Dp*>(this)->_M_destruct(); } - private: - _Optional_payload<_Tp> _M_payload; - }; + void _M_set_allocator(memory_resource* __pmr) noexcept + { + static_cast<_Dp*>(this)->_M_payload._M_pmr = __pmr; + } + memory_resource* _M_get_allocator() noexcept + { + return static_cast<_Dp*>(this)->_M_payload._M_pmr; + } + }; + + /** + * @brief Class template that takes care of copy/move constructors + of optional + * + * Such a separate base class template is necessary in order to + * conditionally make copy/move constructors trivial. + * @see optional, _Enable_special_members + */ template - class _Optional_base<_Tp, true, true> + class _Optional_base + // protected inheritance because optional needs to reach that base too : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> { friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; - public: + public: // Constructors for disengaged optionals. constexpr _Optional_base() = default; // Constructors for engaged optionals. template, bool> = false> - constexpr explicit _Optional_base(in_place_t, _Args&&... __args) - : _M_payload(in_place, - std::forward<_Args>(__args)...) { } - - template, _Args&&...>, bool> = false> + enable_if_t<__is_uses_allocator_constructible_v<_Tp, polymorphic_allocator, _Args&&...>, bool> = false> constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) : _M_payload(__pmr, std::forward<_Args>(__args)...) { } - template&, - _Args&&...>, bool> = false> - constexpr explicit _Optional_base(in_place_t, - initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(in_place, - __il, std::forward<_Args>(__args)...) - { } // Copy and move constructors. - constexpr _Optional_base(const _Optional_base& __other) = default; - constexpr _Optional_base(_Optional_base&& __other) = default; + constexpr _Optional_base(const _Optional_base& __other) + : _M_payload(__other._M_payload) + { } + + constexpr _Optional_base(_Optional_base&& __other) + noexcept(is_nothrow_move_constructible_v<_Tp>) + : _M_payload(std::move(__other._M_payload)) + { } // Assignment operators. _Optional_base& operator=(const _Optional_base&) = default; @@ -1140,6 +318,7 @@ namespace pmr { _Optional_payload<_Tp> _M_payload; }; + template class optional; @@ -1205,8 +384,9 @@ namespace pmr { optional<_Tp>> { static_assert(!is_same_v, nullopt_t>); - static_assert(!is_same_v, in_place_t>); static_assert(!is_reference_v<_Tp>); + + template friend class optional; private: using _Base = _Optional_base<_Tp>; @@ -1214,8 +394,6 @@ namespace pmr { // SFINAE helpers template using __not_self = __not_>>; - template - using __not_tag = __not_>>; template using _Requires = enable_if_t<__and_v<_Cond...>, bool>; @@ -1225,32 +403,34 @@ namespace pmr { typename __has_allocator_type<_Tp>::__alloc_param_type; */ using value_type = _Tp; + using __Allocator_type = std::pmr::polymorphic_allocator; constexpr optional() { - this->_M_set_allocator(std::pmr::get_default_resource()); } constexpr optional(nullopt_t) noexcept { } // Converting constructors for engaged optionals. template, __not_tag<_Up>, + _Requires<__not_self<_Up>, __not_>>>, is_constructible<_Tp, _Up&&>, is_convertible<_Up&&, _Tp>> = true> constexpr optional(_Up&& __t) - : _Base(std::in_place, std::forward<_Up>(__t)) { } + { emplace(std::forward<_Up>(__t)); + }; template, __not_tag<_Up>, + _Requires<__not_self<_Up>, __not_>>>, is_constructible<_Tp, _Up&&>, __not_>> = false> explicit constexpr optional(_Up&& __t) - : _Base(std::in_place, std::forward<_Up>(__t)) { } + { emplace(std::forward<_Up>(__t)); + }; template>, @@ -1260,6 +440,7 @@ namespace pmr { constexpr optional(const optional<_Up>& __t) { + this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(*__t); } @@ -1272,6 +453,7 @@ namespace pmr { explicit constexpr optional(const optional<_Up>& __t) { + this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(*__t); } @@ -1284,6 +466,7 @@ namespace pmr { constexpr optional(optional<_Up>&& __t) { + this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(std::move(*__t)); } @@ -1296,6 +479,7 @@ namespace pmr { explicit constexpr optional(optional<_Up>&& __t) { + this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(std::move(*__t)); } @@ -1308,6 +492,7 @@ namespace pmr { constexpr optional(const std::optional<_Up>& __t) { + this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(*__t); } @@ -1320,6 +505,7 @@ namespace pmr { explicit constexpr optional(const std::optional<_Up>& __t) { + this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(*__t); } @@ -1332,6 +518,7 @@ namespace pmr { constexpr optional(std::optional<_Up>&& __t) { + this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(std::move(*__t)); } @@ -1344,6 +531,7 @@ namespace pmr { explicit constexpr optional(std::optional<_Up>&& __t) { + this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(std::move(*__t)); } @@ -1351,47 +539,44 @@ namespace pmr { constexpr optional(const std::optional<_Tp>& __t) { + this->_M_set_allocator(__t._M_get_allocator()); if (__t) - emplace(std::move(*__t)); + emplace(*__t); } constexpr optional(std::optional<_Tp>&& __t) { + this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(std::move(*__t)); } // Converting memory-resource-constructors for engaged optionals. - optional(memory_resource* __pmr) + optional(allocator_arg_t, const __Allocator_type& __a) { - if (!__pmr) - this->_M_set_allocator(std::pmr::get_default_resource()); - else - this->_M_set_allocator(__pmr); + this->_M_set_allocator(__a.resource()); } template, __not_tag<_Up>, + _Requires<__not_self<_Up>, is_constructible<_Tp, _Up&&>, is_convertible<_Up&&, _Tp>> = true> constexpr - optional(_Up&& __t, memory_resource* __pmr) + optional(allocator_arg_t, const __Allocator_type& __a,_Up&& __t) { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - __emplace_alloc(__actual_alloc, std::forward<_Up>(__t)); + this->_M_set_allocator(__a.resource()); + emplace(std::forward<_Up>(__t)); } template, __not_tag<_Up>, + _Requires<__not_self<_Up>, is_constructible<_Tp, _Up&&>, __not_>> = false> explicit constexpr - optional(_Up&& __t, memory_resource* __pmr) + optional(allocator_arg_t, const __Allocator_type& __a, _Up&& __t) { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - __emplace_alloc(__actual_alloc, std::forward<_Up>(__t)); + this->_M_set_allocator(__a.resource()); + emplace(std::forward<_Up>(__t)); } template, __not_<__converts_from_optional<_Tp, _Up>>> = true> constexpr - optional(const optional<_Up>& __t, memory_resource* __pmr) + optional(allocator_arg_t, const __Allocator_type& __a, const optional<_Up>& __t) { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - __emplace_alloc(__actual_alloc, *__t); + this->_M_set_allocator(__a.resource()); + emplace(*__t); } template>, __not_<__converts_from_optional<_Tp, _Up>>> = false> explicit constexpr - optional(const optional<_Up>& __t, memory_resource* __pmr) + optional(allocator_arg_t, const __Allocator_type& __a, const optional<_Up>& __t) { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); + this->_M_set_allocator(__a.resource()); if (__t) - this->_M_set_allocator(__actual_alloc); - __emplace_alloc(__actual_alloc, *__t); + emplace(*__t); } template , __not_<__converts_from_optional<_Tp, _Up>>> = true> constexpr - optional(optional<_Up>&& __t, memory_resource* __pmr) + optional(allocator_arg_t, const __Allocator_type& __a, optional<_Up>&& __t) { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); + this->_M_set_allocator(__a.resource()); if (__t) - __emplace_alloc(__actual_alloc, std::move(*__t)); + emplace(std::move(*__t)); } template >, __not_<__converts_from_optional<_Tp, _Up>>> = false> explicit constexpr - optional(optional<_Up>&& __t, memory_resource* __pmr) + optional(allocator_arg_t, const __Allocator_type& __a, optional<_Up>&& __t) { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); + this->_M_set_allocator(__a.resource()); if (__t) - __emplace_alloc(__actual_alloc, std::move(*__t)); + emplace(std::move(*__t)); } constexpr - optional(const optional& __t, memory_resource* __pmr) + optional(allocator_arg_t, const __Allocator_type& __a, const optional& __t) { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); + this->_M_set_allocator(__a.resource()); if (__t) - __emplace_alloc(__actual_alloc, *__t); + emplace(*__t); } constexpr - optional(optional&& __t, memory_resource* __pmr) + optional(allocator_arg_t, const __Allocator_type& __a, optional&& __t) { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - if (__t) - __emplace_alloc(__actual_alloc, std::move(*__t)); + memory_resource* __actual_alloc = __a.resource(); + if (__t) + emplace(std::move(*__t)); } template, __not_<__converts_from_optional<_Tp, _Up>>> = true> constexpr - optional(const std::optional<_Up>& __t, memory_resource* __pmr) + optional(allocator_arg_t, const __Allocator_type& __a, const std::optional<_Up>& __t) { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); + this->_M_set_allocator(__a.resource()); if (__t) - __emplace_alloc(__actual_alloc, *__t); - } - - template, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(const std::optional<_Up>& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - if (__t) - __emplace_alloc(__actual_alloc, *__t); - } - - template , - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(std::optional<_Up>&& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - if (__t) - __emplace_alloc(__actual_alloc, std::move(*__t)); - } - - template , - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(std::optional<_Up>&& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - if (__t) - __emplace_alloc(__actual_alloc, std::move(*__t)); - } - - // Converting allocator-constructors for engaged optionals. - template, __not_tag<_Up>, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>> = true> - constexpr - optional(_Up&& __t, const polymorphic_allocator& __pmr) - : _Base(__pmr.resource(), std::forward<_Up>(__t)) { } - - template, __not_tag<_Up>, - is_constructible<_Tp, _Up&&>, - __not_>> = false> - explicit constexpr - optional(_Up&& __t, const polymorphic_allocator& __pmr) - : _Base(__pmr.resource(), std::forward<_Up>(__t)) { } - - template>, - is_constructible<_Tp, const _Up&>, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(const optional<_Up>& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, *__t); - } - - template>, - is_constructible<_Tp, const _Up&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(const optional<_Up>& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, *__t); - } - - template >, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(optional<_Up>&& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, std::move(*__t)); - } - - template >, - is_constructible<_Tp, _Up&&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(optional<_Up>&& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, std::move(*__t)); - } - - template, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(const std::optional<_Up>& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, *__t); + emplace(*__t); } template>, __not_<__converts_from_optional<_Tp, _Up>>> = false> explicit constexpr - optional(const std::optional<_Up>& __t, const polymorphic_allocator& __pmr) + optional(allocator_arg_t, const __Allocator_type& __a, const std::optional<_Up>& __t) { - this->_M_set_allocator(__pmr.resource()); + this->_M_set_allocator(__a.resource()); if (__t) - __emplace_alloc(__pmr, *__t); + emplace(*__t); } template , __not_<__converts_from_optional<_Tp, _Up>>> = true> constexpr - optional(std::optional<_Up>&& __t, const polymorphic_allocator& __pmr) + optional(allocator_arg_t, const __Allocator_type& __a, std::optional<_Up>&& __t) { - this->_M_set_allocator(__pmr.resource()); + this->_M_set_allocator(__a.resource()); if (__t) - __emplace_alloc(__pmr, std::move(*__t)); + emplace(std::move(*__t)); } template >, __not_<__converts_from_optional<_Tp, _Up>>> = false> explicit constexpr - optional(std::optional<_Up>&& __t, const polymorphic_allocator& __pmr) + optional(allocator_arg_t, const __Allocator_type& __a, std::optional<_Up>&& __t) { - this->_M_set_allocator(__pmr.resource()); + this->_M_set_allocator(__a.resource()); if (__t) - __emplace_alloc(__pmr, std::move(*__t)); + emplace(std::move(*__t)); } - constexpr - optional(const optional& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, *__t); - } - - constexpr - optional(optional&& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, std::move(*__t)); - } - - template> = false> - explicit constexpr - optional(in_place_t, _Args&&... __args) - : _Base(std::in_place, std::forward<_Args>(__args)...) { } - template&, - _Args&&...>> = false> - explicit constexpr - optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) - : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { } // Assignment operators. optional& @@ -1793,26 +823,6 @@ namespace pmr { return this->_M_get(); } - template - //enable_if_t<__is_uses_allocator_constructible_v<_Tp, polymorphic_allocator, _Args&&...>, _Tp&> - _Tp& - __emplace_alloc(memory_resource* __pmr, _Args&&... __args) - { - this->_M_reset(); - this->_M_construct(__pmr, std::forward<_Args>(__args)...); - return this->_M_get(); - } - - template - //enable_if_t<__is_uses_allocator_constructible_v<_Tp, polymorphic_allocator, _Args&&...>, _Tp&> - _Tp& - __emplace_alloc(const polymorphic_allocator& __pmr, _Args&&... __args) - { - this->_M_reset(); - this->_M_construct(__pmr.resource(), std::forward<_Args>(__args)...); - return this->_M_get(); - } - template enable_if_t&, _Args&&...>, _Tp&> @@ -1946,12 +956,8 @@ namespace pmr { template _Tp& makeValueInplace(_Args&&... __args) { - memory_resource* __actual_alloc = this->_M_get_allocator(); - if (__actual_alloc) - return this->__emplace_alloc(__actual_alloc, - std::forward<_Args>(__args)...); - else return this->emplace(std::forward<_Args>(__args)...); + } From 5a6c6ca38def87b8daa614e3adcf49368c61adad Mon Sep 17 00:00:00 2001 From: nina Queen of Awesome Date: Fri, 12 Jul 2019 14:35:30 +0100 Subject: [PATCH 07/14] porting std::pmroptional adding bloomberg optional wrapper initial version --- groups/bdl/bdlb/bdlb_nullablevalue.h | 233 +++- groups/bdl/bdlb/bdlb_nullablevalue.t.cpp | 4 +- groups/bdl/bdlb/pmroptional | 1340 +++++++++++----------- 3 files changed, 858 insertions(+), 719 deletions(-) diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.h b/groups/bdl/bdlb/bdlb_nullablevalue.h index d4e4dc1e96..cee9c8c480 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.h +++ b/groups/bdl/bdlb/bdlb_nullablevalue.h @@ -180,30 +180,155 @@ BSLS_IDENT("$Id: $") #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES -namespace BloombergLP { -namespace bslma { - template struct UsesBslmaAllocator> : bsl::true_type {}; -} + +template +struct bb_optional_wrap : private std::_Enable_copy_move< + // Copy constructor. + std::is_copy_constructible_v, + // Copy assignment. + std::is_copy_assignable_v, + // Move constructor. + std::is_move_constructible_v, + // Move assignment. + std::is_move_assignable_v, + // Unique tag type. + bb_optional_wrap> +{ + template + using _Requires = std::enable_if_t, bool>; + + bb_optional_wrap(const bb_optional_wrap& other):value(other.value){}; + bb_optional_wrap(bb_optional_wrap&& other): value(std::move(other.value)){}; + + bb_optional_wrap& + operator=(const bb_optional_wrap& other) + { + this->value = other.value; + return *this; + } + + + bb_optional_wrap& + operator=(bb_optional_wrap&& other) + noexcept(std::__and_v, + std::is_nothrow_move_assignable>) + { + this->value = std::move(other.value); + return *this; + } + + template , + std::is_convertible> = false> + bb_optional_wrap(BDE_OTHER_TYPE&& other) + { + BSLS_ASSERT(false);// "this function should never be called."); + } + + template , + std::__not_>> = true> + explicit bb_optional_wrap(BDE_OTHER_TYPE&& other) + { + BSLS_ASSERT(false);// "this function should never be called."); + } + + template > = false> + bb_optional_wrap(_Args&&... __args) + { + BSLS_ASSERT(false);// "this function should never be called."); + } + + bb_optional_wrap(std::allocator_arg_t, const std::pmr::polymorphic_allocator& __a, + const bb_optional_wrap& other) + { + BloombergLP::bslma::ConstructionUtil::construct( + std::__addressof(this->value), + (BloombergLP::bslma::Allocator *)(__a.resource()), + other.value); + } + bb_optional_wrap(std::allocator_arg_t, const std::pmr::polymorphic_allocator& __a, + bb_optional_wrap&& other) + { + BloombergLP::bslma::ConstructionUtil::construct( + std::__addressof(this->value), + (BloombergLP::bslma::Allocator *)(__a.resource()), + std::move(other.value)); + } + + template< typename... _Args> + bb_optional_wrap(std::allocator_arg_t, const std::pmr::polymorphic_allocator& __a, _Args&&... __args) + { + BloombergLP::bslma::ConstructionUtil::construct( + std::__addressof(this->value), + (BloombergLP::bslma::Allocator *)(__a.resource()), + std::forward<_Args>(__args)...); + } + + + template + bb_optional_wrap(std::allocator_arg_t, const std::pmr::polymorphic_allocator& __a, + std::initializer_list<_Up> __il,_Args&&... __args) + { + BloombergLP::bslma::ConstructionUtil::construct( + std::__addressof(this->value), + (BloombergLP::bslma::Allocator *)(__a.resource()), + __il, + std::forward<_Args>(__args)...); + } + + template > = true> + bb_optional_wrap& operator=(const BDE_OTHER_TYPE& other) + { + this->value = other; + } + + + template > = true> + bb_optional_wrap& operator=(BDE_OTHER_TYPE&& other) + { + this->value = std::move(other); + } + + ~bb_optional_wrap() { value.~TYPE(); } + + struct _Empty_byte { }; + + union { + _Empty_byte _M_empty; + TYPE value; + }; + }; + + + +namespace std +{ + template + struct uses_allocator, _Alloc> : true_type {}; } namespace BloombergLP { namespace bdlb { -template -class NullableValue_WithAllocator; -template -class NullableValue_WithoutAllocator; // ========================= // class NullableValue // ========================= +template +using optional_base = std::conditional_t::value, + std::pmr::optional> , + std::pmr::optional >; template -class NullableValue : public std::pmr::optional +class NullableValue : public optional_base { // This template class extends the set of values of its value-semantic @@ -248,7 +373,22 @@ class NullableValue : public std::pmr::optional // for 'TYPE'. 'HasPrintMethod' is always true for 'NullableValue'. // CREATORS - NullableValue(); + template< typename DUMMY = TYPE> + NullableValue(typename bsl::enable_if< + bslma::UsesBslmaAllocator::value, + void>::type * = 0) + :optional_base(std::allocator_arg_t{}, + std::pmr::polymorphic_allocator( + (std::pmr::memory_resource*)(bslma::Default::allocator(nullptr)))) + { + } + template< typename DUMMY = TYPE> + NullableValue(typename bsl::enable_if< + !bslma::UsesBslmaAllocator::value, + void>::type * = 0) + :optional_base() + { + } // Create a nullable object having the null value. If 'TYPE' takes an // optional allocator at construction, use the currently installed // default allocator to supply memory. @@ -260,7 +400,7 @@ class NullableValue : public std::pmr::optional // at construction. NullableValue(const NullableValue&) = default; - NullableValue(NullableValue&&) = default; + NullableValue(NullableValue&&) = default ; /* NullableValue(const NullableValue& original); // Create a nullable object having the value of the specified // 'original' object. If 'TYPE' takes an optional allocator at @@ -395,6 +535,14 @@ class NullableValue : public std::pmr::optional // reference providing modifiable access to the underlying 'TYPE' // object. + template + TYPE& makeValueInplace(_Args&&... __args) + { + this->emplace(std::forward<_Args>(__args)...); + return this->value(); + } + + template STREAM& bdexStreamIn(STREAM& stream, int version); // Assign to this object the value read from the specified input @@ -413,8 +561,27 @@ class NullableValue : public std::pmr::optional // the null value). // Provided by std::pmr::optional base class. - //TYPE& value(); - // Return a reference providing modifiable access to the underlying + // + + template + typename bsl::enable_if::value, + DUMMY>::type &value() { return optional_base::value().value;} + + template + typename bsl::enable_if::value), + DUMMY>::type & + value() { return optional_base::value();} + + + template + const typename bsl::enable_if::value, + DUMMY>::type& value() const { return optional_base::value().value;} + + template + const typename bsl::enable_if::value), + DUMMY>::type & + value() const { return optional_base::value();} + // Return a reference providing modifiable access to the underlying // 'TYPE' object. The behavior is undefined unless this object is // non-null. // Provided by std::pmr::optional base class. @@ -708,19 +875,29 @@ STREAM& NullableValue::bdexStreamIn(STREAM& stream, int version) // ------------------------- // CREATORS -template +/*template inline -NullableValue::NullableValue() -:std::pmr::optional(std::allocator_arg_t{}, +NullableValue::NullableValue(typename bsl::enable_if< + bslma::UsesBslmaAllocator::value, + void>::type * = 0) +:optional_base(std::allocator_arg_t{}, std::pmr::polymorphic_allocator( (std::pmr::memory_resource*)(bslma::Default::allocator(nullptr)))) { } +template +inline +NullableValue::NullableValue(typename bsl::enable_if< + !bslma::UsesBslmaAllocator::value, + void>::type * = 0) +{ +} +*/ template inline NullableValue::NullableValue(bslma::Allocator *basicAllocator) -: std::pmr::optional(std::allocator_arg_t{}, +: optional_base(std::allocator_arg_t{}, std::pmr::polymorphic_allocator( (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) { @@ -730,7 +907,7 @@ template inline NullableValue::NullableValue(const NullableValue& original, bslma::Allocator *basicAllocator) -: std::pmr::optional(std::allocator_arg_t{}, +: optional_base(std::allocator_arg_t{}, (std::pmr::polymorphic_allocator)( (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) { @@ -744,7 +921,7 @@ inline NullableValue::NullableValue( bslmf::MovableRef original, bslma::Allocator *basicAllocator) -: std::pmr::optional(std::allocator_arg_t{}, +: optional_base(std::allocator_arg_t{}, std::pmr::polymorphic_allocator( (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) { @@ -763,7 +940,7 @@ NullableValue::NullableValue( !bsl::is_convertible::value, void>::type *) -: std::pmr::optional(BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) +: optional_base(BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) { } @@ -775,7 +952,7 @@ NullableValue::NullableValue( bslma::Allocator *basicAllocator, typename bsl::enable_if::value, void>::type *) -: std::pmr::optional(std::allocator_arg_t{}, +: optional_base(std::allocator_arg_t{}, std::pmr::polymorphic_allocator((std::pmr::memory_resource*) (bslma::Default::allocator(basicAllocator))), BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) @@ -787,7 +964,7 @@ template inline NullableValue::NullableValue( const NullableValue& original) -: std::pmr::optional((std::pmr::optional)original) +: optional_base((std::pmr::optional)original) { } @@ -797,7 +974,7 @@ inline NullableValue::NullableValue( const NullableValue& original, bslma::Allocator *basicAllocator) -: std::pmr::optional(std::allocator_arg_t{}, +: optional_base(std::allocator_arg_t{}, std::pmr::polymorphic_allocator((std::pmr::memory_resource*) (bslma::Default::allocator(basicAllocator)))) { @@ -869,7 +1046,7 @@ template inline NullableValue& NullableValue::operator=(const NullableValue& rhs) { - std::pmr::optional::operator=(rhs); + optional_base::operator=(rhs); return *this; } @@ -878,8 +1055,8 @@ inline NullableValue& NullableValue::operator=(bslmf::MovableRef rhs) { - std::pmr::optional& rhs_base = rhs; - std::pmr::optional::operator=(MoveUtil::move(rhs_base)); + optional_base& rhs_base = rhs; + optional_base::operator=(MoveUtil::move(rhs_base)); return *this; } @@ -933,7 +1110,7 @@ TYPE& NullableValue::makeValue( BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value) { this->emplace(BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)); - return *(*this); + return this->value(); } template @@ -941,7 +1118,7 @@ inline TYPE& NullableValue::makeValue() { this->emplace(); - return *(*this); + return this->value(); } template diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp b/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp index 21c51e902e..5d961242a7 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp +++ b/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp @@ -48,7 +48,7 @@ using namespace bsl; namespace std { - template +/* template struct uses_allocator : true_type {}; template struct uses_allocator>, _Alloc> : true_type {}; @@ -60,7 +60,7 @@ struct uses_allocator : true_type {}; struct uses_allocator : true_type {}; template struct uses_allocator : true_type {}; -} +*/} // ============================================================================ // TEST PLAN diff --git a/groups/bdl/bdlb/pmroptional b/groups/bdl/bdlb/pmroptional index 6f5375f15e..3e6a582444 100644 --- a/groups/bdl/bdlb/pmroptional +++ b/groups/bdl/bdlb/pmroptional @@ -1,4 +1,4 @@ -// -*- C++ -*- +// <__pmroptional> -*- C++ -*- // Copyright (C) 2013-2018 Free Software Foundation, Inc. // @@ -22,7 +22,7 @@ // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // . -/** @file include/pmroptional +/** @file include/__pmroptional * This is an extension header. */ @@ -56,282 +56,280 @@ namespace pmr { #define __cpp_lib_pmroptional 201810 template - class optional; + class __pmroptional; + + + template + using optional = conditional_t>, + __pmroptional<_Tp> , std::optional<_Tp>>; - // Payload for optionals with non-trivial destructor. + + + // This class template manages construction/destruction of + // the contained value for a std::pmr::optional. template struct _Optional_payload { - constexpr _Optional_payload() noexcept : _M_empty() { } - - - template - constexpr - _Optional_payload(std::initializer_list<_Up> __il, - _Args&&... __args) - { - _M_construct(__il, std::forward<_Args>(__args)...); - } - - template - constexpr - _Optional_payload(memory_resource* __pmr, _Args&&... __args) - { - _M_pmr = __pmr; - _M_construct(std::forward<_Args>(__args)...); - } - - template - constexpr - _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, - _Args&&... __args) - { - - _M_pmr = __pmr; - _M_construct(__il, std::forward<_Args>(__args)...); - } + using _Stored_type = remove_const_t<_Tp>; + _Optional_payload() noexcept {}; - - constexpr + _Optional_payload(const _Optional_payload& __other) - { - _M_pmr = __other._M_pmr; + : _M_pmr(__other._M_pmr) + { if (__other._M_engaged) - this->_M_construct(__other._M_payload); + this->_M_construct(__other._M_get()); } - constexpr + _Optional_payload(_Optional_payload&& __other) - { - _M_pmr = __other._M_pmr; + : _M_pmr(__other._M_pmr) + { if (__other._M_engaged) - this->_M_construct(std::move(__other._M_payload)); + this->_M_construct(std::move(__other._M_get())); } _Optional_payload& operator=(const _Optional_payload& __other) - { - if (this->_M_engaged && __other._M_engaged) - this->_M_get() = __other._M_get(); - else { - if (__other._M_engaged) - this->_M_construct(__other._M_get()); - else - this->_M_reset(); + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = __other._M_get(); + else + { + if (__other._M_engaged) + this->_M_construct(__other._M_get()); + else + this->_M_reset(); } - return *this; - } - + return *this; + } + + _Optional_payload& operator=(_Optional_payload&& __other) - noexcept(__and_v, - is_nothrow_move_assignable<_Tp>>) - { + noexcept(__and_v, + is_nothrow_move_assignable<_Tp>>) + { if (this->_M_engaged && __other._M_engaged) this->_M_get() = std::move(__other._M_get()); else { - if (__other._M_engaged) - this->_M_construct(std::move(__other._M_get())); - else - this->_M_reset(); + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_get())); + else + this->_M_reset(); } return *this; - } - - using _Stored_type = remove_const_t<_Tp>; + } struct _Empty_byte { }; - union { - _Empty_byte _M_empty; - _Stored_type _M_payload; - }; - bool _M_engaged = false; - memory_resource* _M_pmr = nullptr; + template + union _Storage + { + constexpr _Storage() noexcept : _M_empty() { } + +/* template + constexpr + _Storage(_Args&&... __args) + : _Storage(std::in_place, std::forward<_Args>( __args)...) + { } + + template + constexpr + _Storage(in_place_t,_Args&&... __args) + : _M_value(std::forward<_Args>(__args)...) + { } + + template + constexpr + _Storage(std::initializer_list<_Vp> __il, _Args&&... __args) + : _M_value(__il, std::forward<_Args>(__args)...) + { } + */ + // User-provided destructor is needed when _Up has non-trivial dtor. + ~_Storage() { } + _Empty_byte _M_empty; + _Up _M_value; + }; - ~_Optional_payload() - { - if (_M_engaged) - _M_payload.~_Stored_type(); - } + _Storage<_Stored_type> _M_payload; + + bool _M_engaged = false; + memory_resource* _M_pmr = std::pmr::get_default_resource(); template void _M_construct(_Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - if (_M_pmr) - { - __uses_allocator_construct(polymorphic_allocator<_Stored_type>(_M_pmr), - std::__addressof(this->_M_payload), + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + __uses_allocator_construct(polymorphic_allocator(_M_pmr), + std::__addressof(this->_M_payload._M_value), std::forward<_Args>(__args)...); - } - else - { - ::new ((void *) std::__addressof(this->_M_payload)) - _Stored_type(std::forward<_Args>(__args)...); - } - this->_M_engaged = true; + this->_M_engaged = true; } + + + + constexpr void + _M_destroy() noexcept + { + _M_engaged = false; + _M_payload._M_value.~_Stored_type(); + } + + // The _M_get() operations have _M_engaged as a precondition. + // They exist to access the contained value with the appropriate + // const-qualification, because _M_payload has had the const removed. - // The _M_get operations have _M_engaged as a precondition. constexpr _Tp& _M_get() noexcept - { return this->_M_payload; } + { return this->_M_payload._M_value; } constexpr const _Tp& _M_get() const noexcept - { return this->_M_payload; } + { return this->_M_payload._M_value; } // _M_reset is a 'safe' operation with no precondition. - void + constexpr void _M_reset() noexcept { if (this->_M_engaged) - { - this->_M_engaged = false; - this->_M_payload.~_Stored_type(); - } - } - }; - - template - class _Optional_base_impl - { - protected: - using _Stored_type = remove_const_t<_Tp>; - - // The _M_construct operation has !_M_engaged as a precondition - // while _M_destruct has _M_engaged as a precondition. - - template - void - _M_construct(_Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - if (static_cast<_Dp*>(this)->_M_payload._M_pmr) - { - __uses_allocator_construct(polymorphic_allocator(static_cast<_Dp*>(this)->_M_payload._M_pmr), - std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload), - std::forward<_Args>(__args)...); - } - else - { - ::new - (std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload)) - _Stored_type(std::forward<_Args>(__args)...); - } - static_cast<_Dp*>(this)->_M_payload._M_engaged = true; - } - - void - _M_destruct() noexcept - { - static_cast<_Dp*>(this)->_M_payload._M_engaged = false; - static_cast<_Dp*>(this)->_M_payload._M_payload.~_Stored_type(); + _M_destroy(); } - // _M_reset is a 'safe' operation with no precondition. - void - _M_reset() noexcept - { - if (static_cast<_Dp*>(this)->_M_payload._M_engaged) - static_cast<_Dp*>(this)->_M_destruct(); - } + // Destructor needs to destroy the contained value: + ~_Optional_payload() { this->_M_reset(); } + }; - void _M_set_allocator(memory_resource* __pmr) noexcept - { - static_cast<_Dp*>(this)->_M_payload._M_pmr = __pmr; - } - memory_resource* _M_get_allocator() noexcept - { - return static_cast<_Dp*>(this)->_M_payload._M_pmr; - } - }; - /** - * @brief Class template that takes care of copy/move constructors - of optional - * - * Such a separate base class template is necessary in order to - * conditionally make copy/move constructors trivial. - * @see optional, _Enable_special_members - */ - template - class _Optional_base - // protected inheritance because optional needs to reach that base too - : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> - { - friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; - - public: - // Constructors for disengaged optionals. - constexpr _Optional_base() = default; - - // Constructors for engaged optionals. - template, _Args&&...>, bool> = false> - constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) - : _M_payload(__pmr, - std::forward<_Args>(__args)...) { } - - - // Copy and move constructors. - constexpr _Optional_base(const _Optional_base& __other) + * @brief Class template that takes care of copy/move constructors + of optional + * + * Such a separate base class template is necessary in order to + * conditionally make copy/move constructors trivial. + * @see optional, _Enable_special_members + */ + template + class _Optional_base + { + using _Stored_type = remove_const_t<_Tp>; + + public: + // Constructors for disengaged optionals. + constexpr _Optional_base() = default; + + // Constructors for engaged optionals. + template, bool> = false> + constexpr explicit _Optional_base(in_place_t, _Args&&... __args) + { + _M_construct(std::forward<_Args>(__args)...); + } + + template&, + _Args&&...>, bool> = false> + constexpr explicit _Optional_base(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + { + _M_construct(__il,std::forward<_Args>(__args)...); + } + + + // Constructors for engaged optionals. + template, _Args&&...>, bool> = false> + constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) + { + _M_payload._M_pmr = __pmr; + _M_construct(std::forward<_Args>(__args)...); + } + + // Copy and move constructors. + constexpr _Optional_base(const _Optional_base& __other) : _M_payload(__other._M_payload) - { } + { } - constexpr _Optional_base(_Optional_base&& __other) - noexcept(is_nothrow_move_constructible_v<_Tp>) + + constexpr _Optional_base(_Optional_base&& __other) + noexcept(is_nothrow_move_constructible_v<_Tp>) : _M_payload(std::move(__other._M_payload)) - { } - - // Assignment operators. - _Optional_base& operator=(const _Optional_base&) = default; - _Optional_base& operator=(_Optional_base&&) = default; - - protected: - - constexpr bool _M_is_engaged() const noexcept - { return this->_M_payload._M_engaged; } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& + { } + + // Assignment operators. + _Optional_base& operator=(const _Optional_base&) = default; + _Optional_base& operator=(_Optional_base&&) = default; + + protected: + // The _M_construct operation has !_M_engaged as a precondition + // while _M_destruct has _M_engaged as a precondition. + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + _M_payload._M_construct( + std::forward<_Args>(__args)...); + } + + void + _M_destruct() noexcept + {_M_payload._M_destroy(); } + + // _M_reset is a 'safe' operation with no precondition. + constexpr void + _M_reset() noexcept + { _M_payload._M_reset(); } + + constexpr bool _M_is_engaged() const noexcept + { return this->_M_payload._M_engaged; } + + // The _M_get operations have _M_engaged as a precondition. + constexpr _Tp& _M_get() noexcept - { + { __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } - - constexpr const _Tp& + return this->_M_payload._M_get(); + } + + constexpr const _Tp& _M_get() const noexcept - { + { __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } - - private: - _Optional_payload<_Tp> _M_payload; - }; + return this->_M_payload._M_get(); + } + + void _M_set_allocator(memory_resource* __pmr) noexcept + { + _M_payload._M_pmr = __pmr; + } - template - class optional; + memory_resource* _M_get_allocator() const noexcept + { + return _M_payload._M_pmr; + } + + private: + _Optional_payload<_Tp> _M_payload; + }; + template using __converts_from_optional = - __or_&>, - is_constructible<_Tp, optional<_Up>&>, - is_constructible<_Tp, const optional<_Up>&&>, - is_constructible<_Tp, optional<_Up>&&>, - is_convertible&, _Tp>, - is_convertible&, _Tp>, - is_convertible&&, _Tp>, - is_convertible&&, _Tp>, + __or_&>, + is_constructible<_Tp, __pmroptional<_Up>&>, + is_constructible<_Tp, const __pmroptional<_Up>&&>, + is_constructible<_Tp, __pmroptional<_Up>&&>, + is_convertible&, _Tp>, + is_convertible<__pmroptional<_Up>&, _Tp>, + is_convertible&&, _Tp>, + is_convertible<__pmroptional<_Up>&&, _Tp>, is_constructible<_Tp, const std::optional<_Up>&>, is_constructible<_Tp, std::optional<_Up>&>, is_constructible<_Tp, const std::optional<_Up>&&>, @@ -343,33 +341,21 @@ namespace pmr { template using __assigns_from_optional = - __or_&>, - is_assignable<_Tp&, optional<_Up>&>, - is_assignable<_Tp&, const optional<_Up>&&>, - is_assignable<_Tp&, optional<_Up>&&>, + __or_&>, + is_assignable<_Tp&, __pmroptional<_Up>&>, + is_assignable<_Tp&, const __pmroptional<_Up>&&>, + is_assignable<_Tp&, __pmroptional<_Up>&&>, is_assignable<_Tp&, const std::optional<_Up>&>, is_assignable<_Tp&, std::optional<_Up>&>, is_assignable<_Tp&, const std::optional<_Up>&&>, is_assignable<_Tp&, std::optional<_Up>&&>>; - /* - template - struct __has_allocator_type - { - using __alloc_param_type = __nonesuch; - }; - template - struct __has_allocator_type<_Tp, __void_t> - { - using __alloc_param_type = - typename __remove_cvref_t<_Tp>::allocator_type; - }; - */ + /** * @brief Class template for optional values. */ template - class optional + class __pmroptional : private _Optional_base<_Tp>, private _Enable_copy_move< // Copy constructor. @@ -381,439 +367,427 @@ namespace pmr { // Move assignment. __and_v, is_move_assignable<_Tp>>, // Unique tag type. - optional<_Tp>> + __pmroptional<_Tp>> { static_assert(!is_same_v, nullopt_t>); + static_assert(!is_same_v, allocator_arg_t>); static_assert(!is_reference_v<_Tp>); - - template friend class optional; + template friend class __pmroptional; + private: using _Base = _Optional_base<_Tp>; // SFINAE helpers template - using __not_self = __not_>>; + using __not_self = __not_>>; + template + using __not_tag = __not_>>; template using _Requires = enable_if_t<__and_v<_Cond...>, bool>; + public: - /* - using __alloc_param_type = - typename __has_allocator_type<_Tp>::__alloc_param_type; - */ using value_type = _Tp; using __Allocator_type = std::pmr::polymorphic_allocator; - - constexpr optional() - { + + constexpr __pmroptional() noexcept { } - constexpr optional(nullopt_t) noexcept { } + constexpr __pmroptional(nullopt_t) noexcept { } + + + // Converting constructors for engaged optionals. - template, - __not_>>>, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>> = true> - constexpr - optional(_Up&& __t) - { emplace(std::forward<_Up>(__t)); - }; - - template, - __not_>>>, - is_constructible<_Tp, _Up&&>, - __not_>> = false> - explicit constexpr - optional(_Up&& __t) - { emplace(std::forward<_Up>(__t)); - }; - - template>, - is_constructible<_Tp, const _Up&>, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(const optional<_Up>& __t) - { - this->_M_set_allocator(__t._M_get_allocator()); - if (__t) - emplace(*__t); - } - - template>, - is_constructible<_Tp, const _Up&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(const optional<_Up>& __t) - { - this->_M_set_allocator(__t._M_get_allocator()); - if (__t) - emplace(*__t); - } - - template >, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(optional<_Up>&& __t) - { - this->_M_set_allocator(__t._M_get_allocator()); - if (__t) - emplace(std::move(*__t)); - } - - template >, - is_constructible<_Tp, _Up&&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(optional<_Up>&& __t) - { - this->_M_set_allocator(__t._M_get_allocator()); - if (__t) - emplace(std::move(*__t)); - } - - template>, - is_constructible<_Tp, const _Up&>, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(const std::optional<_Up>& __t) - { - this->_M_set_allocator(__t._M_get_allocator()); - if (__t) - emplace(*__t); - } - - template>, - is_constructible<_Tp, const _Up&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> + template, __not_tag<_Up>, + __not_>>>, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>> = true> + constexpr + __pmroptional(_Up&& __t) + { emplace(std::forward<_Up>(__t)); + }; + + template, __not_tag<_Up>, + __not_>>>, + is_constructible<_Tp, _Up&&>, + __not_>> = false> + explicit constexpr + __pmroptional(_Up&& __t) + { emplace(std::forward<_Up>(__t)); + }; + + template>, + is_constructible<_Tp, const _Up&>, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(const __pmroptional<_Up>& __t) + { + this->_M_set_allocator(__t._M_get_allocator()); + if (__t) + emplace(*__t); + } + + template>, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(const __pmroptional<_Up>& __t) + { + this->_M_set_allocator(__t._M_get_allocator()); + if (__t) + emplace(*__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(__pmroptional<_Up>&& __t) + { + this->_M_set_allocator(__t._M_get_allocator()); + if (__t) + emplace(std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(__pmroptional<_Up>&& __t) + { + this->_M_set_allocator(__t._M_get_allocator()); + if (__t) + emplace(std::move(*__t)); + } + + template, + is_convertible> = true> + constexpr + __pmroptional(const std::optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template, + __not_>> = false> + explicit constexpr + __pmroptional(const std::optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template , + is_convertible<_Up&&, _Tp>> = true> + constexpr + __pmroptional(std::optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + template , + __not_>> = false> + explicit constexpr + __pmroptional(std::optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + template> = false> explicit constexpr - optional(const std::optional<_Up>& __t) - { - this->_M_set_allocator(__t._M_get_allocator()); - if (__t) - emplace(*__t); - } + __pmroptional(in_place_t, _Args&&... __args) + : _Base(std::in_place, std::forward<_Args>(__args)...) { } - template >, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(std::optional<_Up>&& __t) - { - this->_M_set_allocator(__t._M_get_allocator()); - if (__t) - emplace(std::move(*__t)); - } - - template >, - is_constructible<_Tp, _Up&&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> + template&, + _Args&&...>> = false> explicit constexpr - optional(std::optional<_Up>&& __t) - { - this->_M_set_allocator(__t._M_get_allocator()); - if (__t) - emplace(std::move(*__t)); - } - - constexpr - optional(const std::optional<_Tp>& __t) - { - this->_M_set_allocator(__t._M_get_allocator()); - if (__t) - emplace(*__t); - } + __pmroptional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) + : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { } - constexpr - optional(std::optional<_Tp>&& __t) - { - this->_M_set_allocator(__t._M_get_allocator()); - if (__t) - emplace(std::move(*__t)); - } // Converting memory-resource-constructors for engaged optionals. - optional(allocator_arg_t, const __Allocator_type& __a) - { - this->_M_set_allocator(__a.resource()); - } - template, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>> = true> - constexpr - optional(allocator_arg_t, const __Allocator_type& __a,_Up&& __t) - { - this->_M_set_allocator(__a.resource()); - emplace(std::forward<_Up>(__t)); - } - - template, - is_constructible<_Tp, _Up&&>, - __not_>> = false> - explicit constexpr - optional(allocator_arg_t, const __Allocator_type& __a, _Up&& __t) - { - this->_M_set_allocator(__a.resource()); - emplace(std::forward<_Up>(__t)); - } - - template>, - is_constructible<_Tp, const _Up&>, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(allocator_arg_t, const __Allocator_type& __a, const optional<_Up>& __t) - { - this->_M_set_allocator(__a.resource()); - emplace(*__t); - } - - template>, - is_constructible<_Tp, const _Up&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(allocator_arg_t, const __Allocator_type& __a, const optional<_Up>& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(*__t); - } - - template >, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(allocator_arg_t, const __Allocator_type& __a, optional<_Up>&& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(std::move(*__t)); - } - - template >, - is_constructible<_Tp, _Up&&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(allocator_arg_t, const __Allocator_type& __a, optional<_Up>&& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(std::move(*__t)); - } - - constexpr - optional(allocator_arg_t, const __Allocator_type& __a, const optional& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(*__t); - } - - constexpr - optional(allocator_arg_t, const __Allocator_type& __a, optional&& __t) - { - memory_resource* __actual_alloc = __a.resource(); - if (__t) - emplace(std::move(*__t)); - } - - template, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(allocator_arg_t, const __Allocator_type& __a, const std::optional<_Up>& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(*__t); - } - - template, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(allocator_arg_t, const __Allocator_type& __a, const std::optional<_Up>& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(*__t); - } - - template , - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(allocator_arg_t, const __Allocator_type& __a, std::optional<_Up>&& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(std::move(*__t)); - } - - template , - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(allocator_arg_t, const __Allocator_type& __a, std::optional<_Up>&& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(std::move(*__t)); - } - - + __pmroptional(allocator_arg_t, const __Allocator_type& __a) + { + this->_M_set_allocator(__a.resource()); + } + template, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>> = true> + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a,_Up&& __t) + { + this->_M_set_allocator(__a.resource()); + emplace(std::forward<_Up>(__t)); + } + + template, + is_constructible<_Tp, _Up&&>, + __not_>> = false> + explicit constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, _Up&& __t) + { + this->_M_set_allocator(__a.resource()); + emplace(std::forward<_Up>(__t)); + } + + template>, + is_constructible<_Tp, const _Up&>, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional<_Up>& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(*__t); + } + + template>, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional<_Up>& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(*__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional<_Up>&& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional<_Up>&& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(std::move(*__t)); + } + + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(*__t); + } + + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional&& __t) + { + memory_resource* __actual_alloc = __a.resource(); + if (__t) + emplace(std::move(*__t)); + } + + template, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional<_Up>& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(*__t); + } + + template, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional<_Up>& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(*__t); + } + + template , + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional<_Up>&& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(std::move(*__t)); + } + + template , + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional<_Up>&& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(std::move(*__t)); + } // Assignment operators. - optional& + __pmroptional& operator=(nullopt_t) noexcept { this->_M_reset(); return *this; } - + + template - enable_if_t<__and_v<__not_self<_Up>, - __not_<__and_, - is_same<_Tp, decay_t<_Up>>>>, - is_constructible<_Tp, _Up>, - is_assignable<_Tp&, _Up>>, - optional&> - operator=(_Up&& __u) - { - if (this->_M_is_engaged()) - this->_M_get() = std::forward<_Up>(__u); - else - this->_M_construct(std::forward<_Up>(__u)); - - return *this; - } - - template - enable_if_t<__and_v<__not_>, - is_constructible<_Tp, const _Up&>, - is_assignable<_Tp&, _Up>, - __not_<__converts_from_optional<_Tp, _Up>>, - __not_<__assigns_from_optional<_Tp, _Up>>>, - optional&> - operator=(const optional<_Up>& __u) - { - if (__u) - { - if (this->_M_is_engaged()) - this->_M_get() = *__u; - else - this->_M_construct(*__u); - } - else - { - this->_M_reset(); - } - return *this; - } - - template - enable_if_t<__and_v<__not_>, - is_constructible<_Tp, _Up>, - is_assignable<_Tp&, _Up>, - __not_<__converts_from_optional<_Tp, _Up>>, - __not_<__assigns_from_optional<_Tp, _Up>>>, - optional&> - operator=(optional<_Up>&& __u) - { - if (__u) - { - if (this->_M_is_engaged()) - this->_M_get() = std::move(*__u); - else - this->_M_construct(std::move(*__u)); - } - else - { - this->_M_reset(); - } - - return *this; - } - - template - enable_if_t<__and_v, - is_assignable<_Tp&, _Up>, - __not_<__converts_from_optional<_Tp, _Up>>, - __not_<__assigns_from_optional<_Tp, _Up>>>, - optional&> - operator=(const std::optional<_Up>& __u) - { - if (__u) - { - if (this->_M_is_engaged()) - this->_M_get() = *__u; - else - this->_M_construct(*__u); - } - else - { - this->_M_reset(); - } - return *this; - } - - template - enable_if_t<__and_v, - is_assignable<_Tp&, _Up>, - __not_<__converts_from_optional<_Tp, _Up>>, - __not_<__assigns_from_optional<_Tp, _Up>>>, - optional&> - operator=(std::optional<_Up>&& __u) - { - if (__u) - { - if (this->_M_is_engaged()) - this->_M_get() = std::move(*__u); - else - this->_M_construct(std::move(*__u)); - } - else - { - this->_M_reset(); - } - - return *this; - } - - + enable_if_t<__and_v<__not_self<_Up>, + __not_<__and_, + is_same<_Tp, decay_t<_Up>>>>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>>, + __pmroptional&> + operator=(_Up&& __u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::forward<_Up>(__u); + else + this->_M_construct(std::forward<_Up>(__u)); + + return *this; + } + + template + enable_if_t<__and_v<__not_>, + is_constructible<_Tp, const _Up&>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + __pmroptional&> + operator=(const __pmroptional<_Up>& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = *__u; + else + this->_M_construct(*__u); + } + else + { + this->_M_reset(); + } + return *this; + } + + template + enable_if_t<__and_v<__not_>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + __pmroptional&> + operator=(__pmroptional<_Up>&& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::move(*__u); + else + this->_M_construct(std::move(*__u)); + } + else + { + this->_M_reset(); + } + + return *this; + } + + template + enable_if_t<__and_v, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + __pmroptional&> + operator=(const __pmroptional<_Up>& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = *__u; + else + this->_M_construct(*__u); + } + else + { + this->_M_reset(); + } + return *this; + } + + template + enable_if_t<__and_v, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + __pmroptional&> + operator=(__pmroptional<_Up>&& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::move(*__u); + else + this->_M_construct(std::move(*__u)); + } + else + { + this->_M_reset(); + } + + return *this; + } + + template enable_if_t, _Tp&> emplace(_Args&&... __args) @@ -837,7 +811,7 @@ namespace pmr { // Swap. void - swap(optional& __other) + swap(__pmroptional& __other) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>) { @@ -862,7 +836,7 @@ namespace pmr { operator->() const { return std::__addressof(this->_M_get()); } - _Tp* + constexpr _Tp* operator->() { return std::__addressof(this->_M_get()); } @@ -892,36 +866,32 @@ namespace pmr { value() const& { return this->_M_is_engaged() - ? this->_M_get() - : (__throw_bad_optional_access(), - this->_M_get()); + ? this->_M_get() + : (__throw_bad_optional_access(), this->_M_get()); } constexpr _Tp& value()& { return this->_M_is_engaged() - ? this->_M_get() - : (__throw_bad_optional_access(), - this->_M_get()); + ? this->_M_get() + : (__throw_bad_optional_access(), this->_M_get()); } constexpr _Tp&& value()&& { return this->_M_is_engaged() - ? std::move(this->_M_get()) - : (__throw_bad_optional_access(), - std::move(this->_M_get())); + ? std::move(this->_M_get()) + : (__throw_bad_optional_access(), std::move(this->_M_get())); } constexpr const _Tp&& value() const&& { return this->_M_is_engaged() - ? std::move(this->_M_get()) - : (__throw_bad_optional_access(), - std::move(this->_M_get())); + ? std::move(this->_M_get()) + : (__throw_bad_optional_access(), std::move(this->_M_get())); } template @@ -932,12 +902,11 @@ namespace pmr { static_assert(is_convertible_v<_Up&&, _Tp>); return this->_M_is_engaged() - ? this->_M_get() - : static_cast<_Tp>(std::forward<_Up>(__u)); + ? this->_M_get() : static_cast<_Tp>(std::forward<_Up>(__u)); } template - _Tp + constexpr _Tp value_or(_Up&& __u) && { static_assert(is_move_constructible_v<_Tp>); @@ -949,19 +918,7 @@ namespace pmr { } void reset() noexcept { this->_M_reset(); } - - // bloomberg extensions start here - - - template - _Tp& makeValueInplace(_Args&&... __args) - { - return this->emplace(std::forward<_Args>(__args)...); - - } - - - }; +}; template using __optional_relop_t = @@ -1152,29 +1109,10 @@ namespace pmr { -> __optional_relop_t() >= declval<_Tp>())> { return !__rhs || __lhs >= *__rhs; } - - template - constexpr optional> - make_optional(_Tp&& __t) - { return optional> { std::forward<_Tp>(__t) }; } - - template - constexpr optional<_Tp> - make_optional(_Args&&... __args) - { return optional<_Tp> { in_place, std::forward<_Args>(__args)... }; } - - template - constexpr optional<_Tp> - make_optional(initializer_list<_Up> __il, _Args&&... __args) - { return optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; } - - - /// @} - #if __cpp_deduction_guides >= 201606 - template optional(_Tp) -> optional<_Tp>; + template __pmroptional(_Tp) -> __pmroptional<_Tp>; #endif -} // namespace pmr + // Swap and creation functions. // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -1189,7 +1127,26 @@ namespace pmr { enable_if_t && is_swappable_v<_Tp>)> swap(pmr::optional<_Tp>&, pmr::optional<_Tp>&) = delete; - // Hash. + template + constexpr pmr::optional> + make_optional(_Tp&& __t) + { return pmr::optional> { std::forward<_Tp>(__t) }; } + + template + constexpr pmr::optional<_Tp> + make_optional(_Args&&... __args) + { return pmr::optional<_Tp> { in_place, std::forward<_Args>(__args)... }; } + + template + constexpr pmr::optional<_Tp> + make_optional(initializer_list<_Up> __il, _Args&&... __args) + { return pmr::optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; } + + +} // namespace pmr +// Hash. + + template, bool = __poison_hash<_Up>::__enable_hash_call> struct __pmr_optional_hash_call_base @@ -1209,21 +1166,26 @@ namespace pmr { struct __pmr_optional_hash_call_base<_Tp, _Up, false> {}; template - struct hash> + struct hash> : private __poison_hash>, public __pmr_optional_hash_call_base<_Tp> { using result_type [[__deprecated__]] = size_t; - using argument_type [[__deprecated__]] = pmr::optional<_Tp>; + using argument_type [[__deprecated__]] = pmr::__pmroptional<_Tp>; }; template - struct __is_fast_hash>> : __is_fast_hash> + struct __is_fast_hash>> : __is_fast_hash> { }; + + + /// @} + + template - struct uses_allocator, _Alloc> : true_type {}; -_GLIBCXX_END_NAMESPACE_VERSION + struct uses_allocator, _Alloc> : true_type {}; + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++17 From 89c874880847c40806985cdeb900770481dbc6c7 Mon Sep 17 00:00:00 2001 From: nina Queen of Awesome Date: Fri, 2 Aug 2019 17:11:16 +0100 Subject: [PATCH 08/14] hooking-in uses_domain_allocator --- groups/bdl/bdlb/bdlb_nullablevalue.h | 67 +++--- groups/bdl/bdlb/memory_resource | 24 --- groups/bdl/bdlb/pmroptional | 291 ++++++++++++++++++--------- 3 files changed, 230 insertions(+), 152 deletions(-) diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.h b/groups/bdl/bdlb/bdlb_nullablevalue.h index cee9c8c480..53923f3917 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.h +++ b/groups/bdl/bdlb/bdlb_nullablevalue.h @@ -180,7 +180,19 @@ BSLS_IDENT("$Id: $") #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES - +namespace std { +template +struct __domain_allocator_traits::value, + std::pmr::polymorphic_allocator>::type > +: BloombergLP::bslma::UsesBslmaAllocator::type +{ + static BloombergLP::bslma::Allocator* rebind(std::pmr::polymorphic_allocator a) + { return dynamic_cast(a.resource()); + } +}; +} +/* template struct bb_optional_wrap : private std::_Enable_copy_move< // Copy constructor. @@ -310,7 +322,7 @@ namespace std template struct uses_allocator, _Alloc> : true_type {}; } - +*/ namespace BloombergLP { namespace bdlb { @@ -322,13 +334,9 @@ namespace bdlb { // class NullableValue // ========================= -template -using optional_base = std::conditional_t::value, - std::pmr::optional> , - std::pmr::optional >; template -class NullableValue : public optional_base +class NullableValue : public std::pmr::optional { // This template class extends the set of values of its value-semantic @@ -377,7 +385,7 @@ class NullableValue : public optional_base NullableValue(typename bsl::enable_if< bslma::UsesBslmaAllocator::value, void>::type * = 0) - :optional_base(std::allocator_arg_t{}, + :std::pmr::optional(std::allocator_arg_t{}, std::pmr::polymorphic_allocator( (std::pmr::memory_resource*)(bslma::Default::allocator(nullptr)))) { @@ -386,7 +394,7 @@ class NullableValue : public optional_base NullableValue(typename bsl::enable_if< !bslma::UsesBslmaAllocator::value, void>::type * = 0) - :optional_base() + :std::pmr::optional() { } // Create a nullable object having the null value. If 'TYPE' takes an @@ -563,24 +571,7 @@ class NullableValue : public optional_base // - template - typename bsl::enable_if::value, - DUMMY>::type &value() { return optional_base::value().value;} - - template - typename bsl::enable_if::value), - DUMMY>::type & - value() { return optional_base::value();} - - - template - const typename bsl::enable_if::value, - DUMMY>::type& value() const { return optional_base::value().value;} - - template - const typename bsl::enable_if::value), - DUMMY>::type & - value() const { return optional_base::value();} + //TYPE& value() // Return a reference providing modifiable access to the underlying // 'TYPE' object. The behavior is undefined unless this object is // non-null. @@ -880,7 +871,7 @@ inline NullableValue::NullableValue(typename bsl::enable_if< bslma::UsesBslmaAllocator::value, void>::type * = 0) -:optional_base(std::allocator_arg_t{}, +:std::pmr::optional(std::allocator_arg_t{}, std::pmr::polymorphic_allocator( (std::pmr::memory_resource*)(bslma::Default::allocator(nullptr)))) { @@ -897,7 +888,7 @@ NullableValue::NullableValue(typename bsl::enable_if< template inline NullableValue::NullableValue(bslma::Allocator *basicAllocator) -: optional_base(std::allocator_arg_t{}, +: std::pmr::optional(std::allocator_arg_t{}, std::pmr::polymorphic_allocator( (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) { @@ -907,7 +898,7 @@ template inline NullableValue::NullableValue(const NullableValue& original, bslma::Allocator *basicAllocator) -: optional_base(std::allocator_arg_t{}, +: std::pmr::optional(std::allocator_arg_t{}, (std::pmr::polymorphic_allocator)( (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) { @@ -921,7 +912,7 @@ inline NullableValue::NullableValue( bslmf::MovableRef original, bslma::Allocator *basicAllocator) -: optional_base(std::allocator_arg_t{}, +: std::pmr::optional(std::allocator_arg_t{}, std::pmr::polymorphic_allocator( (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) { @@ -940,7 +931,7 @@ NullableValue::NullableValue( !bsl::is_convertible::value, void>::type *) -: optional_base(BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) +: std::pmr::optional(BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) { } @@ -952,7 +943,7 @@ NullableValue::NullableValue( bslma::Allocator *basicAllocator, typename bsl::enable_if::value, void>::type *) -: optional_base(std::allocator_arg_t{}, +: std::pmr::optional(std::allocator_arg_t{}, std::pmr::polymorphic_allocator((std::pmr::memory_resource*) (bslma::Default::allocator(basicAllocator))), BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) @@ -964,7 +955,7 @@ template inline NullableValue::NullableValue( const NullableValue& original) -: optional_base((std::pmr::optional)original) +: std::pmr::optional((std::pmr::optional)original) { } @@ -974,7 +965,7 @@ inline NullableValue::NullableValue( const NullableValue& original, bslma::Allocator *basicAllocator) -: optional_base(std::allocator_arg_t{}, +: std::pmr::optional(std::allocator_arg_t{}, std::pmr::polymorphic_allocator((std::pmr::memory_resource*) (bslma::Default::allocator(basicAllocator)))) { @@ -1046,7 +1037,7 @@ template inline NullableValue& NullableValue::operator=(const NullableValue& rhs) { - optional_base::operator=(rhs); + std::pmr::optional::operator=(rhs); return *this; } @@ -1055,8 +1046,8 @@ inline NullableValue& NullableValue::operator=(bslmf::MovableRef rhs) { - optional_base& rhs_base = rhs; - optional_base::operator=(MoveUtil::move(rhs_base)); + std::pmr::optional& rhs_base = rhs; + std::pmr::optional::operator=(MoveUtil::move(rhs_base)); return *this; } diff --git a/groups/bdl/bdlb/memory_resource b/groups/bdl/bdlb/memory_resource index 625a10af2c..7f1f0ca5e9 100644 --- a/groups/bdl/bdlb/memory_resource +++ b/groups/bdl/bdlb/memory_resource @@ -126,18 +126,6 @@ namespace pmr operator!=(const memory_resource& __a, const memory_resource& __b) noexcept { return !(__a == __b); } - template - struct __is_dynamic_castable - { - static constexpr bool value=false; - }; - template - struct __is_dynamic_castable<_Tp, _Up, - void_t(declval<_Up>()))>> - { - static constexpr bool value=true; - }; - // C++17 23.12.3 Class template polymorphic_allocator template @@ -335,18 +323,6 @@ namespace pmr select_on_container_copy_construction() const noexcept { return polymorphic_allocator(); } - template ::value - && !is_same_v<_Target, memory_resource>>> - operator _Target*() const - { - memory_resource* res = resource(); - _Target& ret = dynamic_cast<_Target&>(*res); - return &ret; - } - memory_resource* resource() const noexcept __attribute__((__returns_nonnull__)) diff --git a/groups/bdl/bdlb/pmroptional b/groups/bdl/bdlb/pmroptional index 3e6a582444..342abe9b52 100644 --- a/groups/bdl/bdlb/pmroptional +++ b/groups/bdl/bdlb/pmroptional @@ -60,7 +60,8 @@ namespace pmr { template - using optional = conditional_t>, + using optional = conditional_t<__or_>, + __uses_domain_allocator<_Tp,polymorphic_allocator>>::value, __pmroptional<_Tp> , std::optional<_Tp>>; @@ -396,7 +397,8 @@ namespace pmr { constexpr __pmroptional(nullopt_t) noexcept { } - + __pmroptional(const __pmroptional&) = default; + __pmroptional(__pmroptional&&) = default; // Converting constructors for engaged optionals. @@ -474,7 +476,8 @@ namespace pmr { template, - is_convertible> = true> + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> constexpr __pmroptional(const std::optional<_Up>& __t) { @@ -484,7 +487,8 @@ namespace pmr { template, - __not_>> = false> + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> explicit constexpr __pmroptional(const std::optional<_Up>& __t) { @@ -494,7 +498,8 @@ namespace pmr { template , - is_convertible<_Up&&, _Tp>> = true> + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> constexpr __pmroptional(std::optional<_Up>&& __t) { @@ -504,7 +509,8 @@ namespace pmr { template , - __not_>> = false> + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> explicit constexpr __pmroptional(std::optional<_Up>&& __t) { @@ -676,7 +682,10 @@ namespace pmr { this->_M_reset(); return *this; } - + + // Assignment operators. + __pmroptional& operator=(const __pmroptional&) = default; + __pmroptional& operator=(__pmroptional&&) = default; template enable_if_t<__and_v<__not_self<_Up>, @@ -742,51 +751,52 @@ namespace pmr { return *this; } - template - enable_if_t<__and_v, - is_assignable<_Tp&, _Up>, - __not_<__converts_from_optional<_Tp, _Up>>, - __not_<__assigns_from_optional<_Tp, _Up>>>, - __pmroptional&> - operator=(const __pmroptional<_Up>& __u) - { - if (__u) - { - if (this->_M_is_engaged()) - this->_M_get() = *__u; - else - this->_M_construct(*__u); - } - else - { - this->_M_reset(); - } - return *this; - } - - template - enable_if_t<__and_v, - is_assignable<_Tp&, _Up>, - __not_<__converts_from_optional<_Tp, _Up>>, - __not_<__assigns_from_optional<_Tp, _Up>>>, - __pmroptional&> - operator=(__pmroptional<_Up>&& __u) - { - if (__u) - { - if (this->_M_is_engaged()) - this->_M_get() = std::move(*__u); - else - this->_M_construct(std::move(*__u)); - } - else - { - this->_M_reset(); - } - - return *this; - } + + template + enable_if_t<__and_v, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + __pmroptional&> + operator=(const std::optional<_Up>& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = *__u; + else + this->_M_construct(*__u); + } + else + { + this->_M_reset(); + } + return *this; + } + + template + enable_if_t<__and_v, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + __pmroptional&> + operator=(std::optional<_Up>&& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::move(*__u); + else + this->_M_construct(std::move(*__u)); + } + else + { + this->_M_reset(); + } + + return *this; + } template enable_if_t, _Tp&> @@ -927,7 +937,7 @@ namespace pmr { // Comparisons between optional values. template constexpr auto - operator==(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + operator==(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() == declval<_Up>())> { return static_cast(__lhs) == static_cast(__rhs) @@ -936,7 +946,7 @@ namespace pmr { template constexpr auto - operator!=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + operator!=(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() != declval<_Up>())> { return static_cast(__lhs) != static_cast(__rhs) @@ -945,7 +955,7 @@ namespace pmr { template constexpr auto - operator<(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + operator<(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() < declval<_Up>())> { return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); @@ -953,7 +963,7 @@ namespace pmr { template constexpr auto - operator>(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + operator>(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() > declval<_Up>())> { return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); @@ -961,7 +971,7 @@ namespace pmr { template constexpr auto - operator<=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + operator<=(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() <= declval<_Up>())> { return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); @@ -969,143 +979,244 @@ namespace pmr { template constexpr auto - operator>=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + operator>=(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() >= declval<_Up>())> { return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs); } + + template + constexpr auto + operator==(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() == declval<_Up>())> + { + return static_cast(__lhs) == static_cast(__rhs) + && (!__lhs || *__lhs == *__rhs); + } + + template + constexpr auto + operator!=(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() != declval<_Up>())> + { + return static_cast(__lhs) != static_cast(__rhs) + || (static_cast(__lhs) && *__lhs != *__rhs); + } + + template + constexpr auto + operator<(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { + return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); + } + + template + constexpr auto + operator>(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { + return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); + } + + template + constexpr auto + operator<=(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { + return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); + } + + template + constexpr auto + operator>=(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { + return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs); + } + + + template + constexpr auto + operator==(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() == declval<_Up>())> + { + return static_cast(__lhs) == static_cast(__rhs) + && (!__lhs || *__lhs == *__rhs); + } + + template + constexpr auto + operator!=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() != declval<_Up>())> + { + return static_cast(__lhs) != static_cast(__rhs) + || (static_cast(__lhs) && *__lhs != *__rhs); + } + + template + constexpr auto + operator<(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { + return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); + } + + template + constexpr auto + operator>(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { + return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); + } + + template + constexpr auto + operator<=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { + return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); + } + + template + constexpr auto + operator>=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { + return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs); + } // Comparisons with nullopt. template constexpr bool - operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept + operator==(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return !__lhs; } template constexpr bool - operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept + operator==(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return !__rhs; } template constexpr bool - operator!=(const optional<_Tp>& __lhs, nullopt_t) noexcept + operator!=(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return static_cast(__lhs); } template constexpr bool - operator!=(nullopt_t, const optional<_Tp>& __rhs) noexcept + operator!=(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return static_cast(__rhs); } template constexpr bool - operator<(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept + operator<(const __pmroptional<_Tp>& /* __lhs */, nullopt_t) noexcept { return false; } template constexpr bool - operator<(nullopt_t, const optional<_Tp>& __rhs) noexcept + operator<(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return static_cast(__rhs); } template constexpr bool - operator>(const optional<_Tp>& __lhs, nullopt_t) noexcept + operator>(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return static_cast(__lhs); } template constexpr bool - operator>(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept + operator>(nullopt_t, const __pmroptional<_Tp>& /* __rhs */) noexcept { return false; } template constexpr bool - operator<=(const optional<_Tp>& __lhs, nullopt_t) noexcept + operator<=(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return !__lhs; } template constexpr bool - operator<=(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept + operator<=(nullopt_t, const __pmroptional<_Tp>& /* __rhs */) noexcept { return true; } template constexpr bool - operator>=(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept + operator>=(const __pmroptional<_Tp>& /* __lhs */, nullopt_t) noexcept { return true; } template constexpr bool - operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept + operator>=(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return !__rhs; } // Comparisons with value type. template constexpr auto - operator==(const optional<_Tp>& __lhs, const _Up& __rhs) + operator==(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() == declval<_Up>())> { return __lhs && *__lhs == __rhs; } template constexpr auto - operator==(const _Up& __lhs, const optional<_Tp>& __rhs) + operator==(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() == declval<_Tp>())> { return __rhs && __lhs == *__rhs; } template constexpr auto - operator!=(const optional<_Tp>& __lhs, const _Up& __rhs) + operator!=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() != declval<_Up>())> { return !__lhs || *__lhs != __rhs; } template constexpr auto - operator!=(const _Up& __lhs, const optional<_Tp>& __rhs) + operator!=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() != declval<_Tp>())> { return !__rhs || __lhs != *__rhs; } template constexpr auto - operator<(const optional<_Tp>& __lhs, const _Up& __rhs) + operator<(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() < declval<_Up>())> { return !__lhs || *__lhs < __rhs; } template constexpr auto - operator<(const _Up& __lhs, const optional<_Tp>& __rhs) + operator<(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() < declval<_Tp>())> { return __rhs && __lhs < *__rhs; } template constexpr auto - operator>(const optional<_Tp>& __lhs, const _Up& __rhs) + operator>(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() > declval<_Up>())> { return __lhs && *__lhs > __rhs; } template constexpr auto - operator>(const _Up& __lhs, const optional<_Tp>& __rhs) + operator>(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() > declval<_Tp>())> { return !__rhs || __lhs > *__rhs; } template constexpr auto - operator<=(const optional<_Tp>& __lhs, const _Up& __rhs) + operator<=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() <= declval<_Up>())> { return !__lhs || *__lhs <= __rhs; } template constexpr auto - operator<=(const _Up& __lhs, const optional<_Tp>& __rhs) + operator<=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() <= declval<_Tp>())> { return __rhs && __lhs <= *__rhs; } template constexpr auto - operator>=(const optional<_Tp>& __lhs, const _Up& __rhs) + operator>=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() >= declval<_Up>())> { return __lhs && *__lhs >= __rhs; } template constexpr auto - operator>=(const _Up& __lhs, const optional<_Tp>& __rhs) + operator>=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() >= declval<_Tp>())> { return !__rhs || __lhs >= *__rhs; } @@ -1119,28 +1230,28 @@ namespace pmr { // 2748. swappable traits for optionals template inline enable_if_t && is_swappable_v<_Tp>> - swap(pmr::optional<_Tp>& __lhs, pmr::optional<_Tp>& __rhs) + swap(__pmroptional<_Tp>& __lhs, __pmroptional<_Tp>& __rhs) noexcept(noexcept(__lhs.swap(__rhs))) { __lhs.swap(__rhs); } template enable_if_t && is_swappable_v<_Tp>)> - swap(pmr::optional<_Tp>&, pmr::optional<_Tp>&) = delete; + swap(__pmroptional<_Tp>&, __pmroptional<_Tp>&) = delete; template - constexpr pmr::optional> + constexpr optional> make_optional(_Tp&& __t) - { return pmr::optional> { std::forward<_Tp>(__t) }; } + { return optional> { std::forward<_Tp>(__t) }; } template - constexpr pmr::optional<_Tp> + constexpr optional<_Tp> make_optional(_Args&&... __args) - { return pmr::optional<_Tp> { in_place, std::forward<_Args>(__args)... }; } + { return optional<_Tp> { in_place, std::forward<_Args>(__args)... }; } template - constexpr pmr::optional<_Tp> + constexpr optional<_Tp> make_optional(initializer_list<_Up> __il, _Args&&... __args) - { return pmr::optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; } + { return optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; } } // namespace pmr @@ -1152,7 +1263,7 @@ namespace pmr { struct __pmr_optional_hash_call_base { size_t - operator()(const pmr::optional<_Tp>& __t) const + operator()(const pmr::__pmroptional<_Tp>& __t) const noexcept(noexcept(hash<_Up>{}(*__t))) { // We pick an arbitrary hash for disengaged optionals which hopefully From cfe67f14251c9385dd2b92ddbc85158aba3aebe3 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Wed, 14 Aug 2019 14:58:07 +0300 Subject: [PATCH 09/14] Further bug-fixes for NullableValue and its tests --- groups/bdl/bdlb/bdlb_nullablevalue.h | 1250 ++++++++++- groups/bdl/bdlb/bdlb_nullablevalue.t.cpp | 6 +- groups/bdl/bdlb/memory_resource | 24 - groups/bdl/bdlb/pmroptional | 2607 +++++++--------------- groups/bdl/bdls/bdls_testutil.t.cpp | 8 +- groups/bsl/bslim/bslim_testutil.t.cpp | 4 +- 6 files changed, 1969 insertions(+), 1930 deletions(-) diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.h b/groups/bdl/bdlb/bdlb_nullablevalue.h index f196d7cdfe..53923f3917 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.h +++ b/groups/bdl/bdlb/bdlb_nullablevalue.h @@ -180,130 +180,1155 @@ BSLS_IDENT("$Id: $") #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES +namespace std { +template +struct __domain_allocator_traits::value, + std::pmr::polymorphic_allocator>::type > +: BloombergLP::bslma::UsesBslmaAllocator::type +{ + static BloombergLP::bslma::Allocator* rebind(std::pmr::polymorphic_allocator a) + { return dynamic_cast(a.resource()); + } +}; +} +/* +template +struct bb_optional_wrap : private std::_Enable_copy_move< + // Copy constructor. + std::is_copy_constructible_v, + // Copy assignment. + std::is_copy_assignable_v, + // Move constructor. + std::is_move_constructible_v, + // Move assignment. + std::is_move_assignable_v, + // Unique tag type. + bb_optional_wrap> +{ + template + using _Requires = std::enable_if_t, bool>; + + bb_optional_wrap(const bb_optional_wrap& other):value(other.value){}; + bb_optional_wrap(bb_optional_wrap&& other): value(std::move(other.value)){}; + + bb_optional_wrap& + operator=(const bb_optional_wrap& other) + { + this->value = other.value; + return *this; + } + + + bb_optional_wrap& + operator=(bb_optional_wrap&& other) + noexcept(std::__and_v, + std::is_nothrow_move_assignable>) + { + this->value = std::move(other.value); + return *this; + } + + template , + std::is_convertible> = false> + bb_optional_wrap(BDE_OTHER_TYPE&& other) + { + BSLS_ASSERT(false);// "this function should never be called."); + } + + template , + std::__not_>> = true> + explicit bb_optional_wrap(BDE_OTHER_TYPE&& other) + { + BSLS_ASSERT(false);// "this function should never be called."); + } + + template > = false> + bb_optional_wrap(_Args&&... __args) + { + BSLS_ASSERT(false);// "this function should never be called."); + } + + bb_optional_wrap(std::allocator_arg_t, const std::pmr::polymorphic_allocator& __a, + const bb_optional_wrap& other) + { + BloombergLP::bslma::ConstructionUtil::construct( + std::__addressof(this->value), + (BloombergLP::bslma::Allocator *)(__a.resource()), + other.value); + } + bb_optional_wrap(std::allocator_arg_t, const std::pmr::polymorphic_allocator& __a, + bb_optional_wrap&& other) + { + BloombergLP::bslma::ConstructionUtil::construct( + std::__addressof(this->value), + (BloombergLP::bslma::Allocator *)(__a.resource()), + std::move(other.value)); + } + + template< typename... _Args> + bb_optional_wrap(std::allocator_arg_t, const std::pmr::polymorphic_allocator& __a, _Args&&... __args) + { + BloombergLP::bslma::ConstructionUtil::construct( + std::__addressof(this->value), + (BloombergLP::bslma::Allocator *)(__a.resource()), + std::forward<_Args>(__args)...); + } + + + template + bb_optional_wrap(std::allocator_arg_t, const std::pmr::polymorphic_allocator& __a, + std::initializer_list<_Up> __il,_Args&&... __args) + { + BloombergLP::bslma::ConstructionUtil::construct( + std::__addressof(this->value), + (BloombergLP::bslma::Allocator *)(__a.resource()), + __il, + std::forward<_Args>(__args)...); + } + + template > = true> + bb_optional_wrap& operator=(const BDE_OTHER_TYPE& other) + { + this->value = other; + } + + + template > = true> + bb_optional_wrap& operator=(BDE_OTHER_TYPE&& other) + { + this->value = std::move(other); + } + + ~bb_optional_wrap() { value.~TYPE(); } + + struct _Empty_byte { }; + + union { + _Empty_byte _M_empty; + TYPE value; + }; + }; + + + +namespace std +{ + template + struct uses_allocator, _Alloc> : true_type {}; +} +*/ + namespace BloombergLP { -namespace bslma { - template struct UsesBslmaAllocator> : bsl::true_type {}; +namespace bdlb { + + + + +// ========================= +// class NullableValue +// ========================= + + +template +class NullableValue : public std::pmr::optional +{ + + // This template class extends the set of values of its value-semantic + // 'TYPE' parameter to include the notion of a "null" value. If 'TYPE' is + // fully value-semantic, then the augmented type 'Nullable' will be + // as well. In addition to supporting all homogeneous value-semantic + // operations, conversions between comparable underlying value types is + // also supported. Two nullable objects with different underlying types + // compare equal if their underlying types are comparable and either (1) + // both objects are null or (2) the non-null values compare equal. A null + // nullable object is considered ordered before any non-null nullable + // object. Attempts to copy construct, copy assign, or compare + // incompatible values types will fail to compile. The 'NullableValue' + // template cannot be instantiated on an incomplete type or on a type that + // overloads 'operator&'. + + // PRIVATE TYPES + typedef bslmf::MovableRefUtil MoveUtil; + +public: + // TYPES + typedef TYPE ValueType; + // 'ValueType' is an alias for the underlying 'TYPE' upon which this + // template class is instantiated, and represents the type of the + // managed object. + + + + // TRAITS + BSLMF_NESTED_TRAIT_DECLARATION_IF(NullableValue, + bslma::UsesBslmaAllocator, + bslma::UsesBslmaAllocator::value); + BSLMF_NESTED_TRAIT_DECLARATION_IF(NullableValue, + bsl::is_trivially_copyable, + bsl::is_trivially_copyable::value); + BSLMF_NESTED_TRAIT_DECLARATION_IF(NullableValue, + bslmf::IsBitwiseMoveable, + bslmf::IsBitwiseMoveable::value); + BSLMF_NESTED_TRAIT_DECLARATION(NullableValue, bdlb::HasPrintMethod); + // 'UsesBslmaAllocator', 'IsBitwiseCopyable', and 'IsBitwiseMoveable' + // are true for 'NullableValue' only if the corresponding trait is true + // for 'TYPE'. 'HasPrintMethod' is always true for 'NullableValue'. + + // CREATORS + template< typename DUMMY = TYPE> + NullableValue(typename bsl::enable_if< + bslma::UsesBslmaAllocator::value, + void>::type * = 0) + :std::pmr::optional(std::allocator_arg_t{}, + std::pmr::polymorphic_allocator( + (std::pmr::memory_resource*)(bslma::Default::allocator(nullptr)))) + { + } + template< typename DUMMY = TYPE> + NullableValue(typename bsl::enable_if< + !bslma::UsesBslmaAllocator::value, + void>::type * = 0) + :std::pmr::optional() + { + } + // Create a nullable object having the null value. If 'TYPE' takes an + // optional allocator at construction, use the currently installed + // default allocator to supply memory. + + explicit NullableValue(bslma::Allocator *basicAllocator); + // Create a nullable object that has the null value and that uses the + // specified 'basicAllocator' to supply memory. Note that this method + // will fail to compile if 'TYPE' does not take an optional allocator + // at construction. + + NullableValue(const NullableValue&) = default; + NullableValue(NullableValue&&) = default ; +/* NullableValue(const NullableValue& original); + // Create a nullable object having the value of the specified + // 'original' object. If 'TYPE' takes an optional allocator at + // construction, use the currently installed default allocator to + // supply memory. + + NullableValue(bslmf::MovableRef original); + // Create a nullable object having the same value as the specified + // 'original' object by moving the contents of 'original' to the + // newly-created object. If 'TYPE' takes an optional allocator at + // construction, the allocator associated with 'original' is propagated + // for use in the newly-created object. 'original' is left in a valid + // but unspecified state. +*/ + NullableValue(const NullableValue& original, + bslma::Allocator *basicAllocator); + // Create a nullable object that has the value of the specified + // 'original' object and that uses the specified 'basicAllocator' to + // supply memory. Note that this method will fail to compile if 'TYPE' + // does not take an optional allocator at construction. + + NullableValue(bslmf::MovableRef original, + bslma::Allocator *basicAllocator); + // Create a nullable object having the same value as the specified + // 'original' object that uses the specified 'basicAllocator' to supply + // memory. If 'basicAllocator' is 0, the default allocator is used. + // The contents of 'original' are moved to the newly-created object. + // 'original' is left in a valid but unspecified state. Note that this + // method will fail to compile if 'TYPE' does not take an optional + // allocator at construction. + + template + NullableValue(BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value, + typename bsl::enable_if< + bsl::is_convertible::value + && + !bsl::is_convertible::value, + void>::type * = 0); // IMPLICIT + // Create a nullable object having the specified 'value' (of + // 'BDE_OTHER_TYPE') converted to 'TYPE'. If 'TYPE' takes an optional + // allocator at construction, use the currently installed default + // allocator to supply memory. Note that this constructor does not + // participate in overload resolution unless 'BDE_OTHER_TYPE' is + // convertible to 'TYPE' and not convertible to 'bslma::Allocator *'. + + template + NullableValue( + BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value, + bslma::Allocator *basicAllocator, + typename bsl::enable_if< + bsl::is_convertible::value, + void>::type * = 0); + // Create a nullable object that has the specified 'value' (of + // 'BDE_OTHER_TYPE') converted to 'TYPE', and that uses the specified + // 'basicAllocator' to supply memory. Note that this method will fail + // to compile if 'TYPE' does not take an optional allocator at + // construction. Also note that this constructor does not participate + // in overload resolution unless 'BDE_OTHER_TYPE' is convertible to + // 'TYPE'. + + template + explicit NullableValue(const NullableValue& original); + // Create a nullable object having the null value if the specified + // 'original' object is null, and the value of 'original.value()' (of + // 'BDE_OTHER_TYPE') converted to 'TYPE' otherwise. If 'TYPE' takes an + // optional allocator at construction, use the currently installed + // default allocator to supply memory. Note that this method will fail + // to compile if 'TYPE and 'BDE_OTHER_TYPE' are not compatible. + + template + NullableValue(const NullableValue& original, + bslma::Allocator *basicAllocator); + // Create a nullable object that has the null value if the specified + // 'original' object is null, and the value of 'original.value()' (of + // 'BDE_OTHER_TYPE') converted to 'TYPE' otherwise; use the specified + // 'basicAllocator' to supply memory. Note that this method will fail + // to compile if 'TYPE' does not take an optional allocator at + // construction, or if 'TYPE and 'BDE_OTHER_TYPE' are not compatible. + + // ~NullableValue(); + // Destroy this object. Note that this destructor is generated by the + // compiler. + + // MANIPULATORS + NullableValue& operator=(const NullableValue& rhs); + // Assign to this object the value of the specified 'rhs', and return a + // reference providing modifiable access to this object. + + NullableValue& operator=(bslmf::MovableRef rhs); + // Assign to this object the value of the specified 'rhs', and return a + // reference providing modifiable access to this object. The contents + // of 'rhs' are either move-inserted into or move-assigned to this + // object. 'rhs' is left in a valid but unspecified state. + + template + NullableValue& operator=(const NullableValue& rhs); + // Assign to this object the null value if the specified 'rhs' object + // is null, and the value of 'rhs.value()' (of 'BDE_OTHER_TYPE') + // converted to 'TYPE' otherwise. Return a reference providing + // modifiable access to this object. Note that this method will fail + // to compile if 'TYPE and 'BDE_OTHER_TYPE' are not compatible. + + NullableValue& operator=(const TYPE& rhs); + // Assign to this object the value of the specified 'rhs', and return a + // reference providing modifiable access to this object. + + NullableValue& operator=(bslmf::MovableRef rhs); + // Assign to this object the value of the specified 'rhs', and return a + // reference providing modifiable access to this object. The contents + // of 'rhs' are either move-inserted into or move-assigned to this + // object. 'rhs' is left in a valid but unspecified state. + + template + NullableValue& operator=(const BDE_OTHER_TYPE& rhs); + // Assign to this object the value of the specified 'rhs' object (of + // 'BDE_OTHER_TYPE') converted to 'TYPE', and return a reference + // providing modifiable access to this object. Note that this method + // will fail to compile if 'TYPE and 'BDE_OTHER_TYPE' are not + // compatible. + + + template + TYPE& makeValue(BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value); + // Assign to this object the specified 'value' (of 'BDE_OTHER_TYPE') + // converted to 'TYPE', and return a reference providing modifiable + // access to the underlying 'TYPE' object. Note that this method will + // fail to compile if 'TYPE and 'BDE_OTHER_TYPE' are not compatible. + + TYPE& makeValue(); + // Assign to this object the default value for 'TYPE', and return a + // reference providing modifiable access to the underlying 'TYPE' + // object. + + template + TYPE& makeValueInplace(_Args&&... __args) + { + this->emplace(std::forward<_Args>(__args)...); + return this->value(); + } + + + template + STREAM& bdexStreamIn(STREAM& stream, int version); + // Assign to this object the value read from the specified input + // 'stream' using the specified 'version' format, and return a + // reference to 'stream'. If 'stream' is initially invalid, this + // operation has no effect. If 'version' is not supported, this object + // is unaltered and 'stream' is invalidated, but otherwise unmodified. + // If 'version' is supported but 'stream' becomes invalid during this + // operation, this object has an undefined, but valid, state. Note + // that no version is read from 'stream'. See the 'bslx' package-level + // documentation for more information on BDEX streaming of + // value-semantic types and containers. + + //void reset(); + // Reset this object to the default constructed state (i.e., to have + // the null value). + // Provided by std::pmr::optional base class. + + // + + //TYPE& value() + // Return a reference providing modifiable access to the underlying + // 'TYPE' object. The behavior is undefined unless this object is + // non-null. + // Provided by std::pmr::optional base class. + + +// ACCESSORS + template + STREAM& bdexStreamOut(STREAM& stream, int version) const; + // Write the value of this object, using the specified 'version' + // format, to the specified output 'stream', and return a reference to + // 'stream'. If 'stream' is initially invalid, this operation has no + // effect. If 'version' is not supported, 'stream' is invalidated, but + // otherwise unmodified. Note that 'version' is not written to + // 'stream'. See the 'bslx' package-level documentation for more + // information on BDEX streaming of value-semantic types and + // containers. + + bool isNull() const; + // Return 'true' if this object is null, and 'false' otherwise. + + int maxSupportedBdexVersion(int versionSelector) const; + // Return the maximum valid BDEX format version, as indicated by the + // specified 'versionSelector', to be passed to the 'bdexStreamOut' + // method. Note that it is highly recommended that 'versionSelector' + // be formatted as "YYYYMMDD", a date representation. Also note that + // 'versionSelector' should be a *compile*-time-chosen value that + // selects a format version supported by both externalizer and + // unexternalizer. See the 'bslx' package-level documentation for more + // information on BDEX streaming of value-semantic types and + // containers. + + + bsl::ostream& print(bsl::ostream& stream, + int level = 0, + int spacesPerLevel = 4) const; + // Format this object to the specified output 'stream' at the (absolute + // value of) the optionally specified indentation 'level' and return a + // reference to 'stream'. If 'level' is specified, optionally specify + // 'spacesPerLevel', the number of spaces per indentation level for + // this and all of its nested objects. If 'level' is negative, + // suppress indentation of the first line. If 'spacesPerLevel' is + // negative, format the entire output on one line, suppressing all but + // the initial indentation (as governed by 'level'). If 'stream' is + // not valid on entry, this operation has no effect. + + //const TYPE& value() const; + // Return a reference providing non-modifiable access to the underlying + // object of a (template parameter) 'TYPE'. The behavior is undefined + // unless this object is non-null. + // provided by std::pmr::optional base class. + + TYPE valueOr(const TYPE& value) const; + // Return the value of the underlying object of a (template parameter) + // 'TYPE' if this object is non-null, and the specified 'value' + // otherwise. Note that this method returns *by* *value*, so may be + // inefficient in some contexts. + + #if BSLS_DEPRECATE_IS_ACTIVE(BDL, 3, 5) + BSLS_DEPRECATE + #endif + const TYPE *valueOr(const TYPE *value) const; + // !DEPRECATED!: Use 'addressOr' instead. + // + // Return an address providing non-modifiable access to the underlying + // object of a (template parameter) 'TYPE' if this object is non-null, + // and the specified 'value' otherwise. + + const TYPE *addressOr(const TYPE *address) const; + // Return an address providing non-modifiable access to the underlying + // object of a (template parameter) 'TYPE' if this object is non-null, + // and the specified 'address' otherwise. + + const TYPE *valueOrNull() const; + // Return an address providing non-modifiable access to the underlying + // object of a (template parameter) 'TYPE' if this object is non-null, + // and 0 otherwise. + +private: + constexpr explicit operator bool() const noexcept; + // base class is convertable to bool, but NullableValue shouldn't be. +}; +// FREE OPERATORS +template +bool operator==(const NullableValue& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' and 'rhs' nullable objects have the + // same value, and 'false' otherwise. Two nullable objects have the same + // value if both are null, or if both are non-null and the values of their + // underlying objects compare equal. Note that this function will fail to + // compile if 'LHS_TYPE' and 'RHS_TYPE' are not compatible. + +template +bool operator!=(const NullableValue& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' and 'rhs' nullable objects do not + // have the same value, and 'false' otherwise. Two nullable objects do not + // have the same value if one is null and the other is non-null, or if both + // are non-null and the values of their underlying objects do not compare + // equal. Note that this function will fail to compile if 'LHS_TYPE' and + // 'RHS_TYPE' are not compatible. + +template +bool operator==(const NullableValue& lhs, + const TYPE& rhs); +template +bool operator==(const TYPE& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' and 'rhs' objects have the same + // value, and 'false' otherwise. A nullable object and a value of the + // underlying 'TYPE' have the same value if the nullable object is non-null + // and its underlying value compares equal to the other value. + +template +bool operator!=(const NullableValue& lhs, + const TYPE& rhs); +template +bool operator!=(const TYPE& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' and 'rhs' objects do not have the + // same value, and 'false' otherwise. A nullable object and a value of the + // underlying 'TYPE' do not have the same value if either the nullable + // object is null, or its underlying value does not compare equal to the + // other value. + +// There is at least one instance of client code having already defined +// 'operator<' on 'bdlb::NullableValue' (see bde_extended.h in DPKG +// crm-integration). The following macro facilitates client migration to the +// comparison operators defined here. +#define BDLB_NULLABLEVALUE_SUPPORTS_LESS_THAN + +template +bool operator<(const NullableValue& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered before + // the specified 'rhs' nullable object, and 'false' otherwise. 'lhs' is + // ordered before 'rhs' if 'lhs' is null and 'rhs' is non-null or if both + // are non-null and 'lhs.value()' is ordered before 'rhs.value()'. Note + // that this function will fail to compile if 'LHS_TYPE' and 'RHS_TYPE' are + // not compatible. + +template +bool operator<(const NullableValue& lhs, + const TYPE& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered before + // the specified 'rhs', and 'false' otherwise. 'lhs' is ordered before + // 'rhs' if 'lhs' is null or 'lhs.value()' is ordered before 'rhs'. + +template +bool operator<(const TYPE& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' is ordered before the specified + // 'rhs' nullable object, and 'false' otherwise. 'lhs' is ordered before + // 'rhs' if 'rhs' is not null and 'lhs' is ordered before 'rhs.value()'. + +template +bool operator>(const NullableValue& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered after + // the specified 'rhs' nullable object, and 'false' otherwise. 'lhs' is + // ordered after 'rhs' if 'lhs' is non-null and 'rhs' is null or if both + // are non-null and 'lhs.value()' is ordered after 'rhs.value()'. Note + // that this operator returns 'rhs < lhs'. Also note that this function + // will fail to compile if 'LHS_TYPE' and 'RHS_TYPE' are not compatible. + +template +bool operator>(const NullableValue& lhs, + const TYPE& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered after + // the specified 'rhs', and 'false' otherwise. 'lhs' is ordered after + // 'rhs' if 'lhs' is not null and 'lhs.value()' is ordered after 'rhs'. + // Note that this operator returns 'rhs < lhs'. + +template +bool operator>(const TYPE& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' is ordered after the specified + // 'rhs' nullable object, and 'false' otherwise. 'lhs' is ordered after + // 'rhs' if 'rhs' is null or 'lhs' is ordered after 'rhs.value()'. Note + // that this operator returns 'rhs < lhs'. + + +template +bool operator<=(const NullableValue& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered before + // the specified 'rhs' nullable object or 'lhs' and 'rhs' have the same + // value, and 'false' otherwise. (See 'operator<' and 'operator=='.) Note + // that this operator returns '!(rhs < lhs)'. Also note that this function + // will fail to compile if 'LHS_TYPE' and 'RHS_TYPE' are not compatible. + +template +bool operator<=(const NullableValue& lhs, + const TYPE& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered before + // the specified 'rhs' or 'lhs' and 'rhs' have the same value, and 'false' + // otherwise. (See 'operator<' and 'operator=='.) Note that this operator + // returns '!(rhs < lhs)'. + +template +bool operator<=(const TYPE& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' is ordered before the specified + // 'rhs' nullable object or 'lhs' and 'rhs' have the same value, and + // 'false' otherwise. (See 'operator<' and 'operator=='.) Note that this + // operator returns '!(rhs < lhs)'. + +template +bool operator>=(const NullableValue& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered after + // the specified 'rhs' nullable object or 'lhs' and 'rhs' have the same + // value, and 'false' otherwise. (See 'operator>' and 'operator=='.) Note + // that this operator returns '!(lhs < rhs)'. Also note that this function + // will fail to compile if 'LHS_TYPE' and 'RHS_TYPE' are not compatible. + +template +bool operator>=(const NullableValue& lhs, + const TYPE& rhs); + // Return 'true' if the specified 'lhs' nullable object is ordered after + // the specified 'rhs' or 'lhs' and 'rhs' have the same value, and 'false' + // otherwise. (See 'operator>' and 'operator=='.) Note that this operator + // returns '!(lhs < rhs)'. + +template +bool operator>=(const TYPE& lhs, + const NullableValue& rhs); + // Return 'true' if the specified 'lhs' is ordered after the specified + // 'rhs' nullable object or 'lhs' and 'rhs' have the same value, and + // 'false' otherwise. (See 'operator>' and 'operator=='.) Note that this + // operator returns '!(lhs < rhs)'. + +template +bsl::ostream& operator<<(bsl::ostream& stream, + const NullableValue& object); + // Write the value of the specified 'object' to the specified output + // 'stream' in a single-line format, and return a reference to 'stream'. + // If 'stream' is not valid on entry, this operation has no effect. Note + // that this human-readable format is not fully specified, can change + // without notice, and is logically equivalent to: + //.. + // print(stream, 0, -1); + //.. + +// FREE FUNCTIONS +template +void hashAppend(HASHALG& hashAlg, const NullableValue& input); + // Pass the boolean value of whether the specified 'input' contains a value + // to the specified 'hashAlg' hashing algorithm of (template parameter) + // type 'HASHALG'. If 'input' contains a value, additionally pass that + // value to 'hashAlg'. + +template +void swap(NullableValue& a, NullableValue& b); + // Efficiently exchange the values of the specified 'a' and 'b' objects. + // This method provides the no-throw exception-safety guarantee if the + // template parameter 'TYPE' provides that guarantee and the result of the + // 'isNull' method for 'a' and 'b' is the same. The behavior is undefined + // unless both objects were created with the same allocator, if any. + + + +template +template +STREAM& NullableValue::bdexStreamIn(STREAM& stream, int version) +{ + using bslx::InStreamFunctions::bdexStreamIn; + + char isNull = 0; // Redundant initialization to suppress -Werror. + + stream.getInt8(isNull); + + if (stream) { + if (!isNull) { + this->makeValue(); + + bdexStreamIn(stream, this->value(), version); + } + else { + this->reset(); + } + } + + return stream; +} +// ============================================================================ +// INLINE DEFINITIONS +// ============================================================================ + + // ------------------------- + // class NullableValue + // ------------------------- + +// CREATORS +/*template +inline +NullableValue::NullableValue(typename bsl::enable_if< + bslma::UsesBslmaAllocator::value, + void>::type * = 0) +:std::pmr::optional(std::allocator_arg_t{}, + std::pmr::polymorphic_allocator( + (std::pmr::memory_resource*)(bslma::Default::allocator(nullptr)))) +{ +} + +template +inline +NullableValue::NullableValue(typename bsl::enable_if< + !bslma::UsesBslmaAllocator::value, + void>::type * = 0) +{ +} +*/ +template +inline +NullableValue::NullableValue(bslma::Allocator *basicAllocator) +: std::pmr::optional(std::allocator_arg_t{}, + std::pmr::polymorphic_allocator( + (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) +{ +} + +template +inline +NullableValue::NullableValue(const NullableValue& original, + bslma::Allocator *basicAllocator) +: std::pmr::optional(std::allocator_arg_t{}, + (std::pmr::polymorphic_allocator)( + (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) +{ + if (!original.isNull()) { + this->makeValue(original.value()); + } +} + +template +inline +NullableValue::NullableValue( + bslmf::MovableRef original, + bslma::Allocator *basicAllocator) +: std::pmr::optional(std::allocator_arg_t{}, + std::pmr::polymorphic_allocator( + (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) +{ + if (!original.isNull()) { + this->makeValue( MoveUtil::move(original.value())); + } +} + +template +template +inline +NullableValue::NullableValue( + BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value, + typename bsl::enable_if::value + && + !bsl::is_convertible::value, + void>::type *) +: std::pmr::optional(BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) +{ +} + +template +template +inline +NullableValue::NullableValue( + BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value, + bslma::Allocator *basicAllocator, + typename bsl::enable_if::value, + void>::type *) +: std::pmr::optional(std::allocator_arg_t{}, + std::pmr::polymorphic_allocator((std::pmr::memory_resource*) + (bslma::Default::allocator(basicAllocator))), + BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) +{ +} + +template +template +inline +NullableValue::NullableValue( + const NullableValue& original) +: std::pmr::optional((std::pmr::optional)original) +{ +} + +template +template +inline +NullableValue::NullableValue( + const NullableValue& original, + bslma::Allocator *basicAllocator) +: std::pmr::optional(std::allocator_arg_t{}, + std::pmr::polymorphic_allocator((std::pmr::memory_resource*) + (bslma::Default::allocator(basicAllocator)))) +{ + if (!original.isNull()) { + this->makeValue( MoveUtil::move(original.value())); + } +} + + +// ACCESSORS +template +template +STREAM& NullableValue::bdexStreamOut(STREAM& stream, int version) const +{ + using bslx::OutStreamFunctions::bdexStreamOut; + + const bool isNull = this->isNull(); + + stream.putInt8(isNull ? 1 : 0); + + if (!isNull) { + bdexStreamOut(stream, this->value(), version); + } + + return stream; +} + +template +inline +bool NullableValue::isNull() const +{ + return !this->has_value(); +} + +template +inline +int NullableValue::maxSupportedBdexVersion(int versionSelector) const +{ + using bslx::VersionFunctions::maxSupportedBdexVersion; + + // We need to call the 'bslx::VersionFunctions' helper function, because we + // cannot guarantee that 'TYPE' implements 'maxSupportedBdexVersion' as a + // class method. + + return maxSupportedBdexVersion(reinterpret_cast(0), + versionSelector); +} + + +template +bsl::ostream& NullableValue::print(bsl::ostream& stream, + int level, + int spacesPerLevel) const +{ + if (this->isNull()) { + return bdlb::PrintMethods::print(stream, + "NULL", + level, + spacesPerLevel); // RETURN + } + + return bdlb::PrintMethods::print(stream, + this->value(), + level, + spacesPerLevel); +} +// MANIPULATORS +template +inline +NullableValue& NullableValue::operator=(const NullableValue& rhs) +{ + std::pmr::optional::operator=(rhs); + return *this; +} + +template +inline +NullableValue& +NullableValue::operator=(bslmf::MovableRef rhs) +{ + std::pmr::optional& rhs_base = rhs; + std::pmr::optional::operator=(MoveUtil::move(rhs_base)); + return *this; +} + +template +template +NullableValue& NullableValue::operator=( + const NullableValue& rhs) +{ + if (rhs.isNull()) { + this->reset(); + } + else { + this->makeValue(rhs.value()); + } + return *this; +} + +template +inline +NullableValue& NullableValue::operator=(const TYPE& rhs) +{ + this->makeValue(rhs); + + return *this; +} + +template +inline +NullableValue& +NullableValue::operator=(bslmf::MovableRef rhs) +{ + this->makeValue(MoveUtil::move(rhs)); + + return *this; +} + +template +template +inline +NullableValue& NullableValue::operator=(const BDE_OTHER_TYPE& rhs) +{ + this->makeValue(rhs); + + return *this; +} + +template +template +inline +TYPE& NullableValue::makeValue( + BSLS_COMPILERFEATURES_FORWARD_REF(BDE_OTHER_TYPE) value) +{ + this->emplace(BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)); + return this->value(); } + +template +inline +TYPE& NullableValue::makeValue() +{ + this->emplace(); + return this->value(); } -namespace std { -namespace pmr { - template - int optional<_Tp>::maxSupportedBdexVersion(int versionSelector) const - { - using BloombergLP::bslx::VersionFunctions::maxSupportedBdexVersion; +template +inline +const TYPE *NullableValue::valueOrNull() const +{ + return this->isNull() ? 0 : &this->value(); +} - // We need to call the 'bslx::VersionFunctions' helper function, because we - // cannot guarantee that 'TYPE' implements 'maxSupportedBdexVersion' as a - // class method. - - return maxSupportedBdexVersion(reinterpret_cast<_Tp *>(0), - versionSelector); - } +template +inline +TYPE NullableValue::valueOr(const TYPE& value) const +{ + return this->isNull() ? value : this->value(); +} - template - template - STREAM& optional::bdexStreamIn(STREAM& stream, int version) - { - using BloombergLP::bslx::InStreamFunctions::bdexStreamIn; +template +inline +const TYPE *NullableValue::valueOr(const TYPE *value) const +{ + return this->isNull() ? value : &this->value(); +} - char isNull = 0; // Redundant initialization to suppress -Werror. +template +inline +const TYPE *NullableValue::addressOr(const TYPE *value) const +{ + return this->isNull() ? value : &this->value(); +} - stream.getInt8(isNull); - if (stream) { - if (!isNull) { - this->makeValue(); +} // close package namespace - bdexStreamIn(stream, this->value(), version); - } - else { - this->reset(); - } +// FREE OPERATORS +template +inline +bool bdlb::operator==(const NullableValue& lhs, + const NullableValue& rhs) +{ + if (!lhs.isNull() && !rhs.isNull()) { + return lhs.value() == rhs.value(); // RETURN } - return stream; - } - - template - template - STREAM& optional::bdexStreamOut(STREAM& stream, int version) const - { - using BloombergLP::bslx::OutStreamFunctions::bdexStreamOut; - - const bool isNull = this->isNull(); - - stream.putInt8(isNull ? 1 : 0); - - if (!isNull) { - bdexStreamOut(stream, this->value(), version); - } - - return stream; - } - - template - bsl::ostream& operator<<(bsl::ostream& stream, - const optional& object) - { - if (object.isNull()) { - return BloombergLP::bdlb::PrintMethods::print(stream, - "NULL", - 0, - -1); // RETURN - } - - return BloombergLP::bdlb::PrintMethods::print(stream, - object.value(), - 0, - -1); - } - - template - template - auto& optional::print(STREAM& stream, int level, - int spacesPerLevel) const - { - if (this->isNull()) { - return (bsl::ostream&)BloombergLP::bdlb::PrintMethods::print(stream, - "NULL", - 0, - -1); // RETURN - } - - return (bsl::ostream&)BloombergLP::bdlb::PrintMethods::print(stream, - this->value(), - 0, - -1); - } - - template - void hashAppend(HASHALG& hashAlg, const optional& input) - { - using namespace BloombergLP; - if (!input.isNull()) { - hashAppend(hashAlg, true); - hashAppend(hashAlg, input.value()); + return lhs.isNull() == rhs.isNull(); +} + +template +inline +bool bdlb::operator==(const NullableValue& lhs, + const TYPE& rhs) +{ + return !lhs.isNull() && lhs.value() == rhs; +} + +template +inline +bool bdlb::operator==(const TYPE& lhs, + const NullableValue& rhs) +{ + return !rhs.isNull() && rhs.value() == lhs; +} + +template +inline +bool bdlb::operator!=(const NullableValue& lhs, + const NullableValue& rhs) +{ + if (!lhs.isNull() && !rhs.isNull()) { + return lhs.value() != rhs.value(); // RETURN } - else { - hashAppend(hashAlg, false); + + return lhs.isNull() != rhs.isNull(); +} + +template +inline +bool bdlb::operator!=(const NullableValue& lhs, + const TYPE& rhs) +{ + return lhs.isNull() || lhs.value() != rhs; +} + +template +inline +bool bdlb::operator!=(const TYPE& lhs, + const NullableValue& rhs) +{ + return rhs.isNull() || rhs.value() != lhs; +} + +template +inline +bool bdlb::operator<(const NullableValue& lhs, + const NullableValue& rhs) +{ + if (rhs.isNull()) { + return false; // RETURN } - } + + return lhs.isNull() || lhs.value() < rhs.value(); +} + +template +inline +bool bdlb::operator<(const NullableValue& lhs, + const TYPE& rhs) +{ + return lhs.isNull() || lhs.value() < rhs; } + +template +inline +bool bdlb::operator<(const TYPE& lhs, + const NullableValue& rhs) +{ + return !rhs.isNull() && lhs < rhs.value(); +} + +template +inline +bool bdlb::operator>(const NullableValue& lhs, + const NullableValue& rhs) +{ + return rhs < lhs; +} + +template +inline +bool bdlb::operator>(const NullableValue& lhs, + const TYPE& rhs) +{ + return rhs < lhs; +} + +template +inline +bool bdlb::operator>(const TYPE& lhs, + const NullableValue& rhs) +{ + return rhs < lhs; +} + +template +inline +bool bdlb::operator<=(const NullableValue& lhs, + const NullableValue& rhs) +{ + return !(rhs < lhs); +} + +template +inline +bool bdlb::operator<=(const NullableValue& lhs, + const TYPE& rhs) +{ + return !(rhs < lhs); +} + +template +inline +bool bdlb::operator<=(const TYPE& lhs, + const NullableValue& rhs) +{ + return !(rhs < lhs); +} + +template +inline +bool bdlb::operator>=(const NullableValue& lhs, + const NullableValue& rhs) +{ + return !(lhs < rhs); } -namespace BloombergLP { -namespace bdlb { template -using NullableValue = std::pmr::optional; +inline +bool bdlb::operator>=(const NullableValue& lhs, + const TYPE& rhs) +{ + return !(lhs < rhs); +} template -class NullableValue_WithAllocator; +inline +bool bdlb::operator>=(const TYPE& lhs, + const NullableValue& rhs) +{ + return !(lhs < rhs); +} template -class NullableValue_WithoutAllocator; +inline +bsl::ostream& bdlb::operator<<(bsl::ostream& stream, + const NullableValue& object) +{ + return object.print(stream, 0, -1); +} + +// FREE FUNCTIONS +template +void bdlb::hashAppend(HASHALG& hashAlg, const NullableValue& input) +{ + if (!input.isNull()) { + hashAppend(hashAlg, true); + hashAppend(hashAlg, input.value()); + } + else { + hashAppend(hashAlg, false); + } +} +template +inline +void bdlb::swap(NullableValue& a, NullableValue& b) +{ + a.swap(b); +} +} // close enterprise namespace #if 0 // ========================= // class NullableValue @@ -670,6 +1695,7 @@ class NullableValue { // and 0 otherwise. }; + // FREE OPERATORS template bool operator==(const NullableValue& lhs, @@ -848,6 +1874,7 @@ void swap(NullableValue& a, NullableValue& b); // 'isNull' method for 'a' and 'b' is the same. The behavior is undefined // unless both objects were created with the same allocator, if any. + // ======================================= // class NullableValue_WithAllocator // ======================================= @@ -1532,6 +2559,7 @@ TYPE& NullableValue::value() return d_imp.value(); } + // ACCESSORS template template @@ -1627,6 +2655,22 @@ const TYPE *NullableValue::addressOr(const TYPE *value) const } // close package namespace +template +inline +int NullableValue::maxSupportedBdexVersion(int versionSelector) const +{ + using bslx::VersionFunctions::maxSupportedBdexVersion; + + // We need to call the 'bslx::VersionFunctions' helper function, because we + // cannot guarantee that 'TYPE' implements 'maxSupportedBdexVersion' as a + // class method. + + return maxSupportedBdexVersion(reinterpret_cast(0), + versionSelector); +} + + +} // FREE OPERATORS template inline @@ -1812,6 +2856,7 @@ void bdlb::swap(NullableValue& a, NullableValue& b) a.swap(b); } + namespace bdlb { // --------------------------------------- @@ -2511,13 +3556,14 @@ const TYPE& NullableValue_WithoutAllocator::value() const return d_buffer.object(); } -#endif + } // close package namespace } // close enterprise namespace -#endif +#endif // 0 +#endif // INCLUDED_BDLB_NULLABLEVALUE // ---------------------------------------------------------------------------- // Copyright 2016 Bloomberg Finance L.P. // diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp b/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp index 15cf2c94c2..5d961242a7 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp +++ b/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp @@ -48,7 +48,7 @@ using namespace bsl; namespace std { - template +/* template struct uses_allocator : true_type {}; template struct uses_allocator>, _Alloc> : true_type {}; @@ -59,10 +59,8 @@ struct uses_allocator : true_type {}; template struct uses_allocator : true_type {}; template -struct uses_allocator : true_type {}; - template struct uses_allocator : true_type {}; -} +*/} // ============================================================================ // TEST PLAN diff --git a/groups/bdl/bdlb/memory_resource b/groups/bdl/bdlb/memory_resource index 625a10af2c..7f1f0ca5e9 100644 --- a/groups/bdl/bdlb/memory_resource +++ b/groups/bdl/bdlb/memory_resource @@ -126,18 +126,6 @@ namespace pmr operator!=(const memory_resource& __a, const memory_resource& __b) noexcept { return !(__a == __b); } - template - struct __is_dynamic_castable - { - static constexpr bool value=false; - }; - template - struct __is_dynamic_castable<_Tp, _Up, - void_t(declval<_Up>()))>> - { - static constexpr bool value=true; - }; - // C++17 23.12.3 Class template polymorphic_allocator template @@ -335,18 +323,6 @@ namespace pmr select_on_container_copy_construction() const noexcept { return polymorphic_allocator(); } - template ::value - && !is_same_v<_Target, memory_resource>>> - operator _Target*() const - { - memory_resource* res = resource(); - _Target& ret = dynamic_cast<_Target&>(*res); - return &ret; - } - memory_resource* resource() const noexcept __attribute__((__returns_nonnull__)) diff --git a/groups/bdl/bdlb/pmroptional b/groups/bdl/bdlb/pmroptional index 2ee81ae419..342abe9b52 100644 --- a/groups/bdl/bdlb/pmroptional +++ b/groups/bdl/bdlb/pmroptional @@ -1,4 +1,4 @@ -// -*- C++ -*- +// <__pmroptional> -*- C++ -*- // Copyright (C) 2013-2018 Free Software Foundation, Inc. // @@ -22,7 +22,7 @@ // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // . -/** @file include/pmroptional +/** @file include/__pmroptional * This is an extension header. */ @@ -56,1606 +56,471 @@ namespace pmr { #define __cpp_lib_pmroptional 201810 template - class optional; - - // Payload for optionals with non-trivial destructor. - template , - bool /*_HasTrivialCopyAssignment*/ = - is_trivially_copy_assignable_v<_Tp>, - bool /*_HasTrivialMoveAssignment*/ = - is_trivially_move_assignable_v<_Tp>> - struct _Optional_payload - { - constexpr _Optional_payload() noexcept : _M_empty() { } - - template - constexpr - _Optional_payload(in_place_t, _Args&&... __args) - : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { } - - template - constexpr - _Optional_payload(std::initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(__il, std::forward<_Args>(__args)...), - _M_engaged(true) - { } - - template - constexpr - _Optional_payload(memory_resource* __pmr, _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(std::forward<_Args>(__args)...); - } + class __pmroptional; + - template - constexpr - _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, - _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(__il, std::forward<_Args>(__args)...); - } + template + using optional = conditional_t<__or_>, + __uses_domain_allocator<_Tp,polymorphic_allocator>>::value, + __pmroptional<_Tp> , std::optional<_Tp>>; - constexpr - _Optional_payload(bool __engaged, const _Optional_payload& __other) - : _Optional_payload(__other) - { } - constexpr - _Optional_payload(bool __engaged, _Optional_payload&& __other) - : _Optional_payload(std::move(__other)) - { } + + // This class template manages construction/destruction of + // the contained value for a std::pmr::optional. + template + struct _Optional_payload + { + using _Stored_type = remove_const_t<_Tp>; - constexpr + _Optional_payload() noexcept {}; + + _Optional_payload(const _Optional_payload& __other) - { - _M_pmr = __other._M_pmr; + : _M_pmr(__other._M_pmr) + { if (__other._M_engaged) - this->_M_construct(__other._M_payload); + this->_M_construct(__other._M_get()); } - constexpr + _Optional_payload(_Optional_payload&& __other) - { - _M_pmr = __other._M_pmr; + : _M_pmr(__other._M_pmr) + { if (__other._M_engaged) - this->_M_construct(std::move(__other._M_payload)); + this->_M_construct(std::move(__other._M_get())); } _Optional_payload& operator=(const _Optional_payload& __other) - { - if (this->_M_engaged && __other._M_engaged) - this->_M_get() = __other._M_get(); - else { - if (__other._M_engaged) - this->_M_construct(__other._M_get()); - else - this->_M_reset(); + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = __other._M_get(); + else + { + if (__other._M_engaged) + this->_M_construct(__other._M_get()); + else + this->_M_reset(); } - return *this; - } - + return *this; + } + + _Optional_payload& operator=(_Optional_payload&& __other) - noexcept(__and_v, - is_nothrow_move_assignable<_Tp>>) - { + noexcept(__and_v, + is_nothrow_move_assignable<_Tp>>) + { if (this->_M_engaged && __other._M_engaged) this->_M_get() = std::move(__other._M_get()); else { - if (__other._M_engaged) - this->_M_construct(std::move(__other._M_get())); - else - this->_M_reset(); + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_get())); + else + this->_M_reset(); } return *this; - } - - using _Stored_type = remove_const_t<_Tp>; - - struct _Empty_byte { }; - - union { - _Empty_byte _M_empty; - _Stored_type _M_payload; - }; - bool _M_engaged = false; - memory_resource* _M_pmr = nullptr; - - ~_Optional_payload() - { - if (_M_engaged) - _M_payload.~_Stored_type(); - } - - template - void - _M_construct(_Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - if (_M_pmr) - { - __uses_allocator_construct(polymorphic_allocator<_Stored_type>(_M_pmr), - std::__addressof(this->_M_payload), - std::forward<_Args>(__args)...); - } - else - { - ::new ((void *) std::__addressof(this->_M_payload)) - _Stored_type(std::forward<_Args>(__args)...); - } - this->_M_engaged = true; - } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { return this->_M_payload; } - - constexpr const _Tp& - _M_get() const noexcept - { return this->_M_payload; } - - // _M_reset is a 'safe' operation with no precondition. - void - _M_reset() noexcept - { - if (this->_M_engaged) - { - this->_M_engaged = false; - this->_M_payload.~_Stored_type(); } - } - }; - - // Payload for potentially-constexpr optionals. - template - struct _Optional_payload<_Tp, true, true, true> - { - constexpr _Optional_payload() noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) { } - - template - constexpr - _Optional_payload(in_place_t, _Args&&... __args) - : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(std::initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(__il, std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(memory_resource* __pmr, _Args&&... __args) - : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true), - _M_pmr(__pmr ? __pmr : std::pmr::get_default_resource()) - { } - - template - constexpr - _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(__il, std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(__pmr ? __pmr : std::pmr::get_default_resource()) - { } - - template struct __ctor_tag {}; - - constexpr - _Optional_payload(__ctor_tag, const _Tp& __other) - : _M_payload(__other), _M_engaged(true), _M_pmr(__other._M_pmr) - { } - - constexpr _Optional_payload(__ctor_tag) noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) - { } - - constexpr _Optional_payload(__ctor_tag, _Tp&& __other) - : _M_payload(std::move(__other)), _M_engaged(true), _M_pmr(__other._M_pmr) - { } - - constexpr - _Optional_payload(bool __engaged, const _Optional_payload& __other) - : _Optional_payload(__engaged ? - _Optional_payload(__ctor_tag{}, - __other._M_payload) : - _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - constexpr - _Optional_payload(bool __engaged, _Optional_payload&& __other) - : _Optional_payload(__engaged - ? _Optional_payload(__ctor_tag{}, - std::move(__other._M_payload)) - : _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - using _Stored_type = remove_const_t<_Tp>; struct _Empty_byte { }; - union { - _Empty_byte _M_empty; - _Stored_type _M_payload; - }; - bool _M_engaged; - memory_resource* _M_pmr; - }; - - // Payload for optionals with non-trivial copy assignment. - template - struct _Optional_payload<_Tp, true, false, true> - { - constexpr _Optional_payload() noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) { } - - template - constexpr - _Optional_payload(in_place_t, _Args&&... __args) - : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(std::initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(__il, std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(memory_resource* __pmr, _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - - _M_construct(std::forward<_Args>(__args)...); - } - - template - constexpr - _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, - _Args&&... __args) + template + union _Storage { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(__il, std::forward<_Args>(__args)...); - } - - template struct __ctor_tag {}; - - constexpr _Optional_payload(__ctor_tag, const _Tp& __other) - : _M_payload(__other), - _M_engaged(true), - _M_pmr(__other._M_pmr) - { } - - constexpr _Optional_payload(__ctor_tag) noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) - { } - - constexpr _Optional_payload(__ctor_tag, _Tp&& __other) - : _M_payload(std::move(__other)), - _M_engaged(true), - _M_pmr(__other._M_pmr) - { } - - constexpr - _Optional_payload(bool __engaged, const _Optional_payload& __other) - : _Optional_payload(__engaged ? - _Optional_payload(__ctor_tag{}, - __other._M_payload) : - _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - constexpr - _Optional_payload(bool __engaged, _Optional_payload&& __other) - : _Optional_payload(__engaged - ? _Optional_payload(__ctor_tag{}, - std::move(__other._M_payload)) - : _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - _Optional_payload(const _Optional_payload&) = default; - _Optional_payload(_Optional_payload&&) = default; - - _Optional_payload& - operator=(const _Optional_payload& __other) - { - if (this->_M_engaged && __other._M_engaged) - this->_M_get() = __other._M_get(); - else - { - if (__other._M_engaged) - this->_M_construct(__other._M_get()); - else - this->_M_reset(); - } - return *this; - } - - _Optional_payload& - operator=(_Optional_payload&& __other) = default; - - using _Stored_type = remove_const_t<_Tp>; + constexpr _Storage() noexcept : _M_empty() { } + +/* template + constexpr + _Storage(_Args&&... __args) + : _Storage(std::in_place, std::forward<_Args>( __args)...) + { } + + template + constexpr + _Storage(in_place_t,_Args&&... __args) + : _M_value(std::forward<_Args>(__args)...) + { } + + template + constexpr + _Storage(std::initializer_list<_Vp> __il, _Args&&... __args) + : _M_value(__il, std::forward<_Args>(__args)...) + { } + */ + // User-provided destructor is needed when _Up has non-trivial dtor. + ~_Storage() { } + _Empty_byte _M_empty; + _Up _M_value; + }; - struct _Empty_byte { }; + _Storage<_Stored_type> _M_payload; - union { - _Empty_byte _M_empty; - _Stored_type _M_payload; - }; - bool _M_engaged; - memory_resource* _M_pmr; + bool _M_engaged = false; + memory_resource* _M_pmr = std::pmr::get_default_resource(); template void _M_construct(_Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - if (_M_pmr) - { - __uses_allocator_construct(polymorphic_allocator<_Stored_type>(_M_pmr), - std::__addressof(this->_M_payload), - std::forward<_Args>(__args)...); - } - else - { - ::new ((void *) std::__addressof(this->_M_payload)) - _Stored_type(std::forward<_Args>(__args)...); - } - this->_M_engaged = true; - } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { return this->_M_payload; } - - constexpr const _Tp& - _M_get() const noexcept - { return this->_M_payload; } - - // _M_reset is a 'safe' operation with no precondition. - void - _M_reset() noexcept - { - if (this->_M_engaged) - { - this->_M_engaged = false; - this->_M_payload.~_Stored_type(); - } - } - }; - - // Payload for optionals with non-trivial move assignment. - template - struct _Optional_payload<_Tp, true, true, false> - { - constexpr _Optional_payload() noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) { } - - template - constexpr - _Optional_payload(in_place_t, _Args&&... __args) - : _M_payload(std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(std::initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(__il, std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(memory_resource* __pmr, _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(std::forward<_Args>(__args)...); - } - - template - constexpr - _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, - _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(__il, std::forward<_Args>(__args)...); - } - - template struct __ctor_tag {}; - - constexpr - _Optional_payload(__ctor_tag, const _Tp& __other) - : _M_payload(__other), - _M_engaged(true), - _M_pmr(__other._M_pmr) - { } - - constexpr _Optional_payload(__ctor_tag) noexcept - : _M_empty(), _M_engaged(false) - { } - - constexpr _Optional_payload(__ctor_tag, _Tp&& __other) - : _M_payload(std::move(__other)), - _M_engaged(true), - _M_pmr(__other._M_pmr) - { } - - constexpr - _Optional_payload(bool __engaged, const _Optional_payload& __other) - : _Optional_payload(__engaged ? - _Optional_payload(__ctor_tag{}, - __other._M_payload) : - _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - constexpr - _Optional_payload(bool __engaged, _Optional_payload&& __other) - : _Optional_payload(__engaged - ? _Optional_payload(__ctor_tag{}, - std::move(__other._M_payload)) - : _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - _Optional_payload(const _Optional_payload&) = default; - _Optional_payload(_Optional_payload&&) = default; - - _Optional_payload& - operator=(const _Optional_payload& __other) = default; - - _Optional_payload& - operator=(_Optional_payload&& __other) - noexcept(__and_v, - is_nothrow_move_assignable<_Tp>>) - { - if (this->_M_engaged && __other._M_engaged) - this->_M_get() = std::move(__other._M_get()); - else + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) { - if (__other._M_engaged) - this->_M_construct(std::move(__other._M_get())); - else - this->_M_reset(); - } - return *this; - } - - using _Stored_type = remove_const_t<_Tp>; - - struct _Empty_byte { }; - - union { - _Empty_byte _M_empty; - _Stored_type _M_payload; - }; - bool _M_engaged; - memory_resource* _M_pmr; - - template - void - _M_construct(_Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - if (_M_pmr) - { - __uses_allocator_construct(polymorphic_allocator<_Stored_type>(_M_pmr), - std::__addressof(this->_M_payload), + __uses_allocator_construct(polymorphic_allocator(_M_pmr), + std::__addressof(this->_M_payload._M_value), std::forward<_Args>(__args)...); - } - else - { - ::new ((void *) std::__addressof(this->_M_payload)) - _Stored_type(std::forward<_Args>(__args)...); - } - this->_M_engaged = true; + this->_M_engaged = true; } + - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { return this->_M_payload; } - - constexpr const _Tp& - _M_get() const noexcept - { return this->_M_payload; } - - // _M_reset is a 'safe' operation with no precondition. - void - _M_reset() noexcept - { - if (this->_M_engaged) - { - this->_M_engaged = false; - this->_M_payload.~_Stored_type(); - } - } - }; - - // Payload for optionals with non-trivial copy and move assignment. - template - struct _Optional_payload<_Tp, true, false, false> - { - constexpr _Optional_payload() noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) {} - - template - constexpr - _Optional_payload(in_place_t, _Args&&... __args) - : _M_payload(std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(std::initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(__il, std::forward<_Args>(__args)...), - _M_engaged(true), - _M_pmr(nullptr) - { } - - template - constexpr - _Optional_payload(memory_resource* __pmr, _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(std::forward<_Args>(__args)...); - } - - template - constexpr - _Optional_payload(memory_resource* __pmr, std::initializer_list<_Up> __il, - _Args&&... __args) - { - if (!__pmr) - _M_pmr = std::pmr::get_default_resource(); - else - _M_pmr = __pmr; - _M_construct(__il, std::forward<_Args>(__args)...); - } - - template struct __ctor_tag {}; - - constexpr _Optional_payload(__ctor_tag, const _Tp& __other) - : _M_payload(__other), - _M_engaged(true), - _M_pmr(__other._M_pmr) - { } - - constexpr _Optional_payload(__ctor_tag) noexcept - : _M_empty(), _M_engaged(false), _M_pmr(nullptr) - { } - - constexpr _Optional_payload(__ctor_tag, _Tp&& __other) - : _M_payload(std::move(__other)), - _M_engaged(true), - _M_pmr(__other._M_pmr) - { } - - constexpr - _Optional_payload(bool __engaged, const _Optional_payload& __other) - : _Optional_payload(__engaged ? - _Optional_payload(__ctor_tag{}, - __other._M_payload) : - _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - constexpr - _Optional_payload(bool __engaged, _Optional_payload&& __other) - : _Optional_payload(__engaged - ? _Optional_payload(__ctor_tag{}, - std::move(__other._M_payload)) - : _Optional_payload(__ctor_tag{})) - { _M_pmr = __other._M_pmr; } - - _Optional_payload(const _Optional_payload&) = default; - _Optional_payload(_Optional_payload&&) = default; - - _Optional_payload& - operator=(const _Optional_payload& __other) + + constexpr void + _M_destroy() noexcept { - if (this->_M_engaged && __other._M_engaged) - this->_M_get() = __other._M_get(); - else - { - if (__other._M_engaged) - this->_M_construct(__other._M_get()); - else - this->_M_reset(); - } - return *this; + _M_engaged = false; + _M_payload._M_value.~_Stored_type(); } - _Optional_payload& - operator=(_Optional_payload&& __other) - noexcept(__and_v, - is_nothrow_move_assignable<_Tp>>) - { - if (this->_M_engaged && __other._M_engaged) - this->_M_get() = std::move(__other._M_get()); - else - { - if (__other._M_engaged) - this->_M_construct(std::move(__other._M_get())); - else - this->_M_reset(); - } - return *this; - } - - using _Stored_type = remove_const_t<_Tp>; - - struct _Empty_byte { }; - - union { - _Empty_byte _M_empty; - _Stored_type _M_payload; - }; - bool _M_engaged; - memory_resource* _M_pmr; - - template - void - _M_construct(_Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - if (_M_pmr) - { - __uses_allocator_construct(polymorphic_allocator<_Stored_type>(_M_pmr), - std::__addressof(this->_M_payload), - std::forward<_Args>(__args)...); - } - else - { - ::new ((void *) std::__addressof(this->_M_payload)) - _Stored_type(std::forward<_Args>(__args)...); - } - this->_M_engaged = true; - } + // The _M_get() operations have _M_engaged as a precondition. + // They exist to access the contained value with the appropriate + // const-qualification, because _M_payload has had the const removed. - // The _M_get operations have _M_engaged as a precondition. constexpr _Tp& _M_get() noexcept - { return this->_M_payload; } + { return this->_M_payload._M_value; } constexpr const _Tp& _M_get() const noexcept - { return this->_M_payload; } + { return this->_M_payload._M_value; } // _M_reset is a 'safe' operation with no precondition. - void + constexpr void _M_reset() noexcept { if (this->_M_engaged) - { - this->_M_engaged = false; - this->_M_payload.~_Stored_type(); - } - } - }; - - template - class _Optional_base_impl - { - protected: - using _Stored_type = remove_const_t<_Tp>; - - // The _M_construct operation has !_M_engaged as a precondition - // while _M_destruct has _M_engaged as a precondition. - template - void - _M_construct(memory_resource* __pmr, _Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - __uses_allocator_construct(polymorphic_allocator(__pmr), - std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload), - std::forward<_Args>(__args)...); - static_cast<_Dp*>(this)->_M_payload._M_engaged = true; - } - - template - void - _M_construct(_Args&&... __args) - noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) - { - if (static_cast<_Dp*>(this)->_M_payload._M_pmr) - { - __uses_allocator_construct(polymorphic_allocator(static_cast<_Dp*>(this)->_M_payload._M_pmr), - std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload), - std::forward<_Args>(__args)...); - } - else - { - ::new - (std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload)) - _Stored_type(std::forward<_Args>(__args)...); - } - static_cast<_Dp*>(this)->_M_payload._M_engaged = true; - } - - void - _M_destruct() noexcept - { - static_cast<_Dp*>(this)->_M_payload._M_engaged = false; - static_cast<_Dp*>(this)->_M_payload._M_payload.~_Stored_type(); - } - - // _M_reset is a 'safe' operation with no precondition. - void - _M_reset() noexcept - { - if (static_cast<_Dp*>(this)->_M_payload._M_engaged) - static_cast<_Dp*>(this)->_M_destruct(); - } - - void _M_set_allocator(memory_resource* __pmr) noexcept - { - if (__pmr) - static_cast<_Dp*>(this)->_M_payload._M_pmr = __pmr; - else - static_cast<_Dp*>(this)->_M_payload._M_pmr = std::pmr::get_default_resource(); - } - memory_resource* _M_get_allocator() noexcept - { - return static_cast<_Dp*>(this)->_M_payload._M_pmr; - } - }; - - /** - * @brief Class template that takes care of copy/move constructors - of optional - * - * Such a separate base class template is necessary in order to - * conditionally make copy/move constructors trivial. - * @see optional, _Enable_special_members - */ - template, - bool = is_trivially_move_constructible_v<_Tp>> - class _Optional_base - // protected inheritance because optional needs to reach that base too - : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> - { - friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; - - public: - // Constructors for disengaged optionals. - constexpr _Optional_base() = default; - - // Constructors for engaged optionals. - template, bool> = false> - constexpr explicit _Optional_base(in_place_t, _Args&&... __args) - : _M_payload(in_place, - std::forward<_Args>(__args)...) { } - - // Constructors for engaged optionals. - template, _Args&&...>, bool> = false> - constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) - : _M_payload(__pmr, - std::forward<_Args>(__args)...) { } - - template&, - _Args&&...>, bool> = false> - constexpr explicit _Optional_base(in_place_t, - initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(in_place, - __il, std::forward<_Args>(__args)...) - { } - - // Copy and move constructors. - constexpr _Optional_base(const _Optional_base& __other) - : _M_payload(__other._M_payload._M_engaged, - __other._M_payload) - { } - - constexpr _Optional_base(_Optional_base&& __other) - noexcept(is_nothrow_move_constructible_v<_Tp>) - : _M_payload(__other._M_payload._M_engaged, - std::move(__other._M_payload)) - { } - - // Assignment operators. - _Optional_base& operator=(const _Optional_base&) = default; - _Optional_base& operator=(_Optional_base&&) = default; - - protected: - - constexpr bool _M_is_engaged() const noexcept - { return this->_M_payload._M_engaged; } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } - - constexpr const _Tp& - _M_get() const noexcept - { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } - - private: - _Optional_payload<_Tp> _M_payload; - }; - - template - class _Optional_base<_Tp, false, true> - : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> - { - friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; - public: - - // Constructors for disengaged optionals. - constexpr _Optional_base() = default; - - // Constructors for engaged optionals. - template, bool> = false> - constexpr explicit _Optional_base(in_place_t, _Args&&... __args) - : _M_payload(in_place, - std::forward<_Args>(__args)...) { } - - // Constructors for engaged optionals. - template, _Args&&...>, bool> = false> - constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) - : _M_payload(__pmr, - std::forward<_Args>(__args)...) { } - - template&, - _Args&&...>, bool> = false> - constexpr explicit _Optional_base(in_place_t, - initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(in_place, - __il, std::forward<_Args>(__args)...) - { } - - // Copy and move constructors. - constexpr _Optional_base(const _Optional_base& __other) - : _M_payload(__other._M_payload._M_engaged, - __other._M_payload) - { } - - constexpr _Optional_base(_Optional_base&& __other) = default; - - // Assignment operators. - _Optional_base& operator=(const _Optional_base&) = default; - _Optional_base& operator=(_Optional_base&&) = default; - - protected: - - constexpr bool _M_is_engaged() const noexcept - { return this->_M_payload._M_engaged; } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } - - constexpr const _Tp& - _M_get() const noexcept - { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } - - private: - _Optional_payload<_Tp> _M_payload; - }; - - template - class _Optional_base<_Tp, true, false> - : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> - { - friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; - public: - - // Constructors for disengaged optionals. - constexpr _Optional_base() = default; - - // Constructors for engaged optionals. - template, bool> = false> - constexpr explicit _Optional_base(in_place_t, _Args&&... __args) - : _M_payload(in_place, - std::forward<_Args>(__args)...) { } - - template, _Args&&...>, bool> = false> - constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) - : _M_payload(__pmr, - std::forward<_Args>(__args)...) { } - - template&, - _Args&&...>, bool> = false> - constexpr explicit _Optional_base(in_place_t, - initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(in_place, - __il, std::forward<_Args>(__args)...) - { } - - // Copy and move constructors. - constexpr _Optional_base(const _Optional_base& __other) = default; - - constexpr _Optional_base(_Optional_base&& __other) - noexcept(is_nothrow_move_constructible_v<_Tp>) - : _M_payload(__other._M_payload._M_engaged, - std::move(__other._M_payload)) - { } - - // Assignment operators. - _Optional_base& operator=(const _Optional_base&) = default; - _Optional_base& operator=(_Optional_base&&) = default; - - protected: - - constexpr bool _M_is_engaged() const noexcept - { return this->_M_payload._M_engaged; } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } - - constexpr const _Tp& - _M_get() const noexcept - { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } - - private: - _Optional_payload<_Tp> _M_payload; - }; - - template - class _Optional_base<_Tp, true, true> - : protected _Optional_base_impl<_Tp, _Optional_base<_Tp>> - { - friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>; - public: - - // Constructors for disengaged optionals. - constexpr _Optional_base() = default; - - // Constructors for engaged optionals. - template, bool> = false> - constexpr explicit _Optional_base(in_place_t, _Args&&... __args) - : _M_payload(in_place, - std::forward<_Args>(__args)...) { } - - template, _Args&&...>, bool> = false> - constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) - : _M_payload(__pmr, - std::forward<_Args>(__args)...) { } - - template&, - _Args&&...>, bool> = false> - constexpr explicit _Optional_base(in_place_t, - initializer_list<_Up> __il, - _Args&&... __args) - : _M_payload(in_place, - __il, std::forward<_Args>(__args)...) - { } - - // Copy and move constructors. - constexpr _Optional_base(const _Optional_base& __other) = default; - constexpr _Optional_base(_Optional_base&& __other) = default; - - // Assignment operators. - _Optional_base& operator=(const _Optional_base&) = default; - _Optional_base& operator=(_Optional_base&&) = default; - - protected: - - constexpr bool _M_is_engaged() const noexcept - { return this->_M_payload._M_engaged; } - - // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& - _M_get() noexcept - { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } - - constexpr const _Tp& - _M_get() const noexcept - { - __glibcxx_assert(this->_M_is_engaged()); - return this->_M_payload._M_payload; - } - - private: - _Optional_payload<_Tp> _M_payload; - }; - - template - class optional; - - template - using __converts_from_optional = - __or_&>, - is_constructible<_Tp, optional<_Up>&>, - is_constructible<_Tp, const optional<_Up>&&>, - is_constructible<_Tp, optional<_Up>&&>, - is_convertible&, _Tp>, - is_convertible&, _Tp>, - is_convertible&&, _Tp>, - is_convertible&&, _Tp>, - is_constructible<_Tp, const std::optional<_Up>&>, - is_constructible<_Tp, std::optional<_Up>&>, - is_constructible<_Tp, const std::optional<_Up>&&>, - is_constructible<_Tp, std::optional<_Up>&&>, - is_convertible&, _Tp>, - is_convertible&, _Tp>, - is_convertible&&, _Tp>, - is_convertible&&, _Tp>>; - - template - using __assigns_from_optional = - __or_&>, - is_assignable<_Tp&, optional<_Up>&>, - is_assignable<_Tp&, const optional<_Up>&&>, - is_assignable<_Tp&, optional<_Up>&&>, - is_assignable<_Tp&, const std::optional<_Up>&>, - is_assignable<_Tp&, std::optional<_Up>&>, - is_assignable<_Tp&, const std::optional<_Up>&&>, - is_assignable<_Tp&, std::optional<_Up>&&>>; - /* - template - struct __has_allocator_type - { - using __alloc_param_type = __nonesuch; - }; - - template - struct __has_allocator_type<_Tp, __void_t> - { - using __alloc_param_type = - typename __remove_cvref_t<_Tp>::allocator_type; - }; - */ - /** - * @brief Class template for optional values. - */ - template - class optional - : private _Optional_base<_Tp>, - private _Enable_copy_move< - // Copy constructor. - is_copy_constructible_v<_Tp>, - // Copy assignment. - __and_v, is_copy_assignable<_Tp>>, - // Move constructor. - is_move_constructible_v<_Tp>, - // Move assignment. - __and_v, is_move_assignable<_Tp>>, - // Unique tag type. - optional<_Tp>> - { - static_assert(!is_same_v, nullopt_t>); - static_assert(!is_same_v, in_place_t>); - static_assert(!is_reference_v<_Tp>); - - private: - using _Base = _Optional_base<_Tp>; - - // SFINAE helpers - template - using __not_self = __not_>>; - template - using __not_tag = __not_>>; - template - using _Requires = enable_if_t<__and_v<_Cond...>, bool>; - - public: - /* - using __alloc_param_type = - typename __has_allocator_type<_Tp>::__alloc_param_type; - */ - using value_type = _Tp; - - constexpr optional() - { - this->_M_set_allocator(std::pmr::get_default_resource()); - } - - constexpr optional(nullopt_t) noexcept { } - - // Converting constructors for engaged optionals. - template, __not_tag<_Up>, - __not_>>>, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>> = true> - constexpr - optional(_Up&& __t) - : _Base(std::in_place, std::forward<_Up>(__t)) { } - - template, __not_tag<_Up>, - __not_>>>, - is_constructible<_Tp, _Up&&>, - __not_>> = false> - explicit constexpr - optional(_Up&& __t) - : _Base(std::in_place, std::forward<_Up>(__t)) { } - - template>, - is_constructible<_Tp, const _Up&>, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(const optional<_Up>& __t) - { - if (__t) - emplace(*__t); - } - - template>, - is_constructible<_Tp, const _Up&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(const optional<_Up>& __t) - { - if (__t) - emplace(*__t); - } - - template >, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(optional<_Up>&& __t) - { - if (__t) - emplace(std::move(*__t)); - } - - template >, - is_constructible<_Tp, _Up&&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(optional<_Up>&& __t) - { - if (__t) - emplace(std::move(*__t)); - } - - template>, - is_constructible<_Tp, const _Up&>, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(const std::optional<_Up>& __t) - { - if (__t) - emplace(*__t); - } - - template>, - is_constructible<_Tp, const _Up&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(const std::optional<_Up>& __t) - { - if (__t) - emplace(*__t); - } - - template >, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(std::optional<_Up>&& __t) - { - if (__t) - emplace(std::move(*__t)); - } - - template >, - is_constructible<_Tp, _Up&&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(std::optional<_Up>&& __t) - { - if (__t) - emplace(std::move(*__t)); - } - - constexpr - optional(const std::optional<_Tp>& __t) - { - if (__t) - emplace(std::move(*__t)); - } - - constexpr - optional(std::optional<_Tp>&& __t) - { - if (__t) - emplace(std::move(*__t)); - } - // Converting memory-resource-constructors for engaged optionals. - - optional(memory_resource* __pmr) - { - if (!__pmr) - this->_M_set_allocator(std::pmr::get_default_resource()); - else - this->_M_set_allocator(__pmr); - } - template, __not_tag<_Up>, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>> = true> - constexpr - optional(_Up&& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - __emplace_alloc(__actual_alloc, std::forward<_Up>(__t)); - } - - template, __not_tag<_Up>, - is_constructible<_Tp, _Up&&>, - __not_>> = false> - explicit constexpr - optional(_Up&& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - __emplace_alloc(__actual_alloc, std::forward<_Up>(__t)); - } - - template>, - is_constructible<_Tp, const _Up&>, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(const optional<_Up>& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - __emplace_alloc(__actual_alloc, *__t); - } - - template>, - is_constructible<_Tp, const _Up&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(const optional<_Up>& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - if (__t) - this->_M_set_allocator(__actual_alloc); - __emplace_alloc(__actual_alloc, *__t); - } - - template >, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(optional<_Up>&& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - if (__t) - __emplace_alloc(__actual_alloc, std::move(*__t)); - } - - template >, - is_constructible<_Tp, _Up&&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(optional<_Up>&& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - if (__t) - __emplace_alloc(__actual_alloc, std::move(*__t)); - } - - constexpr - optional(const optional& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - if (__t) - __emplace_alloc(__actual_alloc, *__t); - } - - constexpr - optional(optional&& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - if (__t) - __emplace_alloc(__actual_alloc, std::move(*__t)); + _M_destroy(); } + + // Destructor needs to destroy the contained value: + ~_Optional_payload() { this->_M_reset(); } + }; - template, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(const std::optional<_Up>& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - if (__t) - __emplace_alloc(__actual_alloc, *__t); - } - - template, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(const std::optional<_Up>& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - if (__t) - __emplace_alloc(__actual_alloc, *__t); - } - - template , - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(std::optional<_Up>&& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - if (__t) - __emplace_alloc(__actual_alloc, std::move(*__t)); - } - template , - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(std::optional<_Up>&& __t, memory_resource* __pmr) - { - memory_resource* __actual_alloc = __pmr ? __pmr : std::pmr::get_default_resource(); - this->_M_set_allocator(__actual_alloc); - if (__t) - __emplace_alloc(__actual_alloc, std::move(*__t)); - } + /** + * @brief Class template that takes care of copy/move constructors + of optional + * + * Such a separate base class template is necessary in order to + * conditionally make copy/move constructors trivial. + * @see optional, _Enable_special_members + */ + template + class _Optional_base + { + using _Stored_type = remove_const_t<_Tp>; + + public: + // Constructors for disengaged optionals. + constexpr _Optional_base() = default; + + // Constructors for engaged optionals. + template, bool> = false> + constexpr explicit _Optional_base(in_place_t, _Args&&... __args) + { + _M_construct(std::forward<_Args>(__args)...); + } + + template&, + _Args&&...>, bool> = false> + constexpr explicit _Optional_base(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + { + _M_construct(__il,std::forward<_Args>(__args)...); + } + + + // Constructors for engaged optionals. + template, _Args&&...>, bool> = false> + constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) + { + _M_payload._M_pmr = __pmr; + _M_construct(std::forward<_Args>(__args)...); + } + + // Copy and move constructors. + constexpr _Optional_base(const _Optional_base& __other) + : _M_payload(__other._M_payload) + { } + + + constexpr _Optional_base(_Optional_base&& __other) + noexcept(is_nothrow_move_constructible_v<_Tp>) + : _M_payload(std::move(__other._M_payload)) + { } + + // Assignment operators. + _Optional_base& operator=(const _Optional_base&) = default; + _Optional_base& operator=(_Optional_base&&) = default; + + protected: + // The _M_construct operation has !_M_engaged as a precondition + // while _M_destruct has _M_engaged as a precondition. + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + _M_payload._M_construct( + std::forward<_Args>(__args)...); + } + + void + _M_destruct() noexcept + {_M_payload._M_destroy(); } + + // _M_reset is a 'safe' operation with no precondition. + constexpr void + _M_reset() noexcept + { _M_payload._M_reset(); } + + constexpr bool _M_is_engaged() const noexcept + { return this->_M_payload._M_engaged; } + + // The _M_get operations have _M_engaged as a precondition. + constexpr _Tp& + _M_get() noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return this->_M_payload._M_get(); + } + + constexpr const _Tp& + _M_get() const noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return this->_M_payload._M_get(); + } + - // Converting allocator-constructors for engaged optionals. - template, __not_tag<_Up>, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>> = true> - constexpr - optional(_Up&& __t, const polymorphic_allocator& __pmr) - : _Base(__pmr.resource(), std::forward<_Up>(__t)) { } - - template, __not_tag<_Up>, - is_constructible<_Tp, _Up&&>, - __not_>> = false> - explicit constexpr - optional(_Up&& __t, const polymorphic_allocator& __pmr) - : _Base(__pmr.resource(), std::forward<_Up>(__t)) { } - - template>, - is_constructible<_Tp, const _Up&>, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(const optional<_Up>& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, *__t); - } + void _M_set_allocator(memory_resource* __pmr) noexcept + { + _M_payload._M_pmr = __pmr; + } + + memory_resource* _M_get_allocator() const noexcept + { + return _M_payload._M_pmr; + } + + private: + _Optional_payload<_Tp> _M_payload; + }; - template>, - is_constructible<_Tp, const _Up&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(const optional<_Up>& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, *__t); - } - template >, - is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(optional<_Up>&& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, std::move(*__t)); - } + template + using __converts_from_optional = + __or_&>, + is_constructible<_Tp, __pmroptional<_Up>&>, + is_constructible<_Tp, const __pmroptional<_Up>&&>, + is_constructible<_Tp, __pmroptional<_Up>&&>, + is_convertible&, _Tp>, + is_convertible<__pmroptional<_Up>&, _Tp>, + is_convertible&&, _Tp>, + is_convertible<__pmroptional<_Up>&&, _Tp>, + is_constructible<_Tp, const std::optional<_Up>&>, + is_constructible<_Tp, std::optional<_Up>&>, + is_constructible<_Tp, const std::optional<_Up>&&>, + is_constructible<_Tp, std::optional<_Up>&&>, + is_convertible&, _Tp>, + is_convertible&, _Tp>, + is_convertible&&, _Tp>, + is_convertible&&, _Tp>>; - template >, - is_constructible<_Tp, _Up&&>, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(optional<_Up>&& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, std::move(*__t)); - } + template + using __assigns_from_optional = + __or_&>, + is_assignable<_Tp&, __pmroptional<_Up>&>, + is_assignable<_Tp&, const __pmroptional<_Up>&&>, + is_assignable<_Tp&, __pmroptional<_Up>&&>, + is_assignable<_Tp&, const std::optional<_Up>&>, + is_assignable<_Tp&, std::optional<_Up>&>, + is_assignable<_Tp&, const std::optional<_Up>&&>, + is_assignable<_Tp&, std::optional<_Up>&&>>; - template, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(const std::optional<_Up>& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, *__t); - } - template, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(const std::optional<_Up>& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, *__t); - } + /** + * @brief Class template for optional values. + */ + template + class __pmroptional + : private _Optional_base<_Tp>, + private _Enable_copy_move< + // Copy constructor. + is_copy_constructible_v<_Tp>, + // Copy assignment. + __and_v, is_copy_assignable<_Tp>>, + // Move constructor. + is_move_constructible_v<_Tp>, + // Move assignment. + __and_v, is_move_assignable<_Tp>>, + // Unique tag type. + __pmroptional<_Tp>> + { + static_assert(!is_same_v, nullopt_t>); + static_assert(!is_same_v, allocator_arg_t>); + static_assert(!is_reference_v<_Tp>); - template , - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - optional(std::optional<_Up>&& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, std::move(*__t)); - } + template friend class __pmroptional; + + private: + using _Base = _Optional_base<_Tp>; - template , - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - optional(std::optional<_Up>&& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, std::move(*__t)); - } + // SFINAE helpers + template + using __not_self = __not_>>; + template + using __not_tag = __not_>>; + template + using _Requires = enable_if_t<__and_v<_Cond...>, bool>; - constexpr - optional(const optional& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, *__t); + + public: + using value_type = _Tp; + using __Allocator_type = std::pmr::polymorphic_allocator; + + constexpr __pmroptional() noexcept { } - constexpr - optional(optional&& __t, const polymorphic_allocator& __pmr) - { - this->_M_set_allocator(__pmr.resource()); - if (__t) - __emplace_alloc(__pmr, std::move(*__t)); - } + constexpr __pmroptional(nullopt_t) noexcept { } + __pmroptional(const __pmroptional&) = default; + __pmroptional(__pmroptional&&) = default; + + + // Converting constructors for engaged optionals. + template, __not_tag<_Up>, + __not_>>>, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>> = true> + constexpr + __pmroptional(_Up&& __t) + { emplace(std::forward<_Up>(__t)); + }; + + template, __not_tag<_Up>, + __not_>>>, + is_constructible<_Tp, _Up&&>, + __not_>> = false> + explicit constexpr + __pmroptional(_Up&& __t) + { emplace(std::forward<_Up>(__t)); + }; + + template>, + is_constructible<_Tp, const _Up&>, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(const __pmroptional<_Up>& __t) + { + this->_M_set_allocator(__t._M_get_allocator()); + if (__t) + emplace(*__t); + } + + template>, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(const __pmroptional<_Up>& __t) + { + this->_M_set_allocator(__t._M_get_allocator()); + if (__t) + emplace(*__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(__pmroptional<_Up>&& __t) + { + this->_M_set_allocator(__t._M_get_allocator()); + if (__t) + emplace(std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(__pmroptional<_Up>&& __t) + { + this->_M_set_allocator(__t._M_get_allocator()); + if (__t) + emplace(std::move(*__t)); + } + + template, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(const std::optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(const std::optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template , + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(std::optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + template , + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(std::optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } template> = false> explicit constexpr - optional(in_place_t, _Args&&... __args) + __pmroptional(in_place_t, _Args&&... __args) : _Base(std::in_place, std::forward<_Args>(__args)...) { } template&, _Args&&...>> = false> explicit constexpr - optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) + __pmroptional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { } + // Converting memory-resource-constructors for engaged optionals. + + __pmroptional(allocator_arg_t, const __Allocator_type& __a) + { + this->_M_set_allocator(__a.resource()); + } + template, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>> = true> + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a,_Up&& __t) + { + this->_M_set_allocator(__a.resource()); + emplace(std::forward<_Up>(__t)); + } + + template, + is_constructible<_Tp, _Up&&>, + __not_>> = false> + explicit constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, _Up&& __t) + { + this->_M_set_allocator(__a.resource()); + emplace(std::forward<_Up>(__t)); + } + + template>, + is_constructible<_Tp, const _Up&>, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional<_Up>& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(*__t); + } + + template>, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional<_Up>& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(*__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional<_Up>&& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional<_Up>&& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(std::move(*__t)); + } + + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(*__t); + } + + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional&& __t) + { + memory_resource* __actual_alloc = __a.resource(); + if (__t) + emplace(std::move(*__t)); + } + + template, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional<_Up>& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(*__t); + } + + template, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional<_Up>& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(*__t); + } + + template , + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional<_Up>&& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(std::move(*__t)); + } + + template , + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional<_Up>&& __t) + { + this->_M_set_allocator(__a.resource()); + if (__t) + emplace(std::move(*__t)); + } + // Assignment operators. - optional& + __pmroptional& operator=(nullopt_t) noexcept { this->_M_reset(); return *this; } - + + // Assignment operators. + __pmroptional& operator=(const __pmroptional&) = default; + __pmroptional& operator=(__pmroptional&&) = default; + template - enable_if_t<__and_v<__not_self<_Up>, - __not_<__and_, - is_same<_Tp, decay_t<_Up>>>>, - is_constructible<_Tp, _Up>, - is_assignable<_Tp&, _Up>>, - optional&> - operator=(_Up&& __u) - { - if (this->_M_is_engaged()) - this->_M_get() = std::forward<_Up>(__u); - else - this->_M_construct(std::forward<_Up>(__u)); - - return *this; - } - - template - enable_if_t<__and_v<__not_>, - is_constructible<_Tp, const _Up&>, - is_assignable<_Tp&, _Up>, - __not_<__converts_from_optional<_Tp, _Up>>, - __not_<__assigns_from_optional<_Tp, _Up>>>, - optional&> - operator=(const optional<_Up>& __u) - { - if (__u) - { - if (this->_M_is_engaged()) - this->_M_get() = *__u; - else - this->_M_construct(*__u); - } - else - { - this->_M_reset(); - } - return *this; - } - - template - enable_if_t<__and_v<__not_>, - is_constructible<_Tp, _Up>, - is_assignable<_Tp&, _Up>, - __not_<__converts_from_optional<_Tp, _Up>>, - __not_<__assigns_from_optional<_Tp, _Up>>>, - optional&> - operator=(optional<_Up>&& __u) - { - if (__u) - { - if (this->_M_is_engaged()) - this->_M_get() = std::move(*__u); - else - this->_M_construct(std::move(*__u)); - } - else - { - this->_M_reset(); - } - - return *this; - } - - template + enable_if_t<__and_v<__not_self<_Up>, + __not_<__and_, + is_same<_Tp, decay_t<_Up>>>>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>>, + __pmroptional&> + operator=(_Up&& __u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::forward<_Up>(__u); + else + this->_M_construct(std::forward<_Up>(__u)); + + return *this; + } + + template + enable_if_t<__and_v<__not_>, + is_constructible<_Tp, const _Up&>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + __pmroptional&> + operator=(const __pmroptional<_Up>& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = *__u; + else + this->_M_construct(*__u); + } + else + { + this->_M_reset(); + } + return *this; + } + + template + enable_if_t<__and_v<__not_>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + __pmroptional&> + operator=(__pmroptional<_Up>&& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::move(*__u); + else + this->_M_construct(std::move(*__u)); + } + else + { + this->_M_reset(); + } + + return *this; + } + + + + template enable_if_t<__and_v, - is_assignable<_Tp&, _Up>, - __not_<__converts_from_optional<_Tp, _Up>>, - __not_<__assigns_from_optional<_Tp, _Up>>>, - optional&> + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + __pmroptional&> operator=(const std::optional<_Up>& __u) { if (__u) - { - if (this->_M_is_engaged()) + { + if (this->_M_is_engaged()) this->_M_get() = *__u; - else + else this->_M_construct(*__u); - } + } else - { - this->_M_reset(); - } + { + this->_M_reset(); + } return *this; } - template - enable_if_t<__and_v, - is_assignable<_Tp&, _Up>, - __not_<__converts_from_optional<_Tp, _Up>>, - __not_<__assigns_from_optional<_Tp, _Up>>>, - optional&> + template + enable_if_t<__and_v, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + __pmroptional&> operator=(std::optional<_Up>&& __u) { if (__u) - { - if (this->_M_is_engaged()) + { + if (this->_M_is_engaged()) this->_M_get() = std::move(*__u); - else + else this->_M_construct(std::move(*__u)); - } + } else - { - this->_M_reset(); - } - + { + this->_M_reset(); + } + return *this; } - - + template enable_if_t, _Tp&> emplace(_Args&&... __args) @@ -1793,26 +807,6 @@ namespace pmr { return this->_M_get(); } - template - //enable_if_t<__is_uses_allocator_constructible_v<_Tp, polymorphic_allocator, _Args&&...>, _Tp&> - _Tp& - __emplace_alloc(memory_resource* __pmr, _Args&&... __args) - { - this->_M_reset(); - this->_M_construct(__pmr, std::forward<_Args>(__args)...); - return this->_M_get(); - } - - template - //enable_if_t<__is_uses_allocator_constructible_v<_Tp, polymorphic_allocator, _Args&&...>, _Tp&> - _Tp& - __emplace_alloc(const polymorphic_allocator& __pmr, _Args&&... __args) - { - this->_M_reset(); - this->_M_construct(__pmr.resource(), std::forward<_Args>(__args)...); - return this->_M_get(); - } - template enable_if_t&, _Args&&...>, _Tp&> @@ -1827,7 +821,7 @@ namespace pmr { // Swap. void - swap(optional& __other) + swap(__pmroptional& __other) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>) { @@ -1852,7 +846,7 @@ namespace pmr { operator->() const { return std::__addressof(this->_M_get()); } - _Tp* + constexpr _Tp* operator->() { return std::__addressof(this->_M_get()); } @@ -1882,36 +876,32 @@ namespace pmr { value() const& { return this->_M_is_engaged() - ? this->_M_get() - : (__throw_bad_optional_access(), - this->_M_get()); + ? this->_M_get() + : (__throw_bad_optional_access(), this->_M_get()); } constexpr _Tp& value()& { return this->_M_is_engaged() - ? this->_M_get() - : (__throw_bad_optional_access(), - this->_M_get()); + ? this->_M_get() + : (__throw_bad_optional_access(), this->_M_get()); } constexpr _Tp&& value()&& { return this->_M_is_engaged() - ? std::move(this->_M_get()) - : (__throw_bad_optional_access(), - std::move(this->_M_get())); + ? std::move(this->_M_get()) + : (__throw_bad_optional_access(), std::move(this->_M_get())); } constexpr const _Tp&& value() const&& { return this->_M_is_engaged() - ? std::move(this->_M_get()) - : (__throw_bad_optional_access(), - std::move(this->_M_get())); + ? std::move(this->_M_get()) + : (__throw_bad_optional_access(), std::move(this->_M_get())); } template @@ -1922,12 +912,11 @@ namespace pmr { static_assert(is_convertible_v<_Up&&, _Tp>); return this->_M_is_engaged() - ? this->_M_get() - : static_cast<_Tp>(std::forward<_Up>(__u)); + ? this->_M_get() : static_cast<_Tp>(std::forward<_Up>(__u)); } template - _Tp + constexpr _Tp value_or(_Up&& __u) && { static_assert(is_move_constructible_v<_Tp>); @@ -1939,83 +928,7 @@ namespace pmr { } void reset() noexcept { this->_M_reset(); } - - // bloomberg extensions start here - template - _Tp& makeValue(_Up&& __u) - { - memory_resource* __actual_alloc = this->_M_get_allocator(); - if (__actual_alloc) { - this->__emplace_alloc(__actual_alloc, std::forward<_Up>(__u)); - } - else - this->emplace(std::forward<_Up>(__u)); - - return *(*this); - } - - _Tp& makeValue() - { - memory_resource* __actual_alloc = this->_M_get_allocator(); - if (__actual_alloc) { - this->__emplace_alloc(__actual_alloc); - } - else - this->emplace(); - return *(*this); - } - - template - _Tp& makeValueInplace(_Args&&... __args) - { - memory_resource* __actual_alloc = this->_M_get_allocator(); - if (__actual_alloc) - return this->__emplace_alloc(__actual_alloc, - std::forward<_Args>(__args)...); - else - return this->emplace(std::forward<_Args>(__args)...); - } - - bool isNull() const - { - return !this->has_value(); - } - - int maxSupportedBdexVersion(int versionSelector) const; - - template - _Stream& bdexStreamIn(_Stream& stream, int version); - - template - _Stream& bdexStreamOut(_Stream& stream, int version) const; - - template - auto& print(_Stream& stream, int level = 0, - int spacesPerLevel = 4) const; - - typedef _Tp ValueType; - - const _Tp* addressOr(const _Tp* __value) const - { - return this->isNull() ? __value : &this->value(); - } - - const _Tp* valueOrNull() const - { - return this->isNull() ? 0 : &this->value(); - } - - _Tp valueOr(const _Tp& __value) const - { - return this->isNull() ? __value : this->value(); - } - - const _Tp* valueOr(const _Tp* __value) const - { - return this->isNull() ? __value : &this->value(); - } - - }; +}; template using __optional_relop_t = @@ -2024,7 +937,7 @@ namespace pmr { // Comparisons between optional values. template constexpr auto - operator==(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + operator==(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() == declval<_Up>())> { return static_cast(__lhs) == static_cast(__rhs) @@ -2033,7 +946,7 @@ namespace pmr { template constexpr auto - operator!=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + operator!=(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() != declval<_Up>())> { return static_cast(__lhs) != static_cast(__rhs) @@ -2042,7 +955,7 @@ namespace pmr { template constexpr auto - operator<(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + operator<(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() < declval<_Up>())> { return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); @@ -2050,7 +963,7 @@ namespace pmr { template constexpr auto - operator>(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + operator>(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() > declval<_Up>())> { return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); @@ -2058,7 +971,7 @@ namespace pmr { template constexpr auto - operator<=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + operator<=(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() <= declval<_Up>())> { return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); @@ -2066,146 +979,264 @@ namespace pmr { template constexpr auto - operator>=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + operator>=(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() >= declval<_Up>())> { return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs); } + + template + constexpr auto + operator==(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() == declval<_Up>())> + { + return static_cast(__lhs) == static_cast(__rhs) + && (!__lhs || *__lhs == *__rhs); + } + + template + constexpr auto + operator!=(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() != declval<_Up>())> + { + return static_cast(__lhs) != static_cast(__rhs) + || (static_cast(__lhs) && *__lhs != *__rhs); + } + + template + constexpr auto + operator<(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { + return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); + } + + template + constexpr auto + operator>(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { + return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); + } + + template + constexpr auto + operator<=(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { + return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); + } + + template + constexpr auto + operator>=(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { + return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs); + } + + + template + constexpr auto + operator==(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() == declval<_Up>())> + { + return static_cast(__lhs) == static_cast(__rhs) + && (!__lhs || *__lhs == *__rhs); + } + + template + constexpr auto + operator!=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() != declval<_Up>())> + { + return static_cast(__lhs) != static_cast(__rhs) + || (static_cast(__lhs) && *__lhs != *__rhs); + } + + template + constexpr auto + operator<(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { + return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); + } + + template + constexpr auto + operator>(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { + return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); + } + + template + constexpr auto + operator<=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { + return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); + } + + template + constexpr auto + operator>=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { + return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs); + } // Comparisons with nullopt. template constexpr bool - operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept + operator==(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return !__lhs; } template constexpr bool - operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept + operator==(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return !__rhs; } template constexpr bool - operator!=(const optional<_Tp>& __lhs, nullopt_t) noexcept + operator!=(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return static_cast(__lhs); } template constexpr bool - operator!=(nullopt_t, const optional<_Tp>& __rhs) noexcept + operator!=(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return static_cast(__rhs); } template constexpr bool - operator<(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept + operator<(const __pmroptional<_Tp>& /* __lhs */, nullopt_t) noexcept { return false; } template constexpr bool - operator<(nullopt_t, const optional<_Tp>& __rhs) noexcept + operator<(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return static_cast(__rhs); } template constexpr bool - operator>(const optional<_Tp>& __lhs, nullopt_t) noexcept + operator>(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return static_cast(__lhs); } template constexpr bool - operator>(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept + operator>(nullopt_t, const __pmroptional<_Tp>& /* __rhs */) noexcept { return false; } template constexpr bool - operator<=(const optional<_Tp>& __lhs, nullopt_t) noexcept + operator<=(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return !__lhs; } template constexpr bool - operator<=(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept + operator<=(nullopt_t, const __pmroptional<_Tp>& /* __rhs */) noexcept { return true; } template constexpr bool - operator>=(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept + operator>=(const __pmroptional<_Tp>& /* __lhs */, nullopt_t) noexcept { return true; } template constexpr bool - operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept + operator>=(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return !__rhs; } // Comparisons with value type. template constexpr auto - operator==(const optional<_Tp>& __lhs, const _Up& __rhs) + operator==(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() == declval<_Up>())> { return __lhs && *__lhs == __rhs; } template constexpr auto - operator==(const _Up& __lhs, const optional<_Tp>& __rhs) + operator==(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() == declval<_Tp>())> { return __rhs && __lhs == *__rhs; } template constexpr auto - operator!=(const optional<_Tp>& __lhs, const _Up& __rhs) + operator!=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() != declval<_Up>())> { return !__lhs || *__lhs != __rhs; } template constexpr auto - operator!=(const _Up& __lhs, const optional<_Tp>& __rhs) + operator!=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() != declval<_Tp>())> { return !__rhs || __lhs != *__rhs; } template constexpr auto - operator<(const optional<_Tp>& __lhs, const _Up& __rhs) + operator<(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() < declval<_Up>())> { return !__lhs || *__lhs < __rhs; } template constexpr auto - operator<(const _Up& __lhs, const optional<_Tp>& __rhs) + operator<(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() < declval<_Tp>())> { return __rhs && __lhs < *__rhs; } template constexpr auto - operator>(const optional<_Tp>& __lhs, const _Up& __rhs) + operator>(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() > declval<_Up>())> { return __lhs && *__lhs > __rhs; } template constexpr auto - operator>(const _Up& __lhs, const optional<_Tp>& __rhs) + operator>(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() > declval<_Tp>())> { return !__rhs || __lhs > *__rhs; } template constexpr auto - operator<=(const optional<_Tp>& __lhs, const _Up& __rhs) + operator<=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() <= declval<_Up>())> { return !__lhs || *__lhs <= __rhs; } template constexpr auto - operator<=(const _Up& __lhs, const optional<_Tp>& __rhs) + operator<=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() <= declval<_Tp>())> { return __rhs && __lhs <= *__rhs; } template constexpr auto - operator>=(const optional<_Tp>& __lhs, const _Up& __rhs) + operator>=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() >= declval<_Up>())> { return __lhs && *__lhs >= __rhs; } template constexpr auto - operator>=(const _Up& __lhs, const optional<_Tp>& __rhs) + operator>=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() >= declval<_Tp>())> { return !__rhs || __lhs >= *__rhs; } +#if __cpp_deduction_guides >= 201606 + template __pmroptional(_Tp) -> __pmroptional<_Tp>; +#endif + + // Swap and creation functions. + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2748. swappable traits for optionals + template + inline enable_if_t && is_swappable_v<_Tp>> + swap(__pmroptional<_Tp>& __lhs, __pmroptional<_Tp>& __rhs) + noexcept(noexcept(__lhs.swap(__rhs))) + { __lhs.swap(__rhs); } + + template + enable_if_t && is_swappable_v<_Tp>)> + swap(__pmroptional<_Tp>&, __pmroptional<_Tp>&) = delete; template constexpr optional> @@ -2222,34 +1253,17 @@ namespace pmr { make_optional(initializer_list<_Up> __il, _Args&&... __args) { return optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; } - - /// @} - -#if __cpp_deduction_guides >= 201606 - template optional(_Tp) -> optional<_Tp>; -#endif + } // namespace pmr - // Swap and creation functions. - - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 2748. swappable traits for optionals - template - inline enable_if_t && is_swappable_v<_Tp>> - swap(pmr::optional<_Tp>& __lhs, pmr::optional<_Tp>& __rhs) - noexcept(noexcept(__lhs.swap(__rhs))) - { __lhs.swap(__rhs); } +// Hash. - template - enable_if_t && is_swappable_v<_Tp>)> - swap(pmr::optional<_Tp>&, pmr::optional<_Tp>&) = delete; - // Hash. template, bool = __poison_hash<_Up>::__enable_hash_call> struct __pmr_optional_hash_call_base { size_t - operator()(const pmr::optional<_Tp>& __t) const + operator()(const pmr::__pmroptional<_Tp>& __t) const noexcept(noexcept(hash<_Up>{}(*__t))) { // We pick an arbitrary hash for disengaged optionals which hopefully @@ -2263,21 +1277,26 @@ namespace pmr { struct __pmr_optional_hash_call_base<_Tp, _Up, false> {}; template - struct hash> + struct hash> : private __poison_hash>, public __pmr_optional_hash_call_base<_Tp> { using result_type [[__deprecated__]] = size_t; - using argument_type [[__deprecated__]] = pmr::optional<_Tp>; + using argument_type [[__deprecated__]] = pmr::__pmroptional<_Tp>; }; template - struct __is_fast_hash>> : __is_fast_hash> + struct __is_fast_hash>> : __is_fast_hash> { }; + + + /// @} + + template - struct uses_allocator, _Alloc> : true_type {}; -_GLIBCXX_END_NAMESPACE_VERSION + struct uses_allocator, _Alloc> : true_type {}; + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++17 diff --git a/groups/bdl/bdls/bdls_testutil.t.cpp b/groups/bdl/bdls/bdls_testutil.t.cpp index 2e6abce0ba..e20767e356 100644 --- a/groups/bdl/bdls/bdls_testutil.t.cpp +++ b/groups/bdl/bdls/bdls_testutil.t.cpp @@ -1373,8 +1373,8 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 2; - BDLS_TESTUTIL_LOOP5_ASSERT(I, J, K, L, M, + const int LINE = __LINE__ + 1; + BDLS_TESTUTIL_LOOP5_ASSERT(I, J, K, L, M, \ idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1476,8 +1476,8 @@ int main(int argc, char *argv[]) } output.reset(); - const int LINE = __LINE__ + 2; - BDLS_TESTUTIL_LOOP6_ASSERT(I, J, K, L, M, N, + const int LINE = __LINE__ + 1; + BDLS_TESTUTIL_LOOP6_ASSERT(I, J, K, L, M, N, \ idx > LOOP_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); diff --git a/groups/bsl/bslim/bslim_testutil.t.cpp b/groups/bsl/bslim/bslim_testutil.t.cpp index af9530f51f..a6a1382512 100644 --- a/groups/bsl/bslim/bslim_testutil.t.cpp +++ b/groups/bsl/bslim/bslim_testutil.t.cpp @@ -1818,7 +1818,7 @@ int main(int argc, char *argv[]) if (veryVerbose) { REALP(idx); } output.reset(); - const int LINE = __LINE__ + 2; + const int LINE = __LINE__ + 1; BSLIM_TESTUTIL_LOOP5_ASSERT(I, J, K, L, M, idx > NUM_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); @@ -1914,7 +1914,7 @@ int main(int argc, char *argv[]) if (veryVerbose) { REALP(idx); } output.reset(); - const int LINE = __LINE__ + 2; + const int LINE = __LINE__ + 1; BSLIM_TESTUTIL_LOOP6_ASSERT(I, J, K, L, M, N, idx > NUM_ITERATIONS); REALLOOP2_ASSERT(testStatus, idx, testStatus == idx + 1); From eaf99e7a61435eb96ce8abe10079d9396fc018d2 Mon Sep 17 00:00:00 2001 From: nina Queen of Awesome Date: Wed, 14 Aug 2019 13:03:39 +0100 Subject: [PATCH 10/14] adding local uses_allocator.h --- groups/bdl/bdlb/bdlb_nullablevalue.h | 2 +- groups/bdl/bdlb/uses_allocator.h | 244 +++++++++++++++++++++++++++ 2 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 groups/bdl/bdlb/uses_allocator.h diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.h b/groups/bdl/bdlb/bdlb_nullablevalue.h index 53923f3917..9533bf166a 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.h +++ b/groups/bdl/bdlb/bdlb_nullablevalue.h @@ -73,7 +73,7 @@ BSLS_IDENT("$Id: $") // nullableInt.reset(); // assert( nullableInt.isNull()); //.. - +#include #include #ifndef INCLUDED_BDLSCM_VERSION diff --git a/groups/bdl/bdlb/uses_allocator.h b/groups/bdl/bdlb/uses_allocator.h new file mode 100644 index 0000000000..caa4a10b19 --- /dev/null +++ b/groups/bdl/bdlb/uses_allocator.h @@ -0,0 +1,244 @@ +// Uses-allocator Construction -*- C++ -*- + +// Copyright (C) 2010-2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#ifndef _USES_ALLOCATOR_H +#define _USES_ALLOCATOR_H 1 + +#if __cplusplus < 201103L +# include +#else + +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + + template > + struct __domain_allocator_detector + : false_type + { + }; + + template + struct __domain_allocator_detector< _Tp, _Alloc, + __void_t> + : __is_invocable::type + { + using __rT = decltype(_Tp::domain_alloc_rebind); + inline static __rT* rebind = &_Tp::domain_alloc_rebind; + }; + + template + struct __domain_allocator_traits + : __domain_allocator_detector<_Tp, _Alloc> { + + }; + + template + struct __uses_domain_allocator + : __domain_allocator_traits<_Tp,_Alloc>::type + { }; + + // This is used for std::experimental::erased_type from Library Fundamentals. + struct __erased_type { }; + + // This also supports the "type-erased allocator" protocol from the + // Library Fundamentals TS, where allocator_type is erased_type. + // The second condition will always be false for types not using the TS. + template + using __is_erased_or_convertible + = __or_, + is_same<_Tp, __erased_type>>; + + /// [allocator.tag] + struct allocator_arg_t { explicit allocator_arg_t() = default; }; + + _GLIBCXX17_INLINE constexpr allocator_arg_t allocator_arg = + allocator_arg_t(); + + template> + struct __uses_allocator_helper + : false_type { }; + + template + struct __uses_allocator_helper<_Tp, _Alloc, + __void_t> + : __is_erased_or_convertible<_Alloc, typename _Tp::allocator_type>::type + { }; + + /// [allocator.uses.trait] + template + struct uses_allocator + : __or_<__uses_allocator_helper<_Tp, _Alloc>, + __uses_domain_allocator<_Tp,_Alloc>> + + { }; + + struct __uses_alloc_base { }; + + struct __uses_alloc0 : __uses_alloc_base + { + struct _Sink { void operator=(const void*) { } } _M_a; + }; + + template + struct __uses_alloc1 : __uses_alloc_base { const _Alloc* _M_a; }; + + template + struct __uses_alloc2 : __uses_alloc_base { const _Alloc* _M_a; }; + + template + struct __uses_alloc3 : __uses_alloc_base { const _Alloc* _M_a; }; + + template + struct __uses_alloc; + + template + struct __uses_alloc + : conditional< + is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>::value, + __uses_alloc1<_Alloc>, + __uses_alloc2<_Alloc>>::type + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2586. Wrong value category used in scoped_allocator_adaptor::construct + static_assert(__or_< + is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>, + is_constructible<_Tp, _Args..., const _Alloc&>>::value, + "construction with an allocator must be possible" + " if uses_allocator is true"); + }; + + template + struct __uses_alloc + : __uses_alloc3<_Alloc> { }; + + template + struct __uses_alloc + : __uses_alloc3<_Alloc> { }; + + template + struct __uses_alloc + : __uses_alloc0 { }; + + template + using __uses_alloc_t = + __uses_alloc<__and_, + __not_<__uses_domain_allocator<_Tp, _Alloc>>>::value, + __uses_domain_allocator<_Tp, _Alloc>::value, + _Tp, _Alloc, _Args...>; + + template + inline __uses_alloc_t<_Tp, _Alloc, _Args...> + __use_alloc(const _Alloc& __a) + { + __uses_alloc_t<_Tp, _Alloc, _Args...> __ret; + __ret._M_a = std::__addressof(__a); + return __ret; + } + + template + void + __use_alloc(const _Alloc&&) = delete; + +#if __cplusplus > 201402L + template + inline constexpr bool uses_allocator_v = + uses_allocator<_Tp, _Alloc>::value; +#endif // C++17 + + template class _Predicate, + typename _Tp, typename _Alloc, typename... _Args> + struct __is_uses_allocator_predicate + : conditional::value, + __or_<_Predicate<_Tp, allocator_arg_t, _Alloc, _Args...>, + _Predicate<_Tp, _Args..., _Alloc>>, + _Predicate<_Tp, _Args...>>::type { }; + + template + struct __is_uses_allocator_constructible + : __is_uses_allocator_predicate + { }; + +#if __cplusplus >= 201402L + template + _GLIBCXX17_INLINE constexpr bool __is_uses_allocator_constructible_v = + __is_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value; +#endif // C++14 + + template + struct __is_nothrow_uses_allocator_constructible + : __is_uses_allocator_predicate + { }; + + +#if __cplusplus >= 201402L + template + _GLIBCXX17_INLINE constexpr bool + __is_nothrow_uses_allocator_constructible_v = + __is_nothrow_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value; +#endif // C++14 + + template + void __uses_allocator_construct_impl(__uses_alloc0 __a, _Tp* __ptr, + _Args&&... __args) + { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)...); } + + template + void __uses_allocator_construct_impl(__uses_alloc1<_Alloc> __a, _Tp* __ptr, + _Args&&... __args) + { + ::new ((void*)__ptr) _Tp(allocator_arg, *__a._M_a, + std::forward<_Args>(__args)...); + } + + template + void __uses_allocator_construct_impl(__uses_alloc2<_Alloc> __a, _Tp* __ptr, + _Args&&... __args) + { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)..., *__a._M_a); } + + template + void __uses_allocator_construct_impl(__uses_alloc3<_Alloc> __a, _Tp* __ptr, + _Args&&... __args) + { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)..., + __domain_allocator_traits<_Tp, _Alloc>::rebind(*__a._M_a)); } + + template + void __uses_allocator_construct(const _Alloc& __a, _Tp* __ptr, + _Args&&... __args) + { + std::__uses_allocator_construct_impl( + std::__use_alloc<_Tp, _Alloc, _Args...>(__a), __ptr, + std::forward<_Args>(__args)...); + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif +#endif From 36c1123c26b44473539849356554f7c3ef849944 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Wed, 14 Aug 2019 15:50:32 +0300 Subject: [PATCH 11/14] adding local uses_allocator.h --- groups/bdl/bdlb/bdlb_nullablevalue.h | 2 +- groups/bdl/bdlb/uses_allocator.h | 244 +++++++++++++++++++++++++++ 2 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 groups/bdl/bdlb/uses_allocator.h diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.h b/groups/bdl/bdlb/bdlb_nullablevalue.h index 53923f3917..9533bf166a 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.h +++ b/groups/bdl/bdlb/bdlb_nullablevalue.h @@ -73,7 +73,7 @@ BSLS_IDENT("$Id: $") // nullableInt.reset(); // assert( nullableInt.isNull()); //.. - +#include #include #ifndef INCLUDED_BDLSCM_VERSION diff --git a/groups/bdl/bdlb/uses_allocator.h b/groups/bdl/bdlb/uses_allocator.h new file mode 100644 index 0000000000..caa4a10b19 --- /dev/null +++ b/groups/bdl/bdlb/uses_allocator.h @@ -0,0 +1,244 @@ +// Uses-allocator Construction -*- C++ -*- + +// Copyright (C) 2010-2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#ifndef _USES_ALLOCATOR_H +#define _USES_ALLOCATOR_H 1 + +#if __cplusplus < 201103L +# include +#else + +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + + template > + struct __domain_allocator_detector + : false_type + { + }; + + template + struct __domain_allocator_detector< _Tp, _Alloc, + __void_t> + : __is_invocable::type + { + using __rT = decltype(_Tp::domain_alloc_rebind); + inline static __rT* rebind = &_Tp::domain_alloc_rebind; + }; + + template + struct __domain_allocator_traits + : __domain_allocator_detector<_Tp, _Alloc> { + + }; + + template + struct __uses_domain_allocator + : __domain_allocator_traits<_Tp,_Alloc>::type + { }; + + // This is used for std::experimental::erased_type from Library Fundamentals. + struct __erased_type { }; + + // This also supports the "type-erased allocator" protocol from the + // Library Fundamentals TS, where allocator_type is erased_type. + // The second condition will always be false for types not using the TS. + template + using __is_erased_or_convertible + = __or_, + is_same<_Tp, __erased_type>>; + + /// [allocator.tag] + struct allocator_arg_t { explicit allocator_arg_t() = default; }; + + _GLIBCXX17_INLINE constexpr allocator_arg_t allocator_arg = + allocator_arg_t(); + + template> + struct __uses_allocator_helper + : false_type { }; + + template + struct __uses_allocator_helper<_Tp, _Alloc, + __void_t> + : __is_erased_or_convertible<_Alloc, typename _Tp::allocator_type>::type + { }; + + /// [allocator.uses.trait] + template + struct uses_allocator + : __or_<__uses_allocator_helper<_Tp, _Alloc>, + __uses_domain_allocator<_Tp,_Alloc>> + + { }; + + struct __uses_alloc_base { }; + + struct __uses_alloc0 : __uses_alloc_base + { + struct _Sink { void operator=(const void*) { } } _M_a; + }; + + template + struct __uses_alloc1 : __uses_alloc_base { const _Alloc* _M_a; }; + + template + struct __uses_alloc2 : __uses_alloc_base { const _Alloc* _M_a; }; + + template + struct __uses_alloc3 : __uses_alloc_base { const _Alloc* _M_a; }; + + template + struct __uses_alloc; + + template + struct __uses_alloc + : conditional< + is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>::value, + __uses_alloc1<_Alloc>, + __uses_alloc2<_Alloc>>::type + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2586. Wrong value category used in scoped_allocator_adaptor::construct + static_assert(__or_< + is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>, + is_constructible<_Tp, _Args..., const _Alloc&>>::value, + "construction with an allocator must be possible" + " if uses_allocator is true"); + }; + + template + struct __uses_alloc + : __uses_alloc3<_Alloc> { }; + + template + struct __uses_alloc + : __uses_alloc3<_Alloc> { }; + + template + struct __uses_alloc + : __uses_alloc0 { }; + + template + using __uses_alloc_t = + __uses_alloc<__and_, + __not_<__uses_domain_allocator<_Tp, _Alloc>>>::value, + __uses_domain_allocator<_Tp, _Alloc>::value, + _Tp, _Alloc, _Args...>; + + template + inline __uses_alloc_t<_Tp, _Alloc, _Args...> + __use_alloc(const _Alloc& __a) + { + __uses_alloc_t<_Tp, _Alloc, _Args...> __ret; + __ret._M_a = std::__addressof(__a); + return __ret; + } + + template + void + __use_alloc(const _Alloc&&) = delete; + +#if __cplusplus > 201402L + template + inline constexpr bool uses_allocator_v = + uses_allocator<_Tp, _Alloc>::value; +#endif // C++17 + + template class _Predicate, + typename _Tp, typename _Alloc, typename... _Args> + struct __is_uses_allocator_predicate + : conditional::value, + __or_<_Predicate<_Tp, allocator_arg_t, _Alloc, _Args...>, + _Predicate<_Tp, _Args..., _Alloc>>, + _Predicate<_Tp, _Args...>>::type { }; + + template + struct __is_uses_allocator_constructible + : __is_uses_allocator_predicate + { }; + +#if __cplusplus >= 201402L + template + _GLIBCXX17_INLINE constexpr bool __is_uses_allocator_constructible_v = + __is_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value; +#endif // C++14 + + template + struct __is_nothrow_uses_allocator_constructible + : __is_uses_allocator_predicate + { }; + + +#if __cplusplus >= 201402L + template + _GLIBCXX17_INLINE constexpr bool + __is_nothrow_uses_allocator_constructible_v = + __is_nothrow_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value; +#endif // C++14 + + template + void __uses_allocator_construct_impl(__uses_alloc0 __a, _Tp* __ptr, + _Args&&... __args) + { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)...); } + + template + void __uses_allocator_construct_impl(__uses_alloc1<_Alloc> __a, _Tp* __ptr, + _Args&&... __args) + { + ::new ((void*)__ptr) _Tp(allocator_arg, *__a._M_a, + std::forward<_Args>(__args)...); + } + + template + void __uses_allocator_construct_impl(__uses_alloc2<_Alloc> __a, _Tp* __ptr, + _Args&&... __args) + { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)..., *__a._M_a); } + + template + void __uses_allocator_construct_impl(__uses_alloc3<_Alloc> __a, _Tp* __ptr, + _Args&&... __args) + { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)..., + __domain_allocator_traits<_Tp, _Alloc>::rebind(*__a._M_a)); } + + template + void __uses_allocator_construct(const _Alloc& __a, _Tp* __ptr, + _Args&&... __args) + { + std::__uses_allocator_construct_impl( + std::__use_alloc<_Tp, _Alloc, _Args...>(__a), __ptr, + std::forward<_Args>(__args)...); + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif +#endif From 66708bd38ca7127df5ded879bde8848ae0de2c55 Mon Sep 17 00:00:00 2001 From: nina Queen of Awesome Date: Mon, 16 Sep 2019 16:52:52 +0100 Subject: [PATCH 12/14] adding pmroptional implementation that matches the paper --- groups/bdl/bdlb/bdlb_nullablevalue.h | 56 +- groups/bdl/bdlb/pmroptional | 1005 +++++++++++++++++++------- groups/bdl/bdlb/uses_allocator.h | 67 +- 3 files changed, 831 insertions(+), 297 deletions(-) diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.h b/groups/bdl/bdlb/bdlb_nullablevalue.h index 9533bf166a..c40dfea9d2 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.h +++ b/groups/bdl/bdlb/bdlb_nullablevalue.h @@ -179,7 +179,7 @@ BSLS_IDENT("$Id: $") #endif #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES - +/* namespace std { template struct __domain_allocator_traits struct bb_optional_wrap : private std::_Enable_copy_move< // Copy constructor. @@ -322,7 +323,7 @@ namespace std template struct uses_allocator, _Alloc> : true_type {}; } -*/ + namespace BloombergLP { namespace bdlb { @@ -334,9 +335,13 @@ namespace bdlb { // class NullableValue // ========================= +template +using optional_base = std::conditional_t::value, + std::pmr::optional> , + std::pmr::optional >; template -class NullableValue : public std::pmr::optional +class NullableValue : public optional_base { // This template class extends the set of values of its value-semantic @@ -385,7 +390,7 @@ class NullableValue : public std::pmr::optional NullableValue(typename bsl::enable_if< bslma::UsesBslmaAllocator::value, void>::type * = 0) - :std::pmr::optional(std::allocator_arg_t{}, + :optional_base(std::allocator_arg_t{}, std::pmr::polymorphic_allocator( (std::pmr::memory_resource*)(bslma::Default::allocator(nullptr)))) { @@ -394,7 +399,7 @@ class NullableValue : public std::pmr::optional NullableValue(typename bsl::enable_if< !bslma::UsesBslmaAllocator::value, void>::type * = 0) - :std::pmr::optional() + :optional_base() { } // Create a nullable object having the null value. If 'TYPE' takes an @@ -571,7 +576,24 @@ class NullableValue : public std::pmr::optional // - //TYPE& value() + template + typename bsl::enable_if::value, + DUMMY>::type &value() { return optional_base::value().value;} + + template + typename bsl::enable_if::value), + DUMMY>::type & + value() { return optional_base::value();} + + + template + const typename bsl::enable_if::value, + DUMMY>::type& value() const { return optional_base::value().value;} + + template + const typename bsl::enable_if::value), + DUMMY>::type & + value() const { return optional_base::value();} // Return a reference providing modifiable access to the underlying // 'TYPE' object. The behavior is undefined unless this object is // non-null. @@ -888,7 +910,7 @@ NullableValue::NullableValue(typename bsl::enable_if< template inline NullableValue::NullableValue(bslma::Allocator *basicAllocator) -: std::pmr::optional(std::allocator_arg_t{}, +: optional_base(std::allocator_arg_t{}, std::pmr::polymorphic_allocator( (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) { @@ -898,7 +920,7 @@ template inline NullableValue::NullableValue(const NullableValue& original, bslma::Allocator *basicAllocator) -: std::pmr::optional(std::allocator_arg_t{}, +: optional_base(std::allocator_arg_t{}, (std::pmr::polymorphic_allocator)( (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) { @@ -912,7 +934,7 @@ inline NullableValue::NullableValue( bslmf::MovableRef original, bslma::Allocator *basicAllocator) -: std::pmr::optional(std::allocator_arg_t{}, +: optional_base(std::allocator_arg_t{}, std::pmr::polymorphic_allocator( (std::pmr::memory_resource*)(bslma::Default::allocator(basicAllocator)))) { @@ -931,7 +953,7 @@ NullableValue::NullableValue( !bsl::is_convertible::value, void>::type *) -: std::pmr::optional(BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) +: optional_base(BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) { } @@ -943,7 +965,7 @@ NullableValue::NullableValue( bslma::Allocator *basicAllocator, typename bsl::enable_if::value, void>::type *) -: std::pmr::optional(std::allocator_arg_t{}, +: optional_base(std::allocator_arg_t{}, std::pmr::polymorphic_allocator((std::pmr::memory_resource*) (bslma::Default::allocator(basicAllocator))), BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, value)) @@ -955,7 +977,7 @@ template inline NullableValue::NullableValue( const NullableValue& original) -: std::pmr::optional((std::pmr::optional)original) +: optional_base((std::pmr::optional)original) { } @@ -965,7 +987,7 @@ inline NullableValue::NullableValue( const NullableValue& original, bslma::Allocator *basicAllocator) -: std::pmr::optional(std::allocator_arg_t{}, +: optional_base(std::allocator_arg_t{}, std::pmr::polymorphic_allocator((std::pmr::memory_resource*) (bslma::Default::allocator(basicAllocator)))) { @@ -1037,7 +1059,7 @@ template inline NullableValue& NullableValue::operator=(const NullableValue& rhs) { - std::pmr::optional::operator=(rhs); + optional_base::operator=(rhs); return *this; } @@ -1046,8 +1068,8 @@ inline NullableValue& NullableValue::operator=(bslmf::MovableRef rhs) { - std::pmr::optional& rhs_base = rhs; - std::pmr::optional::operator=(MoveUtil::move(rhs_base)); + optional_base& rhs_base = rhs; + optional_base::operator=(MoveUtil::move(rhs_base)); return *this; } diff --git a/groups/bdl/bdlb/pmroptional b/groups/bdl/bdlb/pmroptional index 342abe9b52..de267a071b 100644 --- a/groups/bdl/bdlb/pmroptional +++ b/groups/bdl/bdlb/pmroptional @@ -55,26 +55,169 @@ namespace pmr { #define __cpp_lib_pmroptional 201810 - template - class __pmroptional; - - - template - using optional = conditional_t<__or_>, - __uses_domain_allocator<_Tp,polymorphic_allocator>>::value, - __pmroptional<_Tp> , std::optional<_Tp>>; + template > + struct __get_allocator_present + : false_type + { + }; + template + struct __get_allocator_present< _Tp, + __void_t().get_allocator())>> + : is_convertible().get_allocator()), + std::pmr::polymorphic_allocator> + { + }; // This class template manages construction/destruction of // the contained value for a std::pmr::optional. - template + template , + bool = __get_allocator_present<_Tp>::value> struct _Optional_payload { using _Stored_type = remove_const_t<_Tp>; + using __Allocator_type = std::pmr::polymorphic_allocator; _Optional_payload() noexcept {}; + _Optional_payload(allocator_arg_t, const __Allocator_type& __a) noexcept + : _M_pmr(__a.resource()){}; + + _Optional_payload(const _Optional_payload& __other) + : _M_pmr(__other._M_pmr) + { + if (__other._M_engaged) + { + ::new ((void*)std::__addressof(this->_M_payload._M_value)) + _Stored_type(__other._M_get()); + this->_M_engaged = true; + } + } + + + _Optional_payload(_Optional_payload&& __other) + noexcept(is_nothrow_move_constructible_v<_Stored_type>) + : _M_pmr(__other._M_pmr) + { + if (__other._M_engaged) + { + ::new ((void*)std::__addressof(this->_M_payload._M_value)) + _Stored_type(std::move(__other._M_get())); + this->_M_engaged = true; + } + } + + _Optional_payload& + operator=(const _Optional_payload& __other) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = __other._M_get(); + else + { + if (__other._M_engaged) + this->_M_construct(__other._M_get()); + else + this->_M_reset(); + } + return *this; + } + + + _Optional_payload& + operator=(_Optional_payload&& __other) + noexcept(__and_v, + is_nothrow_move_assignable<_Tp>>) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = std::move(__other._M_get()); + else + { + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_get())); + else + this->_M_reset(); + } + return *this; + } + + struct _Empty_byte { }; + + memory_resource* _M_get_allocator() const noexcept + { + return _M_pmr; + } + + template + union _Storage + { + _Storage() noexcept : _M_empty() { } + + // User-provided destructor is needed when _Up has non-trivial dtor. + ~_Storage() { } + _Empty_byte _M_empty; + _Up _M_value; + }; + + _Storage<_Stored_type> _M_payload; + + bool _M_engaged = false; + memory_resource* const _M_pmr = std::pmr::get_default_resource(); + + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + __uses_allocator_construct(polymorphic_allocator(_M_pmr), + std::__addressof(this->_M_payload._M_value), + std::forward<_Args>(__args)...); + this->_M_engaged = true; + } + + + + void + _M_destroy() noexcept + { + _M_engaged = false; + _M_payload._M_value.~_Stored_type(); + } + + // The _M_get() operations have _M_engaged as a precondition. + // They exist to access the contained value with the appropriate + // const-qualification, because _M_payload has had the const removed. + + _Tp& + _M_get() noexcept + { return this->_M_payload._M_value; } + + const _Tp& + _M_get() const noexcept + { return this->_M_payload._M_value; } + + // _M_reset is a 'safe' operation with no precondition. + void + _M_reset() noexcept + { + if (this->_M_engaged) + _M_destroy(); + } + + // Destructor needs to destroy the contained value: + ~_Optional_payload() { this->_M_reset(); } + }; + +template + struct _Optional_payload<_Tp, true, false> + { + using _Stored_type = remove_const_t<_Tp>; + using __Allocator_type = std::pmr::polymorphic_allocator; + + _Optional_payload() noexcept {}; + + _Optional_payload(allocator_arg_t, const __Allocator_type& __a) noexcept + : _M_pmr(__a.resource()){}; _Optional_payload(const _Optional_payload& __other) : _M_pmr(__other._M_pmr) @@ -85,6 +228,7 @@ namespace pmr { _Optional_payload(_Optional_payload&& __other) + noexcept(is_nothrow_move_constructible_v<_Stored_type>) : _M_pmr(__other._M_pmr) { if (__other._M_engaged) @@ -124,41 +268,27 @@ namespace pmr { return *this; } + memory_resource* _M_get_allocator() const noexcept + { + return _M_pmr; + } + + struct _Empty_byte { }; - template + template union _Storage { - constexpr _Storage() noexcept : _M_empty() { } - -/* template - constexpr - _Storage(_Args&&... __args) - : _Storage(std::in_place, std::forward<_Args>( __args)...) - { } - - template - constexpr - _Storage(in_place_t,_Args&&... __args) - : _M_value(std::forward<_Args>(__args)...) - { } - - template - constexpr - _Storage(std::initializer_list<_Vp> __il, _Args&&... __args) - : _M_value(__il, std::forward<_Args>(__args)...) - { } - */ - // User-provided destructor is needed when _Up has non-trivial dtor. - ~_Storage() { } + _Storage() noexcept : _M_empty() { } + _Empty_byte _M_empty; _Up _M_value; }; - + _Storage<_Stored_type> _M_payload; bool _M_engaged = false; - memory_resource* _M_pmr = std::pmr::get_default_resource(); + memory_resource* const _M_pmr = std::pmr::get_default_resource(); template void @@ -173,7 +303,7 @@ namespace pmr { - constexpr void + void _M_destroy() noexcept { _M_engaged = false; @@ -184,27 +314,323 @@ namespace pmr { // They exist to access the contained value with the appropriate // const-qualification, because _M_payload has had the const removed. - constexpr _Tp& + _Tp& _M_get() noexcept { return this->_M_payload._M_value; } - constexpr const _Tp& + const _Tp& _M_get() const noexcept { return this->_M_payload._M_value; } // _M_reset is a 'safe' operation with no precondition. - constexpr void + void _M_reset() noexcept { if (this->_M_engaged) _M_destroy(); } + }; + template + struct _Optional_payload<_Tp, false, true> + { + using _Stored_type = remove_const_t<_Tp>; + using __Allocator_type = std::pmr::polymorphic_allocator; + + _Optional_payload() noexcept {}; + + _Optional_payload(allocator_arg_t, const __Allocator_type& __a) noexcept + { + _M_payload._M_pmr = __a.resource(); + }; + + _Optional_payload(const _Optional_payload& __other) + { + if (__other._M_engaged) + { + ::new ((void*)std::__addressof(this->_M_payload._M_value)) + _Stored_type(__other._M_get()); + this->_M_engaged = true; + } + } + + + _Optional_payload(_Optional_payload&& __other) + noexcept(is_nothrow_move_constructible_v<_Stored_type>) + { + if (__other._M_engaged) + { + ::new ((void*)std::__addressof(this->_M_payload._M_value)) + _Stored_type(std::move(__other._M_get())); + this->_M_engaged = true; + } + } + + _Optional_payload& + operator=(const _Optional_payload& __other) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = __other._M_get(); + else + { + if (__other._M_engaged) + this->_M_construct(__other._M_get()); + else + this->_M_reset(); + } + return *this; + } + + + _Optional_payload& + operator=(_Optional_payload&& __other) + noexcept(__and_v, + is_nothrow_move_assignable<_Tp>>) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = std::move(__other._M_get()); + else + { + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_get())); + else + this->_M_reset(); + } + return *this; + } + + memory_resource* _M_get_allocator() const noexcept + { + memory_resource* __pmr; + if (_M_engaged) + { + __pmr = this->_M_payload._M_value.get_allocator().resource(); + } else { + __pmr = this->_M_payload._M_pmr; + } + return __pmr; + } + + struct _Empty_byte { }; + + template + union _Storage + { + _Storage() noexcept : _M_pmr(std::pmr::get_default_resource()) { } + + // User-provided destructor is needed when _Up has non-trivial dtor. + ~_Storage() { } + _Up _M_value; + memory_resource* _M_pmr; + }; + + _Storage<_Stored_type> _M_payload; + + bool _M_engaged = false; + + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + memory_resource* __pmr; + if (_M_engaged) + { + __pmr = this->_M_payload._M_value.get_allocator().resource(); + } else { + __pmr = this->_M_payload._M_pmr; + } + __uses_allocator_construct(polymorphic_allocator(__pmr), + std::__addressof(this->_M_payload._M_value), + std::forward<_Args>(__args)...); + this->_M_engaged = true; + } + + + + void + _M_destroy() noexcept + { + _M_engaged = false; + _M_payload._M_value.~_Stored_type(); + } + + // The _M_get() operations have _M_engaged as a precondition. + // They exist to access the contained value with the appropriate + // const-qualification, because _M_payload has had the const removed. + + _Tp& + _M_get() noexcept + { return this->_M_payload._M_value; } + + const _Tp& + _M_get() const noexcept + { return this->_M_payload._M_value; } + + // _M_reset is a 'safe' operation with no precondition. + void + _M_reset() noexcept + { + memory_resource* __pmr; + if (this->_M_engaged) + __pmr = this->_M_payload._M_value.get_allocator().resource(); + else + __pmr = __pmr = this->_M_payload._M_pmr; + _M_destroy(); + this->_M_payload._M_pmr = __pmr; + } + // Destructor needs to destroy the contained value: ~_Optional_payload() { this->_M_reset(); } }; + template + struct _Optional_payload<_Tp, true, true> + { + using _Stored_type = remove_const_t<_Tp>; + using __Allocator_type = std::pmr::polymorphic_allocator; + + _Optional_payload() noexcept {}; + + _Optional_payload(allocator_arg_t, const __Allocator_type& __a) noexcept + { + _M_payload._M_pmr = __a.resource(); + }; + + _Optional_payload(const _Optional_payload& __other) + { + if (__other._M_engaged) + { + ::new ((void*)std::__addressof(this->_M_payload._M_value)) + _Stored_type(__other._M_get()); + this->_M_engaged = true; + } + } + + _Optional_payload(_Optional_payload&& __other) + noexcept(is_nothrow_move_constructible_v<_Stored_type>) + { + if (__other._M_engaged) + { + ::new ((void*)std::__addressof(this->_M_payload._M_value)) + _Stored_type(std::move(__other._M_get())); + this->_M_engaged = true; + } + } + + _Optional_payload& + operator=(const _Optional_payload& __other) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = __other._M_get(); + else + { + if (__other._M_engaged) + this->_M_construct(__other._M_get()); + else + this->_M_reset(); + } + return *this; + } + + + _Optional_payload& + operator=(_Optional_payload&& __other) + noexcept(__and_v, + is_nothrow_move_assignable<_Tp>>) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = std::move(__other._M_get()); + else + { + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_get())); + else + this->_M_reset(); + } + return *this; + } + memory_resource* _M_get_allocator() const noexcept + { + if (_M_engaged) + { + return this->_M_payload._M_value.get_allocator().resource(); + } + return this->_M_payload._M_pmr; + } + + struct _Empty_byte { }; + + template + union _Storage + { + _Storage() noexcept : _M_pmr(std::pmr::get_default_resource()) { } + + _Up _M_value; + memory_resource* _M_pmr; + }; + + _Storage<_Stored_type> _M_payload; + + bool _M_engaged = false; + + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + memory_resource* __pmr; + if (_M_engaged) + { + __pmr = this->_M_payload._M_value.get_allocator().resource(); + } else { + __pmr = this->_M_payload._M_pmr; + } + __uses_allocator_construct(polymorphic_allocator(__pmr), + std::__addressof(this->_M_payload._M_value), + std::forward<_Args>(__args)...); + this->_M_engaged = true; + } + + + + void + _M_destroy() noexcept + { + _M_engaged = false; + _M_payload._M_value.~_Stored_type(); + } + + // The _M_get() operations have _M_engaged as a precondition. + // They exist to access the contained value with the appropriate + // const-qualification, because _M_payload has had the const removed. + + _Tp& + _M_get() noexcept + { return this->_M_payload._M_value; } + + const _Tp& + _M_get() const noexcept + { return this->_M_payload._M_value; } + + // _M_reset is a 'safe' operation with no precondition. + void + _M_reset() noexcept + { + memory_resource* __pmr; + if (this->_M_engaged) + __pmr = this->_M_payload._M_value.get_allocator().resource(); + else + __pmr = __pmr = this->_M_payload._M_pmr; + _M_destroy(); + this->_M_payload._M_pmr = __pmr; + } + + // Destructor needs to destroy the contained value: + ~_Optional_payload() { this->_M_reset(); } + }; + /** * @brief Class template that takes care of copy/move constructors of optional @@ -217,15 +643,28 @@ namespace pmr { class _Optional_base { using _Stored_type = remove_const_t<_Tp>; + using __Allocator_type = std::pmr::polymorphic_allocator; public: // Constructors for disengaged optionals. - constexpr _Optional_base() = default; + _Optional_base() = default; + + _Optional_base(allocator_arg_t, const __Allocator_type& __a) noexcept + : _M_payload(allocator_arg, __a){}; // Constructors for engaged optionals. template, bool> = false> - constexpr explicit _Optional_base(in_place_t, _Args&&... __args) + explicit _Optional_base(in_place_t, _Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + _M_construct(std::forward<_Args>(__args)...); + } + template, bool> = false> + explicit _Optional_base(allocator_arg_t, const __Allocator_type& __a, _Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + : _M_payload(allocator_arg, __a) { _M_construct(std::forward<_Args>(__args)...); } @@ -234,30 +673,21 @@ namespace pmr { enable_if_t&, _Args&&...>, bool> = false> - constexpr explicit _Optional_base(in_place_t, + explicit _Optional_base(in_place_t, initializer_list<_Up> __il, _Args&&... __args) { _M_construct(__il,std::forward<_Args>(__args)...); } - - // Constructors for engaged optionals. - template, _Args&&...>, bool> = false> - constexpr explicit _Optional_base(memory_resource* __pmr, _Args&&... __args) - { - _M_payload._M_pmr = __pmr; - _M_construct(std::forward<_Args>(__args)...); - } - + // Copy and move constructors. - constexpr _Optional_base(const _Optional_base& __other) + _Optional_base(const _Optional_base& __other) : _M_payload(__other._M_payload) { } - constexpr _Optional_base(_Optional_base&& __other) + _Optional_base(_Optional_base&& __other) noexcept(is_nothrow_move_constructible_v<_Tp>) : _M_payload(std::move(__other._M_payload)) { } @@ -283,37 +713,32 @@ namespace pmr { {_M_payload._M_destroy(); } // _M_reset is a 'safe' operation with no precondition. - constexpr void + void _M_reset() noexcept { _M_payload._M_reset(); } - constexpr bool _M_is_engaged() const noexcept + bool _M_is_engaged() const noexcept { return this->_M_payload._M_engaged; } // The _M_get operations have _M_engaged as a precondition. - constexpr _Tp& + _Tp& _M_get() noexcept { __glibcxx_assert(this->_M_is_engaged()); return this->_M_payload._M_get(); } - constexpr const _Tp& + const _Tp& _M_get() const noexcept { __glibcxx_assert(this->_M_is_engaged()); return this->_M_payload._M_get(); } - - void _M_set_allocator(memory_resource* __pmr) noexcept - { - _M_payload._M_pmr = __pmr; - } memory_resource* _M_get_allocator() const noexcept { - return _M_payload._M_pmr; + return _M_payload._M_get_allocator(); } private: @@ -323,14 +748,14 @@ namespace pmr { template using __converts_from_optional = - __or_&>, - is_constructible<_Tp, __pmroptional<_Up>&>, - is_constructible<_Tp, const __pmroptional<_Up>&&>, - is_constructible<_Tp, __pmroptional<_Up>&&>, - is_convertible&, _Tp>, - is_convertible<__pmroptional<_Up>&, _Tp>, - is_convertible&&, _Tp>, - is_convertible<__pmroptional<_Up>&&, _Tp>, + __or_&>, + is_constructible<_Tp, pmr::optional<_Up>&>, + is_constructible<_Tp, const pmr::optional<_Up>&&>, + is_constructible<_Tp, pmr::optional<_Up>&&>, + is_convertible&, _Tp>, + is_convertible&, _Tp>, + is_convertible&&, _Tp>, + is_convertible&&, _Tp>, is_constructible<_Tp, const std::optional<_Up>&>, is_constructible<_Tp, std::optional<_Up>&>, is_constructible<_Tp, const std::optional<_Up>&&>, @@ -342,10 +767,10 @@ namespace pmr { template using __assigns_from_optional = - __or_&>, - is_assignable<_Tp&, __pmroptional<_Up>&>, - is_assignable<_Tp&, const __pmroptional<_Up>&&>, - is_assignable<_Tp&, __pmroptional<_Up>&&>, + __or_&>, + is_assignable<_Tp&, pmr::optional<_Up>&>, + is_assignable<_Tp&, const pmr::optional<_Up>&&>, + is_assignable<_Tp&, pmr::optional<_Up>&&>, is_assignable<_Tp&, const std::optional<_Up>&>, is_assignable<_Tp&, std::optional<_Up>&>, is_assignable<_Tp&, const std::optional<_Up>&&>, @@ -373,6 +798,9 @@ namespace pmr { static_assert(!is_same_v, nullopt_t>); static_assert(!is_same_v, allocator_arg_t>); static_assert(!is_reference_v<_Tp>); + static_assert(uses_allocator<_Tp, pmr::polymorphic_allocator>::value, + "__pmroptional can not be instantiated with a class that does not use polymorphic allocator"); + template friend class __pmroptional; @@ -383,19 +811,21 @@ namespace pmr { template using __not_self = __not_>>; template - using __not_tag = __not_>>; + using __not_inplace_tag = __not_>>; + template + using __not_alloc_tag = __not_>>; template using _Requires = enable_if_t<__and_v<_Cond...>, bool>; public: using value_type = _Tp; - using __Allocator_type = std::pmr::polymorphic_allocator; + using allocator_type = std::pmr::polymorphic_allocator; - constexpr __pmroptional() noexcept { + __pmroptional() noexcept { } - constexpr __pmroptional(nullopt_t) noexcept { } + __pmroptional(nullopt_t) noexcept { } __pmroptional(const __pmroptional&) = default; __pmroptional(__pmroptional&&) = default; @@ -403,21 +833,19 @@ namespace pmr { // Converting constructors for engaged optionals. template, __not_tag<_Up>, - __not_>>>, + _Requires<__not_self<_Up>, __not_inplace_tag<_Up>, is_constructible<_Tp, _Up&&>, is_convertible<_Up&&, _Tp>> = true> - constexpr + __pmroptional(_Up&& __t) { emplace(std::forward<_Up>(__t)); }; template, __not_tag<_Up>, - __not_>>>, + _Requires<__not_self<_Up>, __not_inplace_tag<_Up>, is_constructible<_Tp, _Up&&>, __not_>> = false> - explicit constexpr + explicit __pmroptional(_Up&& __t) { emplace(std::forward<_Up>(__t)); }; @@ -427,10 +855,10 @@ namespace pmr { is_constructible<_Tp, const _Up&>, is_convertible, __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr + __pmroptional(const __pmroptional<_Up>& __t) + : _Base(std::allocator_arg, __t._M_get_allocator()) { - this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(*__t); } @@ -440,10 +868,10 @@ namespace pmr { is_constructible<_Tp, const _Up&>, __not_>, __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr + explicit __pmroptional(const __pmroptional<_Up>& __t) + : _Base(std::allocator_arg, __t._M_get_allocator()) { - this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(*__t); } @@ -453,10 +881,10 @@ namespace pmr { is_constructible<_Tp, _Up&&>, is_convertible<_Up&&, _Tp>, __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr + __pmroptional(__pmroptional<_Up>&& __t) + : _Base(std::allocator_arg, __t._M_get_allocator()) { - this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(std::move(*__t)); } @@ -466,10 +894,10 @@ namespace pmr { is_constructible<_Tp, _Up&&>, __not_>, __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr + explicit __pmroptional(__pmroptional<_Up>&& __t) + : _Base(std::allocator_arg, __t._M_get_allocator()) { - this->_M_set_allocator(__t._M_get_allocator()); if (__t) emplace(std::move(*__t)); } @@ -478,7 +906,7 @@ namespace pmr { _Requires< is_constructible<_Tp, const _Up&>, is_convertible, __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr + __pmroptional(const std::optional<_Up>& __t) { if (__t) @@ -489,7 +917,7 @@ namespace pmr { _Requires, __not_>, __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr + explicit __pmroptional(const std::optional<_Up>& __t) { if (__t) @@ -500,7 +928,7 @@ namespace pmr { _Requires< is_constructible<_Tp, _Up&&>, is_convertible<_Up&&, _Tp>, __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr + __pmroptional(std::optional<_Up>&& __t) { if (__t) @@ -511,7 +939,7 @@ namespace pmr { _Requires, __not_>, __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr + explicit __pmroptional(std::optional<_Up>&& __t) { if (__t) @@ -519,7 +947,7 @@ namespace pmr { } template> = false> - explicit constexpr + explicit __pmroptional(in_place_t, _Args&&... __args) : _Base(std::in_place, std::forward<_Args>(__args)...) { } @@ -527,48 +955,75 @@ namespace pmr { _Requires&, _Args&&...>> = false> - explicit constexpr + explicit __pmroptional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { } - // Converting memory-resource-constructors for engaged optionals. + // allocator extended constructors + + __pmroptional(allocator_arg_t, const allocator_type& __a) + noexcept + : _Base(std::allocator_arg, __a) + {} + + + __pmroptional(allocator_arg_t, const allocator_type& __a, nullopt_t) + noexcept + : _Base(std::allocator_arg, __a) + {} + + + - __pmroptional(allocator_arg_t, const __Allocator_type& __a) - { - this->_M_set_allocator(__a.resource()); - } template, is_constructible<_Tp, _Up&&>, is_convertible<_Up&&, _Tp>> = true> - constexpr - __pmroptional(allocator_arg_t, const __Allocator_type& __a,_Up&& __t) - { - this->_M_set_allocator(__a.resource()); - emplace(std::forward<_Up>(__t)); + + __pmroptional(allocator_arg_t, const allocator_type& __a,_Up&& __t) + : _Base(std::allocator_arg, __a) + { emplace(std::forward<_Up>(__t)); } template, is_constructible<_Tp, _Up&&>, __not_>> = false> - explicit constexpr - __pmroptional(allocator_arg_t, const __Allocator_type& __a, _Up&& __t) - { - this->_M_set_allocator(__a.resource()); - emplace(std::forward<_Up>(__t)); + explicit + __pmroptional(allocator_arg_t, const allocator_type& __a, _Up&& __t) + : _Base(std::allocator_arg, __a) + { + emplace(std::forward<_Up>(__t)); } + + + __pmroptional(allocator_arg_t, const allocator_type& __a, const __pmroptional& __t) + : _Base(std::allocator_arg,__a) + { + if (__t) + emplace(*__t); + } + + + __pmroptional(allocator_arg_t, const allocator_type& __a, __pmroptional&& __t) + : _Base(std::allocator_arg,__a) + { + if (__t) + emplace(std::move(*__t)); + } + + template>, is_constructible<_Tp, const _Up&>, is_convertible, __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional<_Up>& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) + + __pmroptional(allocator_arg_t, const allocator_type& __a, const __pmroptional<_Up>& __t) + : _Base(std::allocator_arg, __a) + { + if (__t) emplace(*__t); } @@ -577,11 +1032,11 @@ namespace pmr { is_constructible<_Tp, const _Up&>, __not_>, __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional<_Up>& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) + explicit + __pmroptional(allocator_arg_t, const allocator_type& __a, const __pmroptional<_Up>& __t) + : _Base(std::allocator_arg,__a) + { + if (__t) emplace(*__t); } @@ -590,11 +1045,11 @@ namespace pmr { is_constructible<_Tp, _Up&&>, is_convertible<_Up&&, _Tp>, __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional<_Up>&& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) + + __pmroptional(allocator_arg_t, const allocator_type& __a, __pmroptional<_Up>&& __t) + : _Base(std::allocator_arg,__a) + { + if (__t) emplace(std::move(*__t)); } @@ -603,78 +1058,83 @@ namespace pmr { is_constructible<_Tp, _Up&&>, __not_>, __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional<_Up>&& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) + explicit + __pmroptional(allocator_arg_t, const allocator_type& __a, __pmroptional<_Up>&& __t) + : _Base(std::allocator_arg,__a) + { + if (__t) emplace(std::move(*__t)); } - constexpr - __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(*__t); - } - - constexpr - __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional&& __t) - { - memory_resource* __actual_alloc = __a.resource(); - if (__t) - emplace(std::move(*__t)); - } - - template, - is_convertible, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional<_Up>& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(*__t); - } + template, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + + __pmroptional(allocator_arg_t, const allocator_type& __a,const std::optional<_Up>& __t) + : _Base(std::allocator_arg,__a) + { + if (__t) + emplace(*__t); + } - template, - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - __pmroptional(allocator_arg_t, const __Allocator_type& __a, const __pmroptional<_Up>& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(*__t); - } + template, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit + __pmroptional(allocator_arg_t, const allocator_type& __a, const std::optional<_Up>& __t) + : _Base(std::allocator_arg,__a) + { + if (__t) + emplace(*__t); + } - template , - is_convertible<_Up&&, _Tp>, - __not_<__converts_from_optional<_Tp, _Up>>> = true> - constexpr - __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional<_Up>&& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(std::move(*__t)); - } + template , + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + __pmroptional(allocator_arg_t, const allocator_type& __a, std::optional<_Up>&& __t) + : _Base(std::allocator_arg,__a) + { + if (__t) + emplace(std::move(*__t)); + } - template , - __not_>, - __not_<__converts_from_optional<_Tp, _Up>>> = false> - explicit constexpr - __pmroptional(allocator_arg_t, const __Allocator_type& __a, __pmroptional<_Up>&& __t) - { - this->_M_set_allocator(__a.resource()); - if (__t) - emplace(std::move(*__t)); - } + template , + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit + __pmroptional(allocator_arg_t, const allocator_type& __a, std::optional<_Up>&& __t) + : _Base(std::allocator_arg,__a) + { + if (__t) + emplace(std::move(*__t)); + } + template> = false> + explicit + __pmroptional(in_place_t, allocator_arg_t, const allocator_type& __a, _Args&&... __args) + : _Base(allocator_arg, __a) + { + + emplace( std::forward<_Args>(__args)...); + } + template&, + _Args&&...>> = false> + explicit + __pmroptional(in_place_t, allocator_arg_t, const allocator_type& __a, + initializer_list<_Up> __il, _Args&&... __args) + : _Base(allocator_arg, __a) + { + emplace(__il, std::forward<_Args>(__args)...); + } + + // Assignment operators. __pmroptional& operator=(nullopt_t) noexcept @@ -842,37 +1302,37 @@ namespace pmr { } // Observers. - constexpr const _Tp* + const _Tp* operator->() const { return std::__addressof(this->_M_get()); } - constexpr _Tp* + _Tp* operator->() { return std::__addressof(this->_M_get()); } - constexpr const _Tp& + const _Tp& operator*() const& { return this->_M_get(); } - constexpr _Tp& + _Tp& operator*()& { return this->_M_get(); } - constexpr _Tp&& + _Tp&& operator*()&& { return std::move(this->_M_get()); } - constexpr const _Tp&& + const _Tp&& operator*() const&& { return std::move(this->_M_get()); } - constexpr explicit operator bool() const noexcept + explicit operator bool() const noexcept { return this->_M_is_engaged(); } - constexpr bool has_value() const noexcept + bool has_value() const noexcept { return this->_M_is_engaged(); } - constexpr const _Tp& + const _Tp& value() const& { return this->_M_is_engaged() @@ -880,7 +1340,7 @@ namespace pmr { : (__throw_bad_optional_access(), this->_M_get()); } - constexpr _Tp& + _Tp& value()& { return this->_M_is_engaged() @@ -888,7 +1348,7 @@ namespace pmr { : (__throw_bad_optional_access(), this->_M_get()); } - constexpr _Tp&& + _Tp&& value()&& { return this->_M_is_engaged() @@ -896,7 +1356,7 @@ namespace pmr { : (__throw_bad_optional_access(), std::move(this->_M_get())); } - constexpr const _Tp&& + const _Tp&& value() const&& { return this->_M_is_engaged() @@ -905,7 +1365,7 @@ namespace pmr { } template - constexpr _Tp + _Tp value_or(_Up&& __u) const& { static_assert(is_copy_constructible_v<_Tp>); @@ -916,7 +1376,7 @@ namespace pmr { } template - constexpr _Tp + _Tp value_or(_Up&& __u) && { static_assert(is_move_constructible_v<_Tp>); @@ -927,6 +1387,12 @@ namespace pmr { : static_cast<_Tp>(std::forward<_Up>(__u)); } + pmr::polymorphic_allocator + get_allocator() const noexcept + { + return polymorphic_allocator(this->_M_get_allocator()); + } + void reset() noexcept { this->_M_reset(); } }; @@ -936,7 +1402,7 @@ namespace pmr { // Comparisons between optional values. template - constexpr auto + auto operator==(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() == declval<_Up>())> { @@ -945,7 +1411,7 @@ namespace pmr { } template - constexpr auto + auto operator!=(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() != declval<_Up>())> { @@ -954,7 +1420,7 @@ namespace pmr { } template - constexpr auto + auto operator<(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() < declval<_Up>())> { @@ -962,7 +1428,7 @@ namespace pmr { } template - constexpr auto + auto operator>(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() > declval<_Up>())> { @@ -970,7 +1436,7 @@ namespace pmr { } template - constexpr auto + auto operator<=(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() <= declval<_Up>())> { @@ -978,7 +1444,7 @@ namespace pmr { } template - constexpr auto + auto operator>=(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() >= declval<_Up>())> { @@ -987,7 +1453,7 @@ namespace pmr { template - constexpr auto + auto operator==(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) -> __optional_relop_t() == declval<_Up>())> { @@ -996,7 +1462,7 @@ namespace pmr { } template - constexpr auto + auto operator!=(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) -> __optional_relop_t() != declval<_Up>())> { @@ -1005,7 +1471,7 @@ namespace pmr { } template - constexpr auto + auto operator<(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) -> __optional_relop_t() < declval<_Up>())> { @@ -1013,7 +1479,7 @@ namespace pmr { } template - constexpr auto + auto operator>(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) -> __optional_relop_t() > declval<_Up>())> { @@ -1021,7 +1487,7 @@ namespace pmr { } template - constexpr auto + auto operator<=(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) -> __optional_relop_t() <= declval<_Up>())> { @@ -1029,7 +1495,7 @@ namespace pmr { } template - constexpr auto + auto operator>=(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) -> __optional_relop_t() >= declval<_Up>())> { @@ -1038,7 +1504,7 @@ namespace pmr { template - constexpr auto + auto operator==(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() == declval<_Up>())> { @@ -1047,7 +1513,7 @@ namespace pmr { } template - constexpr auto + auto operator!=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() != declval<_Up>())> { @@ -1056,7 +1522,7 @@ namespace pmr { } template - constexpr auto + auto operator<(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() < declval<_Up>())> { @@ -1064,7 +1530,7 @@ namespace pmr { } template - constexpr auto + auto operator>(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() > declval<_Up>())> { @@ -1072,7 +1538,7 @@ namespace pmr { } template - constexpr auto + auto operator<=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() <= declval<_Up>())> { @@ -1080,7 +1546,7 @@ namespace pmr { } template - constexpr auto + auto operator>=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() >= declval<_Up>())> { @@ -1088,134 +1554,134 @@ namespace pmr { } // Comparisons with nullopt. template - constexpr bool + bool operator==(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return !__lhs; } template - constexpr bool + bool operator==(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return !__rhs; } template - constexpr bool + bool operator!=(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return static_cast(__lhs); } template - constexpr bool + bool operator!=(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return static_cast(__rhs); } template - constexpr bool + bool operator<(const __pmroptional<_Tp>& /* __lhs */, nullopt_t) noexcept { return false; } template - constexpr bool + bool operator<(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return static_cast(__rhs); } template - constexpr bool + bool operator>(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return static_cast(__lhs); } template - constexpr bool + bool operator>(nullopt_t, const __pmroptional<_Tp>& /* __rhs */) noexcept { return false; } template - constexpr bool + bool operator<=(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return !__lhs; } template - constexpr bool + bool operator<=(nullopt_t, const __pmroptional<_Tp>& /* __rhs */) noexcept { return true; } template - constexpr bool + bool operator>=(const __pmroptional<_Tp>& /* __lhs */, nullopt_t) noexcept { return true; } template - constexpr bool + bool operator>=(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return !__rhs; } // Comparisons with value type. template - constexpr auto + auto operator==(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() == declval<_Up>())> { return __lhs && *__lhs == __rhs; } template - constexpr auto + auto operator==(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() == declval<_Tp>())> { return __rhs && __lhs == *__rhs; } template - constexpr auto + auto operator!=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() != declval<_Up>())> { return !__lhs || *__lhs != __rhs; } template - constexpr auto + auto operator!=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() != declval<_Tp>())> { return !__rhs || __lhs != *__rhs; } template - constexpr auto + auto operator<(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() < declval<_Up>())> { return !__lhs || *__lhs < __rhs; } template - constexpr auto + auto operator<(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() < declval<_Tp>())> { return __rhs && __lhs < *__rhs; } template - constexpr auto + auto operator>(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() > declval<_Up>())> { return __lhs && *__lhs > __rhs; } template - constexpr auto + auto operator>(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() > declval<_Tp>())> { return !__rhs || __lhs > *__rhs; } template - constexpr auto + auto operator<=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() <= declval<_Up>())> { return !__lhs || *__lhs <= __rhs; } template - constexpr auto + auto operator<=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() <= declval<_Tp>())> { return __rhs && __lhs <= *__rhs; } template - constexpr auto + auto operator>=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() >= declval<_Up>())> { return __lhs && *__lhs >= __rhs; } template - constexpr auto + auto operator>=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() >= declval<_Tp>())> { return !__rhs || __lhs >= *__rhs; } @@ -1239,20 +1705,41 @@ namespace pmr { swap(__pmroptional<_Tp>&, __pmroptional<_Tp>&) = delete; template - constexpr optional> + optional> + constexpr make_optional(_Tp&& __t) { return optional> { std::forward<_Tp>(__t) }; } template - constexpr optional<_Tp> + optional<_Tp> + constexpr make_optional(_Args&&... __args) { return optional<_Tp> { in_place, std::forward<_Args>(__args)... }; } template - constexpr optional<_Tp> + constexpr + optional<_Tp> make_optional(initializer_list<_Up> __il, _Args&&... __args) - { return optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; } + { return optional<_Tp> ( in_place, __il, std::forward<_Args>(__args)... ); } + + + template + enable_if_t>::value, + optional>> + alloc_optional(const polymorphic_allocator& __a,_Tp&& __t) + { return optional> (in_place, allocator_arg, __a, std::forward<_Tp>(__t) ); } + template + enable_if_t>::value, + optional<_Tp>> + alloc_optional(const polymorphic_allocator& __a,_Args&&... __args) + { return optional<_Tp> (in_place, allocator_arg, __a, std::forward<_Args>(__args)... );} + + template + enable_if_t>::value, + optional<_Tp>> + alloc_optional(const polymorphic_allocator& __a, initializer_list<_Up> __il, _Args&&... __args) + { return optional<_Tp> {in_place, allocator_arg, __a,__il, std::forward<_Args>(__args)... }; } } // namespace pmr // Hash. @@ -1268,7 +1755,7 @@ namespace pmr { { // We pick an arbitrary hash for disengaged optionals which hopefully // usual values of _Tp won't typically hash to. - constexpr size_t __magic_disengaged_hash = static_cast(-3333); + size_t __magic_disengaged_hash = static_cast(-3333); return __t ? hash<_Up>{}(*__t) : __magic_disengaged_hash; } }; @@ -1293,9 +1780,11 @@ namespace pmr { /// @} - - template - struct uses_allocator, _Alloc> : true_type {}; +/* todo:remove + template + struct uses_allocator, std::pmr::polymorphic_allocator> + : public uses_allocator<_Tp, std::pmr::polymorphic_allocator>::type { }; +*/ _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/groups/bdl/bdlb/uses_allocator.h b/groups/bdl/bdlb/uses_allocator.h index caa4a10b19..698f1d81a5 100644 --- a/groups/bdl/bdlb/uses_allocator.h +++ b/groups/bdl/bdlb/uses_allocator.h @@ -45,11 +45,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __domain_allocator_detector< _Tp, _Alloc, - __void_t> - : __is_invocable::type + __void_t> + : true_type { - using __rT = decltype(_Tp::domain_alloc_rebind); - inline static __rT* rebind = &_Tp::domain_alloc_rebind; + using __rT = decltype(_Tp::domain_alloc_convert); + inline static __rT* convert = &_Tp::domain_alloc_convert; }; template @@ -60,7 +60,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __uses_domain_allocator - : __domain_allocator_traits<_Tp,_Alloc>::type + : __domain_allocator_traits<_Tp,_Alloc> { }; // This is used for std::experimental::erased_type from Library Fundamentals. @@ -112,13 +112,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __uses_alloc2 : __uses_alloc_base { const _Alloc* _M_a; }; template - struct __uses_alloc3 : __uses_alloc_base { const _Alloc* _M_a; }; + struct __uses_domain_alloc1 : __uses_alloc_base { const _Alloc* _M_a; }; - template + template + struct __uses_domain_alloc2 : __uses_alloc_base { const _Alloc* _M_a; }; + + template struct __uses_alloc; template - struct __uses_alloc + struct __uses_alloc : conditional< is_constructible<_Tp, allocator_arg_t, const _Alloc&, _Args...>::value, __uses_alloc1<_Alloc>, @@ -134,23 +137,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; template - struct __uses_alloc - : __uses_alloc3<_Alloc> { }; + struct __uses_alloc + : __uses_alloc0 { }; - template - struct __uses_alloc - : __uses_alloc3<_Alloc> { }; + template + struct __uses_domain_alloc; template - struct __uses_alloc - : __uses_alloc0 { }; + struct __uses_domain_alloc + : conditional< + is_constructible<_Tp, allocator_arg_t, + decltype(__domain_allocator_traits<_Tp,_Alloc>::convert(declval<_Alloc>())), _Args...>::value, + __uses_domain_alloc1<_Alloc>, + __uses_domain_alloc2<_Alloc>>::type + { }; template + struct __uses_domain_alloc {}; + + template using __uses_alloc_t = - __uses_alloc<__and_, - __not_<__uses_domain_allocator<_Tp, _Alloc>>>::value, - __uses_domain_allocator<_Tp, _Alloc>::value, - _Tp, _Alloc, _Args...>; + typename conditional< + __uses_domain_allocator<_Tp, _Alloc>::value, + __uses_domain_alloc<__uses_domain_allocator<_Tp, _Alloc>::value, + _Tp, _Alloc,_Args...>, + __uses_alloc::value, + _Tp, _Alloc, _Args...>>::type; template inline __uses_alloc_t<_Tp, _Alloc, _Args...> @@ -222,11 +234,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Args&&... __args) { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)..., *__a._M_a); } + template - void __uses_allocator_construct_impl(__uses_alloc3<_Alloc> __a, _Tp* __ptr, - _Args&&... __args) + void __uses_allocator_construct_impl(__uses_domain_alloc1<_Alloc> __a, _Tp* __ptr, + _Args&&... __args) + { + ::new ((void*)__ptr) _Tp(allocator_arg, + __domain_allocator_traits<_Tp, _Alloc>::convert(*__a._M_a), + std::forward<_Args>(__args)...); + } + + template + void __uses_allocator_construct_impl(__uses_domain_alloc2<_Alloc> __a, _Tp* __ptr, + _Args&&... __args) { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)..., - __domain_allocator_traits<_Tp, _Alloc>::rebind(*__a._M_a)); } + __domain_allocator_traits<_Tp, _Alloc>::convert(*__a._M_a)); } + template void __uses_allocator_construct(const _Alloc& __a, _Tp* __ptr, From f424a4b1d39086443bd3095d2bd0f0dd888baf45 Mon Sep 17 00:00:00 2001 From: nina Queen of Awesome Date: Mon, 16 Sep 2019 16:54:32 +0100 Subject: [PATCH 13/14] adding pmroptional implementation that matches the paper --- groups/bdl/bdlb/optional | 1358 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1358 insertions(+) create mode 100644 groups/bdl/bdlb/optional diff --git a/groups/bdl/bdlb/optional b/groups/bdl/bdlb/optional new file mode 100644 index 0000000000..8419acccca --- /dev/null +++ b/groups/bdl/bdlb/optional @@ -0,0 +1,1358 @@ +// -*- C++ -*- + +// Copyright (C) 2013-2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/optional + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_OPTIONAL +#define _GLIBCXX_OPTIONAL 1 + +#pragma GCC system_header + +#if __cplusplus >= 201703L + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup utilities + * @{ + */ + +#define __cpp_lib_optional 201606L + + template + class optional; + +namespace pmr { + template + class __pmroptional; + + + template + using optional = conditional_t>::value, + __pmroptional<_Tp> , std::optional<_Tp>>; +} + + /// Tag type to disengage optional objects. + struct nullopt_t + { + // Do not user-declare default constructor at all for + // optional_value = {} syntax to work. + // nullopt_t() = delete; + + // Used for constructing nullopt. + enum class _Construct { _Token }; + + // Must be constexpr for nullopt_t to be literal. + explicit constexpr nullopt_t(_Construct) { } + }; + + /// Tag to disengage optional objects. + inline constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token }; + + /** + * @brief Exception class thrown when a disengaged optional object is + * dereferenced. + * @ingroup exceptions + */ + class bad_optional_access : public exception + { + public: + bad_optional_access() { } + + virtual const char* what() const noexcept override + { return "bad optional access"; } + + virtual ~bad_optional_access() noexcept = default; + }; + + void + __throw_bad_optional_access() + __attribute__((__noreturn__)); + + // XXX Does not belong here. + inline void + __throw_bad_optional_access() + { _GLIBCXX_THROW_OR_ABORT(bad_optional_access()); } + + // This class template manages construction/destruction of + // the contained value for a std::optional. + template + struct _Optional_payload_base + { + using _Stored_type = remove_const_t<_Tp>; + + _Optional_payload_base() = default; + ~_Optional_payload_base() = default; + + template + constexpr + _Optional_payload_base(in_place_t __tag, _Args&&... __args) + : _M_payload(__tag, std::forward<_Args>(__args)...), + _M_engaged(true) + { } + + template + constexpr + _Optional_payload_base(std::initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(__il, std::forward<_Args>(__args)...), + _M_engaged(true) + { } + + // Constructor used by _Optional_base copy constructor when the + // contained value is not trivially copy constructible. + constexpr + _Optional_payload_base(bool __engaged, + const _Optional_payload_base& __other) + { + if (__other._M_engaged) + this->_M_construct(__other._M_get()); + } + + // Constructor used by _Optional_base move constructor when the + // contained value is not trivially move constructible. + constexpr + _Optional_payload_base(bool __engaged, + _Optional_payload_base&& __other) + { + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_get())); + } + + // Copy constructor is only used to when the contained value is + // trivially copy constructible. + _Optional_payload_base(const _Optional_payload_base&) = default; + + // Move constructor is only used to when the contained value is + // trivially copy constructible. + _Optional_payload_base(_Optional_payload_base&&) = default; + + _Optional_payload_base& + operator=(const _Optional_payload_base&) = default; + + _Optional_payload_base& + operator=(_Optional_payload_base&&) = default; + + // used to perform non-trivial copy assignment. + constexpr void + _M_copy_assign(const _Optional_payload_base& __other) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = __other._M_get(); + else + { + if (__other._M_engaged) + this->_M_construct(__other._M_get()); + else + this->_M_reset(); + } + } + + // used to perform non-trivial move assignment. + constexpr void + _M_move_assign(_Optional_payload_base&& __other) + noexcept(__and_v, + is_nothrow_move_assignable<_Tp>>) + { + if (this->_M_engaged && __other._M_engaged) + this->_M_get() = std::move(__other._M_get()); + else + { + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_get())); + else + this->_M_reset(); + } + } + + struct _Empty_byte { }; + + template> + union _Storage + { + constexpr _Storage() noexcept : _M_empty() { } + + template + constexpr + _Storage(in_place_t, _Args&&... __args) + : _M_value(std::forward<_Args>(__args)...) + { } + + template + constexpr + _Storage(std::initializer_list<_Vp> __il, _Args&&... __args) + : _M_value(__il, std::forward<_Args>(__args)...) + { } + + _Empty_byte _M_empty; + _Up _M_value; + }; + + template + union _Storage<_Up, false> + { + constexpr _Storage() noexcept : _M_empty() { } + + template + constexpr + _Storage(in_place_t, _Args&&... __args) + : _M_value(std::forward<_Args>(__args)...) + { } + + template + constexpr + _Storage(std::initializer_list<_Vp> __il, _Args&&... __args) + : _M_value(__il, std::forward<_Args>(__args)...) + { } + + // User-provided destructor is needed when _Up has non-trivial dtor. + ~_Storage() { } + + _Empty_byte _M_empty; + _Up _M_value; + }; + + _Storage<_Stored_type> _M_payload; + + bool _M_engaged = false; + + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + ::new ((void *) std::__addressof(this->_M_payload)) + _Stored_type(std::forward<_Args>(__args)...); + this->_M_engaged = true; + } + + constexpr void + _M_destroy() noexcept + { + _M_engaged = false; + _M_payload._M_value.~_Stored_type(); + } + + // The _M_get() operations have _M_engaged as a precondition. + // They exist to access the contained value with the appropriate + // const-qualification, because _M_payload has had the const removed. + + constexpr _Tp& + _M_get() noexcept + { return this->_M_payload._M_value; } + + constexpr const _Tp& + _M_get() const noexcept + { return this->_M_payload._M_value; } + + // _M_reset is a 'safe' operation with no precondition. + constexpr void + _M_reset() noexcept + { + if (this->_M_engaged) + _M_destroy(); + } + }; + + // Class template that manages the payload for optionals. + template , + bool /*_HasTrivialCopy */ = + is_trivially_copy_assignable_v<_Tp> + && is_trivially_copy_constructible_v<_Tp>, + bool /*_HasTrivialMove */ = + is_trivially_move_assignable_v<_Tp> + && is_trivially_move_constructible_v<_Tp>> + struct _Optional_payload; + + // Payload for potentially-constexpr optionals (trivial copy/move/destroy). + template + struct _Optional_payload<_Tp, true, true, true> + : _Optional_payload_base<_Tp> + { + using _Optional_payload_base<_Tp>::_Optional_payload_base; + + _Optional_payload() = default; + }; + + // Payload for optionals with non-trivial copy construction/assignment. + template + struct _Optional_payload<_Tp, true, false, true> + : _Optional_payload_base<_Tp> + { + using _Optional_payload_base<_Tp>::_Optional_payload_base; + + _Optional_payload() = default; + ~_Optional_payload() = default; + _Optional_payload(const _Optional_payload&) = default; + _Optional_payload(_Optional_payload&&) = default; + _Optional_payload& operator=(_Optional_payload&&) = default; + + // Non-trivial copy assignment. + constexpr + _Optional_payload& + operator=(const _Optional_payload& __other) + { + this->_M_copy_assign(__other); + return *this; + } + }; + + // Payload for optionals with non-trivial move construction/assignment. + template + struct _Optional_payload<_Tp, true, true, false> + : _Optional_payload_base<_Tp> + { + using _Optional_payload_base<_Tp>::_Optional_payload_base; + + _Optional_payload() = default; + ~_Optional_payload() = default; + _Optional_payload(const _Optional_payload&) = default; + _Optional_payload(_Optional_payload&&) = default; + _Optional_payload& operator=(const _Optional_payload&) = default; + + // Non-trivial move assignment. + constexpr + _Optional_payload& + operator=(_Optional_payload&& __other) + noexcept(__and_v, + is_nothrow_move_assignable<_Tp>>) + { + this->_M_move_assign(std::move(__other)); + return *this; + } + }; + + // Payload for optionals with non-trivial copy and move assignment. + template + struct _Optional_payload<_Tp, true, false, false> + : _Optional_payload_base<_Tp> + { + using _Optional_payload_base<_Tp>::_Optional_payload_base; + + _Optional_payload() = default; + ~_Optional_payload() = default; + _Optional_payload(const _Optional_payload&) = default; + _Optional_payload(_Optional_payload&&) = default; + + // Non-trivial copy assignment. + constexpr + _Optional_payload& + operator=(const _Optional_payload& __other) + { + this->_M_copy_assign(__other); + return *this; + } + + // Non-trivial move assignment. + constexpr + _Optional_payload& + operator=(_Optional_payload&& __other) + noexcept(__and_v, + is_nothrow_move_assignable<_Tp>>) + { + this->_M_move_assign(std::move(__other)); + return *this; + } + }; + + // Payload for optionals with non-trivial destructors. + template + struct _Optional_payload<_Tp, false, _Copy, _Move> + : _Optional_payload<_Tp, true, false, false> + { + // Base class implements all the constructors and assignment operators: + using _Optional_payload<_Tp, true, false, false>::_Optional_payload; + _Optional_payload() = default; + _Optional_payload(const _Optional_payload&) = default; + _Optional_payload(_Optional_payload&&) = default; + _Optional_payload& operator=(const _Optional_payload&) = default; + _Optional_payload& operator=(_Optional_payload&&) = default; + + // Destructor needs to destroy the contained value: + ~_Optional_payload() { this->_M_reset(); } + }; + + // Common base class for _Optional_base to avoid repeating these + // member functions in each specialization. + template + class _Optional_base_impl + { + protected: + using _Stored_type = remove_const_t<_Tp>; + + // The _M_construct operation has !_M_engaged as a precondition + // while _M_destruct has _M_engaged as a precondition. + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) + { + ::new + (std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload)) + _Stored_type(std::forward<_Args>(__args)...); + static_cast<_Dp*>(this)->_M_payload._M_engaged = true; + } + + void + _M_destruct() noexcept + { static_cast<_Dp*>(this)->_M_payload._M_destroy(); } + + // _M_reset is a 'safe' operation with no precondition. + constexpr void + _M_reset() noexcept + { static_cast<_Dp*>(this)->_M_payload._M_reset(); } + + constexpr bool _M_is_engaged() const noexcept + { return static_cast(this)->_M_payload._M_engaged; } + + // The _M_get operations have _M_engaged as a precondition. + constexpr _Tp& + _M_get() noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return static_cast<_Dp*>(this)->_M_payload._M_get(); + } + + constexpr const _Tp& + _M_get() const noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return static_cast(this)->_M_payload._M_get(); + } + }; + + /** + * @brief Class template that provides copy/move constructors of optional. + * + * Such a separate base class template is necessary in order to + * conditionally make copy/move constructors trivial. + * + * When the contained value is trivally copy/move constructible, + * the copy/move constructors of _Optional_base will invoke the + * trivial copy/move constructor of _Optional_payload. Otherwise, + * they will invoke _Optional_payload(bool, const _Optional_payload&) + * or _Optional_payload(bool, _Optional_payload&&) to initialize + * the contained value, if copying/moving an engaged optional. + * + * Whether the other special members are trivial is determined by the + * _Optional_payload<_Tp> specialization used for the _M_payload member. + * + * @see optional, _Enable_special_members + */ + template, + bool = is_trivially_move_constructible_v<_Tp>> + struct _Optional_base + : _Optional_base_impl<_Tp, _Optional_base<_Tp>> + { + // Constructors for disengaged optionals. + constexpr _Optional_base() = default; + + // Constructors for engaged optionals. + template, bool> = false> + constexpr explicit _Optional_base(in_place_t, _Args&&... __args) + : _M_payload(in_place, + std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>, bool> = false> + constexpr explicit _Optional_base(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(in_place, + __il, std::forward<_Args>(__args)...) + { } + + // Copy and move constructors. + constexpr _Optional_base(const _Optional_base& __other) + : _M_payload(__other._M_payload._M_engaged, + __other._M_payload) + { } + + constexpr _Optional_base(_Optional_base&& __other) + noexcept(is_nothrow_move_constructible_v<_Tp>) + : _M_payload(__other._M_payload._M_engaged, + std::move(__other._M_payload)) + { } + + // Assignment operators. + _Optional_base& operator=(const _Optional_base&) = default; + _Optional_base& operator=(_Optional_base&&) = default; + + _Optional_payload<_Tp> _M_payload; + }; + + template + struct _Optional_base<_Tp, false, true> + : _Optional_base_impl<_Tp, _Optional_base<_Tp>> + { + // Constructors for disengaged optionals. + constexpr _Optional_base() = default; + + // Constructors for engaged optionals. + template, bool> = false> + constexpr explicit _Optional_base(in_place_t, _Args&&... __args) + : _M_payload(in_place, + std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>, bool> = false> + constexpr explicit _Optional_base(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(in_place, + __il, std::forward<_Args>(__args)...) + { } + + // Copy and move constructors. + constexpr _Optional_base(const _Optional_base& __other) + : _M_payload(__other._M_payload._M_engaged, + __other._M_payload) + { } + + constexpr _Optional_base(_Optional_base&& __other) = default; + + // Assignment operators. + _Optional_base& operator=(const _Optional_base&) = default; + _Optional_base& operator=(_Optional_base&&) = default; + + _Optional_payload<_Tp> _M_payload; + }; + + template + struct _Optional_base<_Tp, true, false> + : _Optional_base_impl<_Tp, _Optional_base<_Tp>> + { + // Constructors for disengaged optionals. + constexpr _Optional_base() = default; + + // Constructors for engaged optionals. + template, bool> = false> + constexpr explicit _Optional_base(in_place_t, _Args&&... __args) + : _M_payload(in_place, + std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>, bool> = false> + constexpr explicit _Optional_base(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(in_place, + __il, std::forward<_Args>(__args)...) + { } + + // Copy and move constructors. + constexpr _Optional_base(const _Optional_base& __other) = default; + + constexpr _Optional_base(_Optional_base&& __other) + noexcept(is_nothrow_move_constructible_v<_Tp>) + : _M_payload(__other._M_payload._M_engaged, + std::move(__other._M_payload)) + { } + + // Assignment operators. + _Optional_base& operator=(const _Optional_base&) = default; + _Optional_base& operator=(_Optional_base&&) = default; + + _Optional_payload<_Tp> _M_payload; + }; + + template + struct _Optional_base<_Tp, true, true> + : _Optional_base_impl<_Tp, _Optional_base<_Tp>> + { + // Constructors for disengaged optionals. + constexpr _Optional_base() = default; + + // Constructors for engaged optionals. + template, bool> = false> + constexpr explicit _Optional_base(in_place_t, _Args&&... __args) + : _M_payload(in_place, + std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>, bool> = false> + constexpr explicit _Optional_base(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(in_place, + __il, std::forward<_Args>(__args)...) + { } + + // Copy and move constructors. + constexpr _Optional_base(const _Optional_base& __other) = default; + constexpr _Optional_base(_Optional_base&& __other) = default; + + // Assignment operators. + _Optional_base& operator=(const _Optional_base&) = default; + _Optional_base& operator=(_Optional_base&&) = default; + + _Optional_payload<_Tp> _M_payload; + }; + + template + class optional; + + template + using __converts_from_optional = + __or_&>, + is_constructible<_Tp, pmr::optional<_Up>&>, + is_constructible<_Tp, const pmr::optional<_Up>&&>, + is_constructible<_Tp, pmr::optional<_Up>&&>, + is_convertible&, _Tp>, + is_convertible&, _Tp>, + is_convertible&&, _Tp>, + is_convertible&&, _Tp>, + is_constructible<_Tp, const std::optional<_Up>&>, + is_constructible<_Tp, std::optional<_Up>&>, + is_constructible<_Tp, const std::optional<_Up>&&>, + is_constructible<_Tp, std::optional<_Up>&&>, + is_convertible&, _Tp>, + is_convertible&, _Tp>, + is_convertible&&, _Tp>, + is_convertible&&, _Tp>>; + + template + using __assigns_from_optional = + __or_&>, + is_assignable<_Tp&, pmr::optional<_Up>&>, + is_assignable<_Tp&, const pmr::optional<_Up>&&>, + is_assignable<_Tp&, pmr::optional<_Up>&&>, + is_assignable<_Tp&, const std::optional<_Up>&>, + is_assignable<_Tp&, std::optional<_Up>&>, + is_assignable<_Tp&, const std::optional<_Up>&&>, + is_assignable<_Tp&, std::optional<_Up>&&>>; + + /** + * @brief Class template for optional values. + */ + template + class optional + : private _Optional_base<_Tp>, + private _Enable_copy_move< + // Copy constructor. + is_copy_constructible_v<_Tp>, + // Copy assignment. + __and_v, is_copy_assignable<_Tp>>, + // Move constructor. + is_move_constructible_v<_Tp>, + // Move assignment. + __and_v, is_move_assignable<_Tp>>, + // Unique tag type. + optional<_Tp>> + { + static_assert(!is_same_v, nullopt_t>); + static_assert(!is_same_v, in_place_t>); + static_assert(!is_reference_v<_Tp>); + + private: + using _Base = _Optional_base<_Tp>; + + // SFINAE helpers + template + using __not_self = __not_>>; + template + using __not_tag = __not_>>; + template + using _Requires = enable_if_t<__and_v<_Cond...>, bool>; + + public: + using value_type = _Tp; + + constexpr optional() = default; + + constexpr optional(nullopt_t) noexcept { } + + // Converting constructors for engaged optionals. + template, __not_tag<_Up>, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>> = true> + constexpr + optional(_Up&& __t) + : _Base(std::in_place, std::forward<_Up>(__t)) { } + + template, __not_tag<_Up>, + is_constructible<_Tp, _Up&&>, + __not_>> = false> + explicit constexpr + optional(_Up&& __t) + : _Base(std::in_place, std::forward<_Up>(__t)) { } + + template>, + is_constructible<_Tp, const _Up&>, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(const optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template>, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(const optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + + template>, + is_constructible<_Tp, const _Up&>, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(const pmr::__pmroptional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template>, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(const pmr::__pmroptional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + constexpr + optional(pmr::__pmroptional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit constexpr + optional(pmr::__pmroptional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + + + template> = false> + explicit constexpr + optional(in_place_t, _Args&&... __args) + : _Base(std::in_place, std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>> = false> + explicit constexpr + optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) + : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { } + + // Assignment operators. + optional& + operator=(nullopt_t) noexcept + { + this->_M_reset(); + return *this; + } + + template + enable_if_t<__and_v<__not_self<_Up>, + __not_<__and_, + is_same<_Tp, decay_t<_Up>>>>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>>, + optional&> + operator=(_Up&& __u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::forward<_Up>(__u); + else + this->_M_construct(std::forward<_Up>(__u)); + + return *this; + } + + template + enable_if_t<__and_v<__not_>, + is_constructible<_Tp, const _Up&>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + optional&> + operator=(const optional<_Up>& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = *__u; + else + this->_M_construct(*__u); + } + else + { + this->_M_reset(); + } + return *this; + } + + template + enable_if_t<__and_v<__not_>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + optional&> + operator=(optional<_Up>&& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::move(*__u); + else + this->_M_construct(std::move(*__u)); + } + else + { + this->_M_reset(); + } + + return *this; + } + + template + enable_if_t<__and_v<__not_>, + is_constructible<_Tp, const _Up&>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + optional&> + operator=(const pmr::__pmroptional<_Up>& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = *__u; + else + this->_M_construct(*__u); + } + else + { + this->_M_reset(); + } + return *this; + } + + template + enable_if_t<__and_v<__not_>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>>>, + optional&> + operator=(pmr::__pmroptional<_Up>&& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::move(*__u); + else + this->_M_construct(std::move(*__u)); + } + else + { + this->_M_reset(); + } + + return *this; + } + + template + enable_if_t, _Tp&> + emplace(_Args&&... __args) + { + this->_M_reset(); + this->_M_construct(std::forward<_Args>(__args)...); + return this->_M_get(); + } + + template + enable_if_t&, + _Args&&...>, _Tp&> + emplace(initializer_list<_Up> __il, _Args&&... __args) + { + this->_M_reset(); + this->_M_construct(__il, std::forward<_Args>(__args)...); + return this->_M_get(); + } + + // Destructor is implicit, implemented in _Optional_base. + + // Swap. + void + swap(optional& __other) + noexcept(is_nothrow_move_constructible_v<_Tp> + && is_nothrow_swappable_v<_Tp>) + { + using std::swap; + + if (this->_M_is_engaged() && __other._M_is_engaged()) + swap(this->_M_get(), __other._M_get()); + else if (this->_M_is_engaged()) + { + __other._M_construct(std::move(this->_M_get())); + this->_M_destruct(); + } + else if (__other._M_is_engaged()) + { + this->_M_construct(std::move(__other._M_get())); + __other._M_destruct(); + } + } + + // Observers. + constexpr const _Tp* + operator->() const + { return std::__addressof(this->_M_get()); } + + constexpr _Tp* + operator->() + { return std::__addressof(this->_M_get()); } + + constexpr const _Tp& + operator*() const& + { return this->_M_get(); } + + constexpr _Tp& + operator*()& + { return this->_M_get(); } + + constexpr _Tp&& + operator*()&& + { return std::move(this->_M_get()); } + + constexpr const _Tp&& + operator*() const&& + { return std::move(this->_M_get()); } + + constexpr explicit operator bool() const noexcept + { return this->_M_is_engaged(); } + + constexpr bool has_value() const noexcept + { return this->_M_is_engaged(); } + + constexpr const _Tp& + value() const& + { + return this->_M_is_engaged() + ? this->_M_get() + : (__throw_bad_optional_access(), this->_M_get()); + } + + constexpr _Tp& + value()& + { + return this->_M_is_engaged() + ? this->_M_get() + : (__throw_bad_optional_access(), this->_M_get()); + } + + constexpr _Tp&& + value()&& + { + return this->_M_is_engaged() + ? std::move(this->_M_get()) + : (__throw_bad_optional_access(), std::move(this->_M_get())); + } + + constexpr const _Tp&& + value() const&& + { + return this->_M_is_engaged() + ? std::move(this->_M_get()) + : (__throw_bad_optional_access(), std::move(this->_M_get())); + } + + template + constexpr _Tp + value_or(_Up&& __u) const& + { + static_assert(is_copy_constructible_v<_Tp>); + static_assert(is_convertible_v<_Up&&, _Tp>); + + return this->_M_is_engaged() + ? this->_M_get() : static_cast<_Tp>(std::forward<_Up>(__u)); + } + + template + constexpr _Tp + value_or(_Up&& __u) && + { + static_assert(is_move_constructible_v<_Tp>); + static_assert(is_convertible_v<_Up&&, _Tp>); + + return this->_M_is_engaged() + ? std::move(this->_M_get()) + : static_cast<_Tp>(std::forward<_Up>(__u)); + } + + void reset() noexcept { this->_M_reset(); } + }; + + template + using __optional_relop_t = + enable_if_t::value, bool>; + + // Comparisons between optional values. + template + constexpr auto + operator==(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() == declval<_Up>())> + { + return static_cast(__lhs) == static_cast(__rhs) + && (!__lhs || *__lhs == *__rhs); + } + + template + constexpr auto + operator!=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() != declval<_Up>())> + { + return static_cast(__lhs) != static_cast(__rhs) + || (static_cast(__lhs) && *__lhs != *__rhs); + } + + template + constexpr auto + operator<(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { + return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); + } + + template + constexpr auto + operator>(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { + return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); + } + + template + constexpr auto + operator<=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { + return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); + } + + template + constexpr auto + operator>=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { + return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs); + } + + // Comparisons with nullopt. + template + constexpr bool + operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept + { return !__lhs; } + + template + constexpr bool + operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept + { return !__rhs; } + + template + constexpr bool + operator!=(const optional<_Tp>& __lhs, nullopt_t) noexcept + { return static_cast(__lhs); } + + template + constexpr bool + operator!=(nullopt_t, const optional<_Tp>& __rhs) noexcept + { return static_cast(__rhs); } + + template + constexpr bool + operator<(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept + { return false; } + + template + constexpr bool + operator<(nullopt_t, const optional<_Tp>& __rhs) noexcept + { return static_cast(__rhs); } + + template + constexpr bool + operator>(const optional<_Tp>& __lhs, nullopt_t) noexcept + { return static_cast(__lhs); } + + template + constexpr bool + operator>(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept + { return false; } + + template + constexpr bool + operator<=(const optional<_Tp>& __lhs, nullopt_t) noexcept + { return !__lhs; } + + template + constexpr bool + operator<=(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept + { return true; } + + template + constexpr bool + operator>=(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept + { return true; } + + template + constexpr bool + operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept + { return !__rhs; } + + // Comparisons with value type. + template + constexpr auto + operator==(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() == declval<_Up>())> + { return __lhs && *__lhs == __rhs; } + + template + constexpr auto + operator==(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() == declval<_Tp>())> + { return __rhs && __lhs == *__rhs; } + + template + constexpr auto + operator!=(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() != declval<_Up>())> + { return !__lhs || *__lhs != __rhs; } + + template + constexpr auto + operator!=(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() != declval<_Tp>())> + { return !__rhs || __lhs != *__rhs; } + + template + constexpr auto + operator<(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { return !__lhs || *__lhs < __rhs; } + + template + constexpr auto + operator<(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() < declval<_Tp>())> + { return __rhs && __lhs < *__rhs; } + + template + constexpr auto + operator>(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { return __lhs && *__lhs > __rhs; } + + template + constexpr auto + operator>(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() > declval<_Tp>())> + { return !__rhs || __lhs > *__rhs; } + + template + constexpr auto + operator<=(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { return !__lhs || *__lhs <= __rhs; } + + template + constexpr auto + operator<=(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() <= declval<_Tp>())> + { return __rhs && __lhs <= *__rhs; } + + template + constexpr auto + operator>=(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { return __lhs && *__lhs >= __rhs; } + + template + constexpr auto + operator>=(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() >= declval<_Tp>())> + { return !__rhs || __lhs >= *__rhs; } + + // Swap and creation functions. + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2748. swappable traits for optionals + template + inline enable_if_t && is_swappable_v<_Tp>> + swap(optional<_Tp>& __lhs, optional<_Tp>& __rhs) + noexcept(noexcept(__lhs.swap(__rhs))) + { __lhs.swap(__rhs); } + + template + enable_if_t && is_swappable_v<_Tp>)> + swap(optional<_Tp>&, optional<_Tp>&) = delete; + + template + constexpr optional> + make_optional(_Tp&& __t) + { return optional> { std::forward<_Tp>(__t) }; } + + template + constexpr optional<_Tp> + make_optional(_Args&&... __args) + { return optional<_Tp> { in_place, std::forward<_Args>(__args)... }; } + + template + constexpr optional<_Tp> + make_optional(initializer_list<_Up> __il, _Args&&... __args) + { return optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; } + + // Hash. + + template, + bool = __poison_hash<_Up>::__enable_hash_call> + struct __optional_hash_call_base + { + size_t + operator()(const optional<_Tp>& __t) const + noexcept(noexcept(hash<_Up>{}(*__t))) + { + // We pick an arbitrary hash for disengaged optionals which hopefully + // usual values of _Tp won't typically hash to. + constexpr size_t __magic_disengaged_hash = static_cast(-3333); + return __t ? hash<_Up>{}(*__t) : __magic_disengaged_hash; + } + }; + + template + struct __optional_hash_call_base<_Tp, _Up, false> {}; + + template + struct hash> + : private __poison_hash>, + public __optional_hash_call_base<_Tp> + { + using result_type [[__deprecated__]] = size_t; + using argument_type [[__deprecated__]] = optional<_Tp>; + }; + + template + struct __is_fast_hash>> : __is_fast_hash> + { }; + + /// @} + +#if __cpp_deduction_guides >= 201606 + template optional(_Tp) -> optional<_Tp>; +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++17 + +#endif // _GLIBCXX_OPTIONAL From c76b70e3d37b689a2b80d864ee418743de19b49a Mon Sep 17 00:00:00 2001 From: nina Queen of Awesome Date: Thu, 3 Oct 2019 13:17:54 +0100 Subject: [PATCH 14/14] fixing merge problems --- groups/bdl/bdlb/pmroptional | 84 ++++++++++++++++---------------- groups/bdl/bdlb/uses_allocator.h | 1 - 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/groups/bdl/bdlb/pmroptional b/groups/bdl/bdlb/pmroptional index 99abb943fa..de267a071b 100644 --- a/groups/bdl/bdlb/pmroptional +++ b/groups/bdl/bdlb/pmroptional @@ -55,6 +55,7 @@ namespace pmr { #define __cpp_lib_pmroptional 201810 + template > struct __get_allocator_present : false_type @@ -92,7 +93,6 @@ namespace pmr { _Stored_type(__other._M_get()); this->_M_engaged = true; } - } @@ -274,8 +274,7 @@ template } - - _Storage<_Stored_type> _M_payload; + struct _Empty_byte { }; template union _Storage @@ -447,6 +446,7 @@ template this->_M_engaged = true; } + void _M_destroy() noexcept @@ -605,6 +605,7 @@ template // The _M_get() operations have _M_engaged as a precondition. // They exist to access the contained value with the appropriate // const-qualification, because _M_payload has had the const removed. + _Tp& _M_get() noexcept { return this->_M_payload._M_value; } @@ -823,10 +824,6 @@ template __pmroptional() noexcept { } - - // Destructor needs to destroy the contained value: - ~_Optional_payload() { this->_M_reset(); } - }; __pmroptional(nullopt_t) noexcept { } @@ -1117,7 +1114,6 @@ template } template> = false> - explicit __pmroptional(in_place_t, allocator_arg_t, const allocator_type& __a, _Args&&... __args) : _Base(allocator_arg, __a) @@ -1310,7 +1306,7 @@ template operator->() const { return std::__addressof(this->_M_get()); } - constexpr _Tp* + _Tp* operator->() { return std::__addressof(this->_M_get()); } @@ -1380,7 +1376,7 @@ template } template - constexpr _Tp + _Tp value_or(_Up&& __u) && { static_assert(is_move_constructible_v<_Tp>); @@ -1499,7 +1495,7 @@ template } template - auto + auto operator>=(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) -> __optional_relop_t() >= declval<_Up>())> { @@ -1508,7 +1504,7 @@ template template -auto + auto operator==(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() == declval<_Up>())> { @@ -1517,7 +1513,7 @@ auto } template -auto + auto operator!=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() != declval<_Up>())> { @@ -1526,7 +1522,7 @@ auto } template -auto + auto operator<(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() < declval<_Up>())> { @@ -1534,7 +1530,7 @@ auto } template -auto + auto operator>(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() > declval<_Up>())> { @@ -1542,7 +1538,7 @@ auto } template -auto + auto operator<=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() <= declval<_Up>())> { @@ -1550,7 +1546,7 @@ auto } template -auto + auto operator>=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) -> __optional_relop_t() >= declval<_Up>())> { @@ -1558,134 +1554,134 @@ auto } // Comparisons with nullopt. template -auto + bool operator==(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return !__lhs; } template -bool + bool operator==(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return !__rhs; } template -bool + bool operator!=(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return static_cast(__lhs); } template -bool + bool operator!=(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return static_cast(__rhs); } template -bool + bool operator<(const __pmroptional<_Tp>& /* __lhs */, nullopt_t) noexcept { return false; } template -bool + bool operator<(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return static_cast(__rhs); } template -bool + bool operator>(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return static_cast(__lhs); } template -bool + bool operator>(nullopt_t, const __pmroptional<_Tp>& /* __rhs */) noexcept { return false; } template -bool + bool operator<=(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept { return !__lhs; } template -bool + bool operator<=(nullopt_t, const __pmroptional<_Tp>& /* __rhs */) noexcept { return true; } template -bool + bool operator>=(const __pmroptional<_Tp>& /* __lhs */, nullopt_t) noexcept { return true; } template -bool + bool operator>=(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept { return !__rhs; } // Comparisons with value type. template -auto + auto operator==(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() == declval<_Up>())> { return __lhs && *__lhs == __rhs; } template -auto + auto operator==(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() == declval<_Tp>())> { return __rhs && __lhs == *__rhs; } template -auto + auto operator!=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() != declval<_Up>())> { return !__lhs || *__lhs != __rhs; } template -auto + auto operator!=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() != declval<_Tp>())> { return !__rhs || __lhs != *__rhs; } template -auto + auto operator<(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() < declval<_Up>())> { return !__lhs || *__lhs < __rhs; } template -auto + auto operator<(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() < declval<_Tp>())> { return __rhs && __lhs < *__rhs; } template -auto + auto operator>(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() > declval<_Up>())> { return __lhs && *__lhs > __rhs; } template - auto + auto operator>(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() > declval<_Tp>())> { return !__rhs || __lhs > *__rhs; } template -auto + auto operator<=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() <= declval<_Up>())> { return !__lhs || *__lhs <= __rhs; } template -auto + auto operator<=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() <= declval<_Tp>())> { return __rhs && __lhs <= *__rhs; } template -auto + auto operator>=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) -> __optional_relop_t() >= declval<_Up>())> { return __lhs && *__lhs >= __rhs; } template -auto + auto operator>=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) -> __optional_relop_t() >= declval<_Tp>())> { return !__rhs || __lhs >= *__rhs; } @@ -1726,6 +1722,7 @@ auto make_optional(initializer_list<_Up> __il, _Args&&... __args) { return optional<_Tp> ( in_place, __il, std::forward<_Args>(__args)... ); } + template enable_if_t>::value, optional>> @@ -1783,6 +1780,11 @@ auto /// @} +/* todo:remove + template + struct uses_allocator, std::pmr::polymorphic_allocator> + : public uses_allocator<_Tp, std::pmr::polymorphic_allocator>::type { }; +*/ _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/groups/bdl/bdlb/uses_allocator.h b/groups/bdl/bdlb/uses_allocator.h index b7be3c8cce..698f1d81a5 100644 --- a/groups/bdl/bdlb/uses_allocator.h +++ b/groups/bdl/bdlb/uses_allocator.h @@ -45,7 +45,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __domain_allocator_detector< _Tp, _Alloc, - __void_t> : true_type {