// scoped_allocator standard header // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #pragma once #ifndef _SCOPED_ALLOCATOR_ #define _SCOPED_ALLOCATOR_ #include #if _STL_COMPILER_PREPROCESSOR #include #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new _STD_BEGIN // FUNCTION TEMPLATE _Scoped_outermost template struct _Scoped_outermost_helper { // gets the outermost allocator static decltype(auto) _Fn(_Alloc& _Al) { // gets the outermost allocator return _Al; } }; template struct _Scoped_outermost_helper<_Alloc, void_t().outer_allocator())>> { // gets the outermost allocator using _Outer_alloc = decltype(_STD declval<_Alloc&>().outer_allocator()); static decltype(auto) _Fn(_Alloc& _Al) { // gets the outermost allocator return _Scoped_outermost_helper<_Outer_alloc>::_Fn(_Al.outer_allocator()); } }; template decltype(auto) _Scoped_outermost(_Alloc& _Al) { // gets the outermost allocator return _Scoped_outermost_helper<_Alloc>::_Fn(_Al); } // ALIAS TEMPLATE _Scoped_outermost_t template using _Scoped_outermost_t = remove_reference_t()))>; // ALIAS TEMPLATE _Scoped_outermost_traits template using _Scoped_outermost_traits = allocator_traits<_Scoped_outermost_t<_Alloc>>; // CLASS TEMPLATE _Scoped_base template class scoped_allocator_adaptor; template struct _Scoped_base; struct _Secret_scoped_allocator_construct_tag { explicit _Secret_scoped_allocator_construct_tag() = default; }; template struct _Scoped_base<_Outer, _Inner0, _Inner...> : _Outer { // nest of allocators, arbitrary depth using _Myadaptor = scoped_allocator_adaptor<_Outer, _Inner0, _Inner...>; using inner_allocator_type = scoped_allocator_adaptor<_Inner0, _Inner...>; inner_allocator_type _Inner_obj; inner_allocator_type& _Get_inner_object(_Myadaptor&) { return _Inner_obj; } const inner_allocator_type& _Get_inner_object(const _Myadaptor&) const { return _Inner_obj; } _Scoped_base() : _Outer(), _Inner_obj() { // value-initialize Outer and Inner } template >, int> = 0> _Scoped_base(_Other1&& _Outer_arg, _Other2&&... _Inner_args) : _Outer(_STD forward<_Other1>(_Outer_arg)), _Inner_obj(_STD forward<_Other2>(_Inner_args)...) { // also handles rebinding } _Scoped_base(const _Scoped_base&) = default; _Scoped_base(_Scoped_base&&) = default; _Scoped_base& operator=(const _Scoped_base&) = default; _Scoped_base& operator=(_Scoped_base&&) = default; _NODISCARD _Myadaptor select_on_container_copy_construction() const { // make new adaptor return _Myadaptor(_Secret_scoped_allocator_construct_tag{}, allocator_traits<_Outer>::select_on_container_copy_construction(static_cast(*this)), _Inner_obj.select_on_container_copy_construction()); } }; template struct _Scoped_base<_Outer> : _Outer { // nest of allocators, one deep using _Myadaptor = scoped_allocator_adaptor<_Outer>; using inner_allocator_type = scoped_allocator_adaptor<_Outer>; inner_allocator_type& _Get_inner_object(_Myadaptor& _Self) { return _Self; } const inner_allocator_type& _Get_inner_object(const _Myadaptor& _Self) const { return _Self; } _Scoped_base() : _Outer() { // value-initialize } template >, int> = 0> _Scoped_base(_Other1&& _Outer_arg) : _Outer(_STD forward<_Other1>(_Outer_arg)) { // also handles rebinding } _Scoped_base(const _Scoped_base&) = default; _Scoped_base(_Scoped_base&&) = default; _Scoped_base& operator=(const _Scoped_base&) = default; _Scoped_base& operator=(_Scoped_base&&) = default; _NODISCARD _Myadaptor select_on_container_copy_construction() const { // make new adaptor return _Myadaptor( allocator_traits<_Outer>::select_on_container_copy_construction(static_cast(*this))); } }; // CLASS TEMPLATE scoped_allocator_adaptor template class scoped_allocator_adaptor : public _Scoped_base<_Outer, _Inner...> { // nest of allocators using _Mybase = _Scoped_base<_Outer, _Inner...>; using _Outer_traits = allocator_traits<_Outer>; public: using outer_allocator_type = _Outer; using inner_allocator_type = typename _Mybase::inner_allocator_type; using value_type = typename _Outer_traits::value_type; using pointer = typename _Outer_traits::pointer; using const_pointer = typename _Outer_traits::const_pointer; using void_pointer = typename _Outer_traits::void_pointer; using const_void_pointer = typename _Outer_traits::const_void_pointer; using size_type = typename _Outer_traits::size_type; using difference_type = typename _Outer_traits::difference_type; template struct rebind { // converts X to X<_Other> using _Other_alloc = typename _Get_rebind_type<_Outer, _Other>::type; using other = scoped_allocator_adaptor<_Other_alloc, _Inner...>; }; using propagate_on_container_copy_assignment = bool_constant::propagate_on_container_copy_assignment, typename allocator_traits<_Inner>::propagate_on_container_copy_assignment...>>; using propagate_on_container_move_assignment = bool_constant::propagate_on_container_move_assignment, typename allocator_traits<_Inner>::propagate_on_container_move_assignment...>>; using propagate_on_container_swap = bool_constant::propagate_on_container_swap, typename allocator_traits<_Inner>::propagate_on_container_swap...>>; using is_always_equal = bool_constant::is_always_equal, typename allocator_traits<_Inner>::is_always_equal...>>; scoped_allocator_adaptor() = default; // value-init handled in _Scoped_base template , int> = 0> scoped_allocator_adaptor(_Other&& _Other_arg, const _Inner&... _Inner_args) noexcept : _Mybase(_STD forward<_Other>(_Other_arg), _Inner_args...) { // also handles rebinding construction when sizeof...(_Inner) == 0 } scoped_allocator_adaptor(const scoped_allocator_adaptor& _Right) noexcept : _Mybase(_Right) {} scoped_allocator_adaptor(scoped_allocator_adaptor&& _Right) noexcept : _Mybase(_STD move(_Right)) {} template , enable_if_t<_Enabled, int> = 0> scoped_allocator_adaptor(const scoped_allocator_adaptor<_Other, _Inner...>& _Right) noexcept : _Mybase(_Right.outer_allocator(), _Right.inner_allocator()) {} template , enable_if_t<_Enabled, int> = 0> scoped_allocator_adaptor(scoped_allocator_adaptor<_Other, _Inner...>&& _Right) noexcept : _Mybase(_STD move(_Right.outer_allocator()), _STD move(_Right.inner_allocator())) {} scoped_allocator_adaptor(_Secret_scoped_allocator_construct_tag, const outer_allocator_type& _Outer_arg, const inner_allocator_type& _Inner_arg) noexcept : _Mybase(_Outer_arg, _Inner_arg) {} scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&) = default; scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&&) = default; _NODISCARD inner_allocator_type& inner_allocator() noexcept { // get reference to inner allocator return this->_Get_inner_object(*this); } _NODISCARD const inner_allocator_type& inner_allocator() const noexcept { // get reference to inner allocator return this->_Get_inner_object(*this); } _NODISCARD outer_allocator_type& outer_allocator() noexcept { // get reference to outer allocator return static_cast<_Outer&>(*this); } _NODISCARD const outer_allocator_type& outer_allocator() const noexcept { // get reference to outer allocator return static_cast(*this); } _NODISCARD __declspec(allocator) pointer allocate(_CRT_GUARDOVERFLOW size_type _Count) { // allocate array of _Count elements, ignore hint return _Outer_traits::allocate(outer_allocator(), _Count); } _NODISCARD __declspec(allocator) pointer allocate( _CRT_GUARDOVERFLOW size_type _Count, const_void_pointer _Hint) { // allocate array of _Count elements, with hint return _Outer_traits::allocate(outer_allocator(), _Count, _Hint); } void deallocate(pointer _Ptr, size_type _Count) { // deallocate object at _Ptr, with size return _Outer_traits::deallocate(outer_allocator(), _Ptr, _Count); } _NODISCARD size_type max_size() const { // estimate maximum array size return _Outer_traits::max_size(outer_allocator()); } template void construct(_Ty* _Ptr, _Types&&... _Args) { // construct with varying allocator styles _Uses_allocator_construct(_Ptr, _Scoped_outermost(*this), inner_allocator(), _STD forward<_Types>(_Args)...); } template void destroy(_Ty* _Ptr) { // destroy object at _Ptr _Scoped_outermost_traits::destroy(_Scoped_outermost(*this), _Ptr); } // select_on_container_copy_construction comes from _Scoped_base }; #if _HAS_CXX17 template scoped_allocator_adaptor(_Outer, _Inner...) -> scoped_allocator_adaptor<_Outer, _Inner...>; #endif // _HAS_CXX17 template _NODISCARD bool operator==(const scoped_allocator_adaptor<_Outer1, _Inner1, _Inner...>& _Left, const scoped_allocator_adaptor<_Outer2, _Inner1, _Inner...>& _Right) noexcept { // compare scoped_allocator_adaptors for equality return _Left.outer_allocator() == _Right.outer_allocator() && _Left.inner_allocator() == _Right.inner_allocator(); } template _NODISCARD bool operator==(const scoped_allocator_adaptor<_Outer1>& _Left, const scoped_allocator_adaptor<_Outer2>& _Right) noexcept { // compare scoped_allocator_adaptors for equality return _Left.outer_allocator() == _Right.outer_allocator(); } template _NODISCARD bool operator!=(const scoped_allocator_adaptor<_Outer1, _Inner...>& _Left, const scoped_allocator_adaptor<_Outer2, _Inner...>& _Right) noexcept { // compare scoped_allocator_adaptors for equality return !(_Left == _Right); } _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) #endif // _STL_COMPILER_PREPROCESSOR #endif // _SCOPED_ALLOCATOR_