diff --git a/groups/bdl/bdlb/bdlb_nullablevalue.h b/groups/bdl/bdlb/bdlb_nullablevalue.h index defd9be69a..6449142efc 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.h +++ b/groups/bdl/bdlb/bdlb_nullablevalue.h @@ -73,6 +73,8 @@ BSLS_IDENT("$Id: $") // nullableInt.reset(); // assert( nullableInt.isNull()); //.. +#include +#include #ifndef INCLUDED_BDLSCM_VERSION #include @@ -178,15 +180,1185 @@ 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 bdlb { + + + +// ========================= +// class NullableValue +// ========================= + + +template +using optional_base = std::conditional_t::value, + std::pmr::optional> , + std::pmr::optional >; + +template +class NullableValue : public optional_base +{ + + // 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) + :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. + + 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. + + // + + 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. + + +// 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) +: optional_base(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) +: optional_base(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) +: optional_base(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 *) + +: optional_base(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 *) + +: 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)) +{ +} + +template +template +inline +NullableValue::NullableValue( + const NullableValue& original) + +: optional_base((std::pmr::optional)original) +{ +} + +template +template +inline +NullableValue::NullableValue( + const NullableValue& original, + bslma::Allocator *basicAllocator) + +: optional_base(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) +{ + optional_base::operator=(rhs); + return *this; +} + +template +inline +NullableValue& +NullableValue::operator=(bslmf::MovableRef rhs) +{ + optional_base& rhs_base = rhs; + optional_base::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(); +} + +template +inline +const TYPE *NullableValue::valueOrNull() const +{ + return this->isNull() ? 0 : &this->value(); +} + +template +inline +TYPE NullableValue::valueOr(const TYPE& value) const +{ + return this->isNull() ? value : this->value(); +} + +template +inline +const TYPE *NullableValue::valueOr(const TYPE *value) const +{ + return this->isNull() ? value : &this->value(); +} + +template +inline +const TYPE *NullableValue::addressOr(const TYPE *value) const +{ + return this->isNull() ? value : &this->value(); +} + + +} // 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 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 + } + + 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); +} + +template +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 // ========================= @@ -552,6 +1724,7 @@ class NullableValue { // and 0 otherwise. }; + // FREE OPERATORS template bool operator==(const NullableValue& lhs, @@ -730,6 +1903,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 // ======================================= @@ -1414,6 +2588,7 @@ TYPE& NullableValue::value() return d_imp.value(); } + // ACCESSORS template template @@ -1509,6 +2684,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 @@ -1694,6 +2885,7 @@ void bdlb::swap(NullableValue& a, NullableValue& b) a.swap(b); } + namespace bdlb { // --------------------------------------- @@ -2397,8 +3589,10 @@ const TYPE& NullableValue_WithoutAllocator::value() const } // 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 cc55cd69d9..5d961242a7 100644 --- a/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp +++ b/groups/bdl/bdlb/bdlb_nullablevalue.t.cpp @@ -46,6 +46,22 @@ 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 {}; + template +struct uses_allocator : true_type {}; +*/} + // ============================================================================ // TEST PLAN // ---------------------------------------------------------------------------- @@ -1312,6 +1328,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 +1523,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 +1921,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 +3397,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 +7235,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..7f1f0ca5e9 --- /dev/null +++ b/groups/bdl/bdlb/memory_resource @@ -0,0 +1,697 @@ +// -*- 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); } + + + // 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(); } + + 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/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 diff --git a/groups/bdl/bdlb/pmroptional b/groups/bdl/bdlb/pmroptional new file mode 100644 index 0000000000..de267a071b --- /dev/null +++ b/groups/bdl/bdlb/pmroptional @@ -0,0 +1,1793 @@ +// <__pmroptional> -*- 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 > + 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 , + 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) + { + if (__other._M_engaged) + this->_M_construct(__other._M_get()); + } + + + _Optional_payload(_Optional_payload&& __other) + noexcept(is_nothrow_move_constructible_v<_Stored_type>) + : _M_pmr(__other._M_pmr) + { + if (__other._M_engaged) + 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(); + } + 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 + { + return _M_pmr; + } + + + struct _Empty_byte { }; + + template + union _Storage + { + _Storage() noexcept : _M_empty() { } + + _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(); + } + + }; + 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 + * + * 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>; + using __Allocator_type = std::pmr::polymorphic_allocator; + + public: + // Constructors for disengaged optionals. + _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> + 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)...); + } + + template&, + _Args&&...>, bool> = false> + explicit _Optional_base(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + { + _M_construct(__il,std::forward<_Args>(__args)...); + } + + + // Copy and move constructors. + _Optional_base(const _Optional_base& __other) + : _M_payload(__other._M_payload) + { } + + + _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. + void + _M_reset() noexcept + { _M_payload._M_reset(); } + + bool _M_is_engaged() const noexcept + { return this->_M_payload._M_engaged; } + + // The _M_get operations have _M_engaged as a precondition. + _Tp& + _M_get() noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return this->_M_payload._M_get(); + } + + const _Tp& + _M_get() const noexcept + { + __glibcxx_assert(this->_M_is_engaged()); + return this->_M_payload._M_get(); + } + + + memory_resource* _M_get_allocator() const noexcept + { + return _M_payload._M_get_allocator(); + } + + private: + _Optional_payload<_Tp> _M_payload; + }; + + + 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 __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>); + 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; + + private: + using _Base = _Optional_base<_Tp>; + + // SFINAE helpers + template + using __not_self = __not_>>; + template + 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; + + __pmroptional() noexcept { + } + + __pmroptional(nullopt_t) noexcept { } + + __pmroptional(const __pmroptional&) = default; + __pmroptional(__pmroptional&&) = default; + + + // Converting constructors for engaged optionals. + template, __not_inplace_tag<_Up>, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>> = true> + + __pmroptional(_Up&& __t) + { emplace(std::forward<_Up>(__t)); + }; + + template, __not_inplace_tag<_Up>, + is_constructible<_Tp, _Up&&>, + __not_>> = false> + explicit + __pmroptional(_Up&& __t) + { emplace(std::forward<_Up>(__t)); + }; + + template>, + is_constructible<_Tp, const _Up&>, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + + __pmroptional(const __pmroptional<_Up>& __t) + : _Base(std::allocator_arg, __t._M_get_allocator()) + { + if (__t) + emplace(*__t); + } + + template>, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit + __pmroptional(const __pmroptional<_Up>& __t) + : _Base(std::allocator_arg, __t._M_get_allocator()) + { + if (__t) + emplace(*__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + + __pmroptional(__pmroptional<_Up>&& __t) + : _Base(std::allocator_arg, __t._M_get_allocator()) + { + if (__t) + emplace(std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit + __pmroptional(__pmroptional<_Up>&& __t) + : _Base(std::allocator_arg, __t._M_get_allocator()) + { + if (__t) + emplace(std::move(*__t)); + } + + template, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + + __pmroptional(const std::optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit + __pmroptional(const std::optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template , + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + + __pmroptional(std::optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + template , + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit + __pmroptional(std::optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + template> = false> + explicit + __pmroptional(in_place_t, _Args&&... __args) + : _Base(std::in_place, std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>> = false> + explicit + __pmroptional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) + : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { } + + // 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) + {} + + + + + template, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>> = true> + + __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 + __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> + + __pmroptional(allocator_arg_t, const allocator_type& __a, const __pmroptional<_Up>& __t) + : _Base(std::allocator_arg, __a) + { + if (__t) + emplace(*__t); + } + + template>, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit + __pmroptional(allocator_arg_t, const allocator_type& __a, const __pmroptional<_Up>& __t) + : _Base(std::allocator_arg,__a) + { + if (__t) + emplace(*__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>>> = true> + + __pmroptional(allocator_arg_t, const allocator_type& __a, __pmroptional<_Up>&& __t) + : _Base(std::allocator_arg,__a) + { + if (__t) + emplace(std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>>> = false> + explicit + __pmroptional(allocator_arg_t, const allocator_type& __a, __pmroptional<_Up>&& __t) + : _Base(std::allocator_arg,__a) + { + if (__t) + emplace(std::move(*__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 + __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> + __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 + __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 + { + 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>>, + __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 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&> + 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(__pmroptional& __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. + const _Tp* + operator->() const + { return std::__addressof(this->_M_get()); } + + _Tp* + operator->() + { return std::__addressof(this->_M_get()); } + + const _Tp& + operator*() const& + { return this->_M_get(); } + + _Tp& + operator*()& + { return this->_M_get(); } + + _Tp&& + operator*()&& + { return std::move(this->_M_get()); } + + const _Tp&& + operator*() const&& + { return std::move(this->_M_get()); } + + explicit operator bool() const noexcept + { return this->_M_is_engaged(); } + + bool has_value() const noexcept + { return this->_M_is_engaged(); } + + const _Tp& + value() const& + { + return this->_M_is_engaged() + ? this->_M_get() + : (__throw_bad_optional_access(), this->_M_get()); + } + + _Tp& + value()& + { + return this->_M_is_engaged() + ? this->_M_get() + : (__throw_bad_optional_access(), this->_M_get()); + } + + _Tp&& + value()&& + { + return this->_M_is_engaged() + ? std::move(this->_M_get()) + : (__throw_bad_optional_access(), std::move(this->_M_get())); + } + + const _Tp&& + value() const&& + { + return this->_M_is_engaged() + ? std::move(this->_M_get()) + : (__throw_bad_optional_access(), std::move(this->_M_get())); + } + + template + _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)); + } + + pmr::polymorphic_allocator + get_allocator() const noexcept + { + return polymorphic_allocator(this->_M_get_allocator()); + } + + void reset() noexcept { this->_M_reset(); } +}; + + template + using __optional_relop_t = + enable_if_t::value, bool>; + + // Comparisons between optional values. + template + auto + operator==(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() == declval<_Up>())> + { + return static_cast(__lhs) == static_cast(__rhs) + && (!__lhs || *__lhs == *__rhs); + } + + template + auto + operator!=(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() != declval<_Up>())> + { + return static_cast(__lhs) != static_cast(__rhs) + || (static_cast(__lhs) && *__lhs != *__rhs); + } + + template + auto + operator<(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { + return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); + } + + template + auto + operator>(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { + return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); + } + + template + auto + operator<=(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { + return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); + } + + template + auto + operator>=(const __pmroptional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { + return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs); + } + + + template + 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 + 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 + auto + operator<(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { + return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); + } + + template + auto + operator>(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { + return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); + } + + template + auto + operator<=(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { + return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); + } + + template + auto + operator>=(const __pmroptional<_Tp>& __lhs, const std::optional<_Up>& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { + return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs); + } + + + template + 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 + 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 + auto + operator<(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { + return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); + } + + template + auto + operator>(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { + return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); + } + + template + auto + operator<=(const std::optional<_Tp>& __lhs, const __pmroptional<_Up>& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { + return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); + } + + template + 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 + bool + operator==(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept + { return !__lhs; } + + template + bool + operator==(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept + { return !__rhs; } + + template + bool + operator!=(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept + { return static_cast(__lhs); } + + template + bool + operator!=(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept + { return static_cast(__rhs); } + + template + bool + operator<(const __pmroptional<_Tp>& /* __lhs */, nullopt_t) noexcept + { return false; } + + template + bool + operator<(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept + { return static_cast(__rhs); } + + template + bool + operator>(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept + { return static_cast(__lhs); } + + template + bool + operator>(nullopt_t, const __pmroptional<_Tp>& /* __rhs */) noexcept + { return false; } + + template + bool + operator<=(const __pmroptional<_Tp>& __lhs, nullopt_t) noexcept + { return !__lhs; } + + template + bool + operator<=(nullopt_t, const __pmroptional<_Tp>& /* __rhs */) noexcept + { return true; } + + template + bool + operator>=(const __pmroptional<_Tp>& /* __lhs */, nullopt_t) noexcept + { return true; } + + template + bool + operator>=(nullopt_t, const __pmroptional<_Tp>& __rhs) noexcept + { return !__rhs; } + + // Comparisons with value type. + template + auto + operator==(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() == declval<_Up>())> + { return __lhs && *__lhs == __rhs; } + + template + auto + operator==(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) + -> __optional_relop_t() == declval<_Tp>())> + { return __rhs && __lhs == *__rhs; } + + template + auto + operator!=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() != declval<_Up>())> + { return !__lhs || *__lhs != __rhs; } + + template + auto + operator!=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) + -> __optional_relop_t() != declval<_Tp>())> + { return !__rhs || __lhs != *__rhs; } + + template + auto + operator<(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { return !__lhs || *__lhs < __rhs; } + + template + auto + operator<(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) + -> __optional_relop_t() < declval<_Tp>())> + { return __rhs && __lhs < *__rhs; } + + template + auto + operator>(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { return __lhs && *__lhs > __rhs; } + + template + auto + operator>(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) + -> __optional_relop_t() > declval<_Tp>())> + { return !__rhs || __lhs > *__rhs; } + + template + auto + operator<=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { return !__lhs || *__lhs <= __rhs; } + + template + auto + operator<=(const _Up& __lhs, const __pmroptional<_Tp>& __rhs) + -> __optional_relop_t() <= declval<_Tp>())> + { return __rhs && __lhs <= *__rhs; } + + template + auto + operator>=(const __pmroptional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { return __lhs && *__lhs >= __rhs; } + + template + auto + 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 + optional> + constexpr + make_optional(_Tp&& __t) + { return optional> { std::forward<_Tp>(__t) }; } + + template + optional<_Tp> + constexpr + 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)... ); } + + + 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. + + + template, + bool = __poison_hash<_Up>::__enable_hash_call> + struct __pmr_optional_hash_call_base + { + size_t + operator()(const pmr::__pmroptional<_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. + 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::__pmroptional<_Tp>; + }; + + template + struct __is_fast_hash>> : __is_fast_hash> + { }; + + + + /// @} + +/* 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 + +#endif // C++17 + +#endif // _GLIBCXX_OPTIONAL diff --git a/groups/bdl/bdlb/uses_allocator.h b/groups/bdl/bdlb/uses_allocator.h new file mode 100644 index 0000000000..698f1d81a5 --- /dev/null +++ b/groups/bdl/bdlb/uses_allocator.h @@ -0,0 +1,267 @@ +// 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> + : true_type + { + using __rT = decltype(_Tp::domain_alloc_convert); + inline static __rT* convert = &_Tp::domain_alloc_convert; + }; + + template + struct __domain_allocator_traits + : __domain_allocator_detector<_Tp, _Alloc> { + + }; + + template + struct __uses_domain_allocator + : __domain_allocator_traits<_Tp,_Alloc> + { }; + + // 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_domain_alloc1 : __uses_alloc_base { const _Alloc* _M_a; }; + + template + struct __uses_domain_alloc2 : __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_alloc0 { }; + + template + struct __uses_domain_alloc; + + template + 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 = + 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...> + __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_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>::convert(*__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 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/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); 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..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: //.. 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 // ============================================================================