diff --git a/doc/allocator_traits.qbk b/doc/allocator_traits.qbk new file mode 100644 index 0000000..3b20d32 --- /dev/null +++ b/doc/allocator_traits.qbk @@ -0,0 +1,116 @@ +[/ +Copyright 2021 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +] + +[section:allocator_traits allocator_traits] + +[simplesect Authors] + +* Glen Fernandes + +[endsimplesect] + +[section Overview] + +This header provides an implementation of the +C++ standard library class template `allocator_traits` based on the facilities +in [link core.allocator_access Allocator Access]. Users should still prefer the +individual traits, but this utility exists to simplify migration. + +[endsect] + +[section Reference] + +``` +namespace boost { + +template +struct allocator_traits { + using allocator_type = A; + + using value_type = allocator_value_type_t; + + using pointer = allocator_pointer_t; + + using const_pointer = allocator_const_pointer_t; + + using void_pointer = allocator_void_pointer_t; + + using const_pointer = allocator_const_void_pointer_t; + + using difference_type = allocator_difference_type_t; + + using size_type = allocator_size_type_t; + + using propagate_on_container_copy_assignment = + allocator_propagate_on_container_copy_assignment_t; + + using propagate_on_container_move_assignment = + allocator_propagate_on_container_move_assignment_t; + + using propagate_on_container_swap = + allocator_propagate_on_container_swap_t; + + using is_always_equal = allocator_is_always_equal_t; + + template + using rebind_traits = allocator_traits >; + + static pointer allocate(A& a, size_type n); + + static pointer allocate(A& a, size_type n, const_void_pointer h); + + static void deallocate(A& a, pointer p, size_type n); + + template + static void construct(A& a, T* p, Args&&... args); + + static void destroy(A& a, T* p); + + static size_type max_size(const A& a) noexcept; + + static A select_on_container_copy_construction(const A& a); +}; + +} /* boost */ +``` + +[section Static member functions] + +[variablelist +[[`static pointer allocate(A& a, size_type n);`] +[Equivalent to: `return boost::allocator_allocate(a, n);`]] +[[`static pointer allocate(A& a, size_type n, const_void_pointer h);`] +[Equivalent to: `return boost::allocator_allocate(a, n, h);`]] +[[`static void deallocate(A& a, pointer p, size_type n);`] +[Equivalent to: `return boost::allocator_deallocate(a, n, h);`]] +[[`template +static void construct(A& a, T* p, Args&&... args);`] +[Equivalent to: +`return boost::allocator_construct(a, p, std::forward(args)...);`]] +[[`static void destroy(A& a, T* p);`] +[Equivalent to: `return boost::allocator_destroy(a, p);`]] +[[`static size_type max_size(const A& a);`] +[Equivalent to: `return boost::allocator_max_size(a);`]] +[[`static A select_on_container_copy_construction(const A& a);`] +[Equivalent to: +`return boost::allocator_select_on_container_copy_construction(a);`]]] + +[endsect] + +[section Notes] + +# The member `rebind_alloc` is not provided for parity with C++03 where it is +unimplementable. Instead of `allocator_traits::rebind_alloc` you can +express the same with `allocator_traits::rebind_traits::allocator_type` +or more simply with `allocator_rebind_t`. + +[endsect] + +[endsect] + +[endsect] diff --git a/doc/changes.qbk b/doc/changes.qbk index 5168026..e809ee9 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -6,6 +6,12 @@ [section Revision History] +[section Changes in 1.79.0] + +* Added `boost::allocator_traits`, an implementation of `std::allocator_traits`. + +[endsect] + [section Changes in 1.78.0] * Added a generic implementation to `boost/core/cmath.hpp`, enabled when `BOOST_CORE_USE_GENERIC_CMATH` diff --git a/doc/core.qbk b/doc/core.qbk index 7f7a75b..fbbecf6 100644 --- a/doc/core.qbk +++ b/doc/core.qbk @@ -42,6 +42,7 @@ criteria for inclusion is that the utility component be: [include addressof.qbk] [include allocator_access.qbk] +[include allocator_traits.qbk] [include alloc_construct.qbk] [include bit.qbk] [include checked_delete.qbk] diff --git a/include/boost/core/allocator_traits.hpp b/include/boost/core/allocator_traits.hpp new file mode 100644 index 0000000..bf8749d --- /dev/null +++ b/include/boost/core/allocator_traits.hpp @@ -0,0 +1,112 @@ +/* +Copyright 2021 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_CORE_ALLOCATOR_TRAITS_HPP +#define BOOST_CORE_ALLOCATOR_TRAITS_HPP + +#include + +namespace boost { + +template +struct allocator_traits { + typedef A allocator_type; + + typedef typename allocator_value_type::type value_type; + + typedef typename allocator_pointer::type pointer; + + typedef typename allocator_const_pointer::type const_pointer; + + typedef typename allocator_void_pointer::type void_pointer; + + typedef typename allocator_const_void_pointer::type const_void_pointer; + + typedef typename allocator_difference_type::type difference_type; + + typedef typename allocator_size_type::type size_type; + + typedef typename allocator_propagate_on_container_copy_assignment::type + propagate_on_container_copy_assignment; + + typedef typename allocator_propagate_on_container_move_assignment::type + propagate_on_container_move_assignment; + + typedef typename allocator_propagate_on_container_swap::type + propagate_on_container_swap; + + typedef typename allocator_is_always_equal::type is_always_equal; + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + template + using rebind_traits = allocator_traits::type>; +#else + template + struct rebind_traits + : allocator_traits::type> { }; +#endif + + static pointer allocate(A& a, size_type n) { + return boost::allocator_allocate(a, n); + } + + static pointer allocate(A& a, size_type n, const_void_pointer h) { + return boost::allocator_allocate(a, n, h); + } + + static void deallocate(A& a, pointer p, size_type n) { + return boost::allocator_deallocate(a, p, n); + } + + template + static void construct(A& a, T* p) { + boost::allocator_construct(a, p); + } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + static void construct(A& a, T* p, V&& v, Args&&... args) { + boost::allocator_construct(a, p, std::forward(v), + std::forward(args)...); + } +#else + template + static void construct(A& a, T* p, V&& v) { + boost::allocator_construct(a, p, std::forward(v)); + } +#endif +#else + template + static void construct(A& a, T* p, const V& v) { + boost::allocator_construct(a, p, v); + } + + template + static void construct(A& a, T* p, V& v) { + boost::allocator_construct(a, p, v); + } +#endif + + template + static void destroy(A& a, T* p) { + boost::allocator_destroy(a, p); + } + + static size_type max_size(const A& a) BOOST_NOEXCEPT { + return boost::allocator_max_size(a); + } + + static A select_on_container_copy_construction(const A& a) { + return boost::allocator_select_on_container_copy_construction(a); + } +}; + +} /* boost */ + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0b6e54b..0518bdc 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -236,6 +236,7 @@ run allocator_allocate_hint_test.cpp ; run allocator_deallocate_test.cpp ; run allocator_max_size_test.cpp ; run allocator_soccc_test.cpp ; +run allocator_traits_test.cpp ; lib lib_typeid : lib_typeid.cpp : shared:LIB_TYPEID_DYN_LINK=1 ; diff --git a/test/allocator_traits_test.cpp b/test/allocator_traits_test.cpp new file mode 100644 index 0000000..89a67e8 --- /dev/null +++ b/test/allocator_traits_test.cpp @@ -0,0 +1,114 @@ +/* +Copyright 2021 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#include + +template +class creator { +public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef void* void_pointer; + typedef const void* const_void_pointer; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + template + struct rebind { + typedef creator other; + }; + + explicit creator(int value) BOOST_NOEXCEPT + : state_(value) { } + + template + creator(const creator& other) BOOST_NOEXCEPT + : state_(other.state) { } + + std::size_t max_size() const BOOST_NOEXCEPT { + return static_cast(-1) / sizeof(T); + } + + T* allocate(std::size_t n, const void* = 0) { + return static_cast(::operator new(sizeof(T) * n)); + } + + void deallocate(T* p, std::size_t) { + ::operator delete(p); + } + + int state() const { + return state_; + } + +private: + int state_; +}; + +template +inline bool operator==(const creator& lhs, + const creator& rhs) BOOST_NOEXCEPT +{ + return lhs.state() == rhs.state(); +} + +template +inline bool operator!=(const creator& lhs, + const creator& rhs) BOOST_NOEXCEPT +{ + return !(lhs == rhs); +} + +int main() +{ + BOOST_TEST_TRAIT_SAME(creator, + boost::allocator_traits >::allocator_type); + BOOST_TEST_TRAIT_SAME(int, + boost::allocator_traits >::value_type); + BOOST_TEST_TRAIT_SAME(int*, + boost::allocator_traits >::pointer); + BOOST_TEST_TRAIT_SAME(const int*, + boost::allocator_traits >::const_pointer); + BOOST_TEST_TRAIT_SAME(void*, + boost::allocator_traits >::void_pointer); + BOOST_TEST_TRAIT_SAME(const void*, + boost::allocator_traits >::const_void_pointer); + BOOST_TEST_TRAIT_SAME(std::ptrdiff_t, + boost::allocator_traits >::difference_type); + BOOST_TEST_TRAIT_SAME(std::size_t, + boost::allocator_traits >::size_type); + BOOST_TEST_TRAIT_FALSE((boost::allocator_traits >:: + propagate_on_container_copy_assignment)); + BOOST_TEST_TRAIT_FALSE((boost::allocator_traits >:: + propagate_on_container_move_assignment)); + BOOST_TEST_TRAIT_FALSE((boost::allocator_traits >:: + propagate_on_container_swap)); + BOOST_TEST_TRAIT_FALSE((boost::allocator_traits >:: + is_always_equal)); + BOOST_TEST_TRAIT_SAME(creator, + boost::allocator_traits >:: + rebind_traits::allocator_type); + creator a(1); + int* p1 = boost::allocator_traits >::allocate(a, 1); + if (BOOST_TEST(p1)) { + int* p2 = boost::allocator_traits >::allocate(a, 1, p1); + if (BOOST_TEST(p2)) { + boost::allocator_traits >::deallocate(a, p2, 1); + } + boost::allocator_traits >::construct(a, p1, 5); + BOOST_TEST_EQ(*p1, 5); + boost::allocator_traits >::destroy(a, p1); + boost::allocator_traits >::deallocate(a, p1, 1); + } + BOOST_TEST_EQ(boost::allocator_traits >::max_size(a), + static_cast(-1) / sizeof(int)); + BOOST_TEST(boost::allocator_traits >:: + select_on_container_copy_construction(a) == a); + return boost::report_errors(); +}