From 9c88e5cbb15611129df3d79d84519823ed8095a5 Mon Sep 17 00:00:00 2001 From: Glen Fernandes Date: Wed, 24 Apr 2019 22:21:13 -0400 Subject: [PATCH] Implement default_allocator --- doc/core.qbk | 1 + doc/default_allocator.qbk | 113 ++++++++++++ include/boost/core/default_allocator.hpp | 119 +++++++++++++ test/Jamfile.v2 | 2 + test/default_allocator_test.cpp | 211 +++++++++++++++++++++++ 5 files changed, 446 insertions(+) create mode 100644 doc/default_allocator.qbk create mode 100644 include/boost/core/default_allocator.hpp create mode 100644 test/default_allocator_test.cpp diff --git a/doc/core.qbk b/doc/core.qbk index 2a616b8..5edceba 100644 --- a/doc/core.qbk +++ b/doc/core.qbk @@ -40,6 +40,7 @@ criteria for inclusion is that the utility component be: [include addressof.qbk] [include checked_delete.qbk] +[include default_allocator.qbk] [include demangle.qbk] [include empty_value.qbk] [include enable_if.qbk] diff --git a/doc/default_allocator.qbk b/doc/default_allocator.qbk new file mode 100644 index 0000000..87de8c3 --- /dev/null +++ b/doc/default_allocator.qbk @@ -0,0 +1,113 @@ +[/ +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +] + +[section:default_allocator default_allocator] + +[simplesect Authors] + +* Glen Fernandes + +[endsimplesect] + +[section Overview] + +The header provides the class template +`boost::default_allocator` to serve as a minimal default allocator that: + +* Like C++2a's `std::allocator`, does not provide members such as `construct()` +and `destroy()` to be eligible for optimizations by allocator-aware code that +detects the absence of these members to provide more optimal construction of +objects. +* Supports `BOOST_NO_EXCEPTIONS`. +* Does not have `std` as an associated namespace. + +[endsect] + +[section Reference] + +``` +namespace boost { + +template +struct default_allocator { + typedef T value_type; + typedef T* pointer; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef ``['true_type]`` propagate_on_container_move_assignment; + typedef ``['true_type]`` is_always_equal; + + template + struct rebind { + typedef default_allocator other; + }; + + constexpr default_allocator() = default; + + template + constexpr default_allocator(const default_allocator&) noexcept { } + + constexpr std::size_t max_size() const noexcept; + T* allocate(std::size_t n); + void deallocate(T* p, std::size_t); +}; + +template +constexpr bool operator==(const default_allocator&, + const default_allocator&) noexcept; + +template +constexpr operator!=(const default_allocator&, + const default_allocator&) noexcept; + +} /* boost */ +``` + +[section Members] + +[variablelist + +[[`constexpr std::size_t max_size() const noexcept;`] +[[variablelist +[[Returns][The largest value `N` for which the call `allocate(N)` might +succeed.]]]]] +[[`T* allocate(std::size_t n);`] +[[variablelist +[[Returns] +[A pointer to the initial element of an array of storage of size +`n * sizeof(T)`, aligned appropriately for objects of type `T`.]] +[[Remarks][The storage is obtained by calling `::operator new`.]] +[[Throws][`std::bad_alloc` if the storage cannot be obtained.]]]]] +[[`void deallocate(T* p, std::size_t n);`] +[[variablelist +[[Requires] +[`p` shall be a pointer value obtained from `allocate()`. `n` shall equal the +value passed as the first argument to the invocation of `allocate` which +returned `p`.]] +[[Effects][Deallocates the storage referenced by `p`.]] +[[Remarks][Uses `::operator delete`.]]]]]] + +[endsect] + +[section Operators] + +[variablelist +[[`template constexpr bool operator==(const +default_allocator&, const default_allocator&) noexcept;`] +[[variablelist +[[Returns][`true`.]]]]] +[[`template constexpr bool operator!=(const +default_allocator&, const default_allocator&) noexcept;`] +[[variablelist +[[Returns][`false`.]]]]]] + +[endsect] + +[endsect] + +[endsect] diff --git a/include/boost/core/default_allocator.hpp b/include/boost/core/default_allocator.hpp new file mode 100644 index 0000000..d13b93a --- /dev/null +++ b/include/boost/core/default_allocator.hpp @@ -0,0 +1,119 @@ +/* +Copyright 2019 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_DEFAULT_ALLOCATOR_HPP +#define BOOST_CORE_DEFAULT_ALLOCATOR_HPP + +#include +#include + +namespace boost { + +#if defined(BOOST_NO_EXCEPTIONS) +void throw_exception(const std::exception&); +#endif + +namespace default_ { + +struct true_type { + typedef bool value_type; + typedef true_type type; + + BOOST_STATIC_CONSTANT(bool, value = true); + + BOOST_CONSTEXPR operator bool() const BOOST_NOEXCEPT { + return true; + } + + BOOST_CONSTEXPR bool operator()() const BOOST_NOEXCEPT { + return true; + } +}; + +template +struct default_allocator { + typedef T value_type; + typedef T* pointer; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef true_type propagate_on_container_move_assignment; + typedef true_type is_always_equal; + + template + struct rebind { + typedef default_allocator other; + }; + +#if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) + default_allocator() = default; +#else + BOOST_CONSTEXPR default_allocator() BOOST_NOEXCEPT { } +#endif + + template + BOOST_CONSTEXPR default_allocator(const default_allocator&) + BOOST_NOEXCEPT { } + + BOOST_CONSTEXPR std::size_t max_size() const BOOST_NOEXCEPT { + return ~static_cast(0) / sizeof(T); + } + +#if !defined(BOOST_NO_EXCEPTIONS) + T* allocate(std::size_t n) { + if (n > max_size()) { + throw std::bad_alloc(); + } + return static_cast(::operator new(sizeof(T) * n)); + } + + void deallocate(T* p, std::size_t) { + ::operator delete(p); + } +#else + T* allocate(std::size_t n) { + if (n > max_size()) { + boost::throw_exception(std::bad_alloc()); + } + if (!n) { + return 0; + } + void* p = ::operator new(sizeof(T) * n, std::nothrow); + if (!p) { + boost::throw_exception(std::bad_alloc()); + } + return static_cast(p); + } + + void deallocate(T* p, std::size_t) { + ::operator delete(p, std::nothrow); + } +#endif +}; + +template +BOOST_CONSTEXPR inline bool +operator==(const default_allocator&, + const default_allocator&) BOOST_NOEXCEPT +{ + return true; +} + +template +BOOST_CONSTEXPR inline bool +operator!=(const default_allocator&, + const default_allocator&) BOOST_NOEXCEPT +{ + return false; +} + +} /* default_ */ + +using default_::default_allocator; + +} /* boost */ + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a9a9e48..49fe5a9 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -136,6 +136,8 @@ run-fail quick_exit_fail.cpp ; compile use_default_test.cpp ; +run default_allocator_test.cpp ; + lib lib_typeid : lib_typeid.cpp : shared:LIB_TYPEID_DYN_LINK=1 ; run test_lib_typeid.cpp lib_typeid : : : shared : test_lib_typeid_shared ; diff --git a/test/default_allocator_test.cpp b/test/default_allocator_test.cpp new file mode 100644 index 0000000..855b5bb --- /dev/null +++ b/test/default_allocator_test.cpp @@ -0,0 +1,211 @@ +/* +Copyright 2019 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 + +class type { +public: + explicit type(int) { } + +private: + type(const type&); + type& operator=(const type&); +}; + +void test_value_type() +{ + BOOST_TEST_TRAIT_SAME(int, + boost::default_allocator::value_type); + BOOST_TEST_TRAIT_SAME(type, + boost::default_allocator::value_type); + BOOST_TEST_TRAIT_SAME(int[5], + boost::default_allocator::value_type); + BOOST_TEST_TRAIT_SAME(void, + boost::default_allocator::value_type); +} + +void test_pointer() +{ + BOOST_TEST_TRAIT_SAME(int*, + boost::default_allocator::pointer); + BOOST_TEST_TRAIT_SAME(type*, + boost::default_allocator::pointer); + BOOST_TEST_TRAIT_SAME(int(*)[5], + boost::default_allocator::pointer); + BOOST_TEST_TRAIT_SAME(void*, + boost::default_allocator::pointer); +} + +void test_size_type() +{ + BOOST_TEST_TRAIT_SAME(std::size_t, + boost::default_allocator::size_type); + BOOST_TEST_TRAIT_SAME(std::size_t, + boost::default_allocator::size_type); + BOOST_TEST_TRAIT_SAME(std::size_t, + boost::default_allocator::size_type); + BOOST_TEST_TRAIT_SAME(std::size_t, + boost::default_allocator::size_type); +} + +void test_difference_type() +{ + BOOST_TEST_TRAIT_SAME(std::ptrdiff_t, + boost::default_allocator::difference_type); + BOOST_TEST_TRAIT_SAME(std::ptrdiff_t, + boost::default_allocator::difference_type); + BOOST_TEST_TRAIT_SAME(std::ptrdiff_t, + boost::default_allocator::difference_type); + BOOST_TEST_TRAIT_SAME(std::ptrdiff_t, + boost::default_allocator::difference_type); +} + +void test_propagate_on_container_move_assignment() +{ + BOOST_TEST_TRAIT_TRUE((boost::default_allocator:: + propagate_on_container_move_assignment)); + BOOST_TEST_TRAIT_TRUE((boost::default_allocator:: + propagate_on_container_move_assignment)); + BOOST_TEST_TRAIT_TRUE((boost::default_allocator:: + propagate_on_container_move_assignment)); + BOOST_TEST_TRAIT_TRUE((boost::default_allocator:: + propagate_on_container_move_assignment)); +} + +void test_is_always_equal() +{ + BOOST_TEST_TRAIT_TRUE((boost::default_allocator::is_always_equal)); + BOOST_TEST_TRAIT_TRUE((boost::default_allocator::is_always_equal)); + BOOST_TEST_TRAIT_TRUE((boost::default_allocator::is_always_equal)); + BOOST_TEST_TRAIT_TRUE((boost::default_allocator::is_always_equal)); +} + +void test_rebind() +{ + BOOST_TEST_TRAIT_SAME(boost::default_allocator, + boost::default_allocator::rebind::other); + BOOST_TEST_TRAIT_SAME(boost::default_allocator, + boost::default_allocator::rebind::other); + BOOST_TEST_TRAIT_SAME(boost::default_allocator, + boost::default_allocator::rebind::other); + BOOST_TEST_TRAIT_SAME(boost::default_allocator, + boost::default_allocator::rebind::other); +} + +void test_default_construct() +{ + boost::default_allocator a1; + (void)a1; + boost::default_allocator a2; + (void)a2; + boost::default_allocator a3; + (void)a3; + boost::default_allocator a4; + (void)a4; +} + +void test_copy() +{ + boost::default_allocator a1; + boost::default_allocator a2(a1); + (void)a2; + boost::default_allocator a3; + boost::default_allocator a4(a3); + (void)a4; + boost::default_allocator a5; + boost::default_allocator a6(a5); + (void)a6; +} + +void test_construct_other() +{ + boost::default_allocator a1; + boost::default_allocator a2(a1); + boost::default_allocator a3(a2); + boost::default_allocator a4(a3); + boost::default_allocator a5(a4); + (void)a5; +} + +template +std::size_t max_size() +{ + return ~static_cast(0) / sizeof(T); +} + +void test_max_size() +{ + BOOST_TEST_EQ(max_size(), + boost::default_allocator().max_size()); + BOOST_TEST_EQ(max_size(), + boost::default_allocator().max_size()); + BOOST_TEST_EQ(max_size(), + boost::default_allocator().max_size()); +} + +template +void test_allocate() +{ + boost::default_allocator a; + T* p = a.allocate(1); + BOOST_TEST(p != 0); + a.deallocate(p, 1); + p = a.allocate(0); + a.deallocate(p, 0); + BOOST_TEST_THROWS(a.allocate(a.max_size()), std::bad_alloc); +} + +void test_allocate_deallocate() +{ + test_allocate(); + test_allocate(); + test_allocate(); +} + +void test_equals() +{ + BOOST_TEST(boost::default_allocator() == + boost::default_allocator()); + BOOST_TEST(boost::default_allocator() == + boost::default_allocator()); + BOOST_TEST(boost::default_allocator() == + boost::default_allocator()); + BOOST_TEST(boost::default_allocator() == + boost::default_allocator()); +} + +void test_not_equals() +{ + BOOST_TEST(!(boost::default_allocator() != + boost::default_allocator())); + BOOST_TEST(!(boost::default_allocator() != + boost::default_allocator())); + BOOST_TEST(!(boost::default_allocator() != + boost::default_allocator())); + BOOST_TEST(!(boost::default_allocator() != + boost::default_allocator())); +} + +int main() +{ + test_value_type(); + test_pointer(); + test_size_type(); + test_difference_type(); + test_propagate_on_container_move_assignment(); + test_is_always_equal(); + test_rebind(); + test_default_construct(); + test_copy(); + test_construct_other(); + test_max_size(); + test_allocate_deallocate(); + test_equals(); + test_not_equals(); + return boost::report_errors(); +}