Merge pull request #56 from boostorg/feature/default_allocator

Implement default_allocator
This commit is contained in:
Glen Fernandes
2019-04-25 16:25:51 +10:00
committed by GitHub
5 changed files with 446 additions and 0 deletions

View File

@ -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]

113
doc/default_allocator.qbk Normal file
View File

@ -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 <boost/core/default_allocator.hpp> 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<class T>
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<class U>
struct rebind {
typedef default_allocator<U> other;
};
constexpr default_allocator() = default;
template<class U>
constexpr default_allocator(const default_allocator<U>&) noexcept { }
constexpr std::size_t max_size() const noexcept;
T* allocate(std::size_t n);
void deallocate(T* p, std::size_t);
};
template<class T, class U>
constexpr bool operator==(const default_allocator<T>&,
const default_allocator<U>&) noexcept;
template<class T, class U>
constexpr operator!=(const default_allocator<T>&,
const default_allocator<U>&) 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<class T, class U> constexpr bool operator==(const
default_allocator<T>&, const default_allocator<U>&) noexcept;`]
[[variablelist
[[Returns][`true`.]]]]]
[[`template<class T, class U> constexpr bool operator!=(const
default_allocator<T>&, const default_allocator<U>&) noexcept;`]
[[variablelist
[[Returns][`false`.]]]]]]
[endsect]
[endsect]
[endsect]

View File

@ -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 <boost/config.hpp>
#include <new>
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<class T>
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<class U>
struct rebind {
typedef default_allocator<U> other;
};
#if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS)
default_allocator() = default;
#else
BOOST_CONSTEXPR default_allocator() BOOST_NOEXCEPT { }
#endif
template<class U>
BOOST_CONSTEXPR default_allocator(const default_allocator<U>&)
BOOST_NOEXCEPT { }
BOOST_CONSTEXPR std::size_t max_size() const BOOST_NOEXCEPT {
return ~static_cast<std::size_t>(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<T*>(::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<T*>(p);
}
void deallocate(T* p, std::size_t) {
::operator delete(p, std::nothrow);
}
#endif
};
template<class T, class U>
BOOST_CONSTEXPR inline bool
operator==(const default_allocator<T>&,
const default_allocator<U>&) BOOST_NOEXCEPT
{
return true;
}
template<class T, class U>
BOOST_CONSTEXPR inline bool
operator!=(const default_allocator<T>&,
const default_allocator<U>&) BOOST_NOEXCEPT
{
return false;
}
} /* default_ */
using default_::default_allocator;
} /* boost */
#endif

View File

@ -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 : <link>shared:<define>LIB_TYPEID_DYN_LINK=1 ;
run test_lib_typeid.cpp lib_typeid : : : <link>shared : test_lib_typeid_shared ;

View File

@ -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 <boost/core/default_allocator.hpp>
#include <boost/core/lightweight_test_trait.hpp>
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<int>::value_type);
BOOST_TEST_TRAIT_SAME(type,
boost::default_allocator<type>::value_type);
BOOST_TEST_TRAIT_SAME(int[5],
boost::default_allocator<int[5]>::value_type);
BOOST_TEST_TRAIT_SAME(void,
boost::default_allocator<void>::value_type);
}
void test_pointer()
{
BOOST_TEST_TRAIT_SAME(int*,
boost::default_allocator<int>::pointer);
BOOST_TEST_TRAIT_SAME(type*,
boost::default_allocator<type>::pointer);
BOOST_TEST_TRAIT_SAME(int(*)[5],
boost::default_allocator<int[5]>::pointer);
BOOST_TEST_TRAIT_SAME(void*,
boost::default_allocator<void>::pointer);
}
void test_size_type()
{
BOOST_TEST_TRAIT_SAME(std::size_t,
boost::default_allocator<int>::size_type);
BOOST_TEST_TRAIT_SAME(std::size_t,
boost::default_allocator<type>::size_type);
BOOST_TEST_TRAIT_SAME(std::size_t,
boost::default_allocator<int[5]>::size_type);
BOOST_TEST_TRAIT_SAME(std::size_t,
boost::default_allocator<void>::size_type);
}
void test_difference_type()
{
BOOST_TEST_TRAIT_SAME(std::ptrdiff_t,
boost::default_allocator<int>::difference_type);
BOOST_TEST_TRAIT_SAME(std::ptrdiff_t,
boost::default_allocator<type>::difference_type);
BOOST_TEST_TRAIT_SAME(std::ptrdiff_t,
boost::default_allocator<int[5]>::difference_type);
BOOST_TEST_TRAIT_SAME(std::ptrdiff_t,
boost::default_allocator<void>::difference_type);
}
void test_propagate_on_container_move_assignment()
{
BOOST_TEST_TRAIT_TRUE((boost::default_allocator<int>::
propagate_on_container_move_assignment));
BOOST_TEST_TRAIT_TRUE((boost::default_allocator<type>::
propagate_on_container_move_assignment));
BOOST_TEST_TRAIT_TRUE((boost::default_allocator<int[5]>::
propagate_on_container_move_assignment));
BOOST_TEST_TRAIT_TRUE((boost::default_allocator<void>::
propagate_on_container_move_assignment));
}
void test_is_always_equal()
{
BOOST_TEST_TRAIT_TRUE((boost::default_allocator<int>::is_always_equal));
BOOST_TEST_TRAIT_TRUE((boost::default_allocator<type>::is_always_equal));
BOOST_TEST_TRAIT_TRUE((boost::default_allocator<int[5]>::is_always_equal));
BOOST_TEST_TRAIT_TRUE((boost::default_allocator<void>::is_always_equal));
}
void test_rebind()
{
BOOST_TEST_TRAIT_SAME(boost::default_allocator<type>,
boost::default_allocator<int>::rebind<type>::other);
BOOST_TEST_TRAIT_SAME(boost::default_allocator<int[5]>,
boost::default_allocator<type>::rebind<int[5]>::other);
BOOST_TEST_TRAIT_SAME(boost::default_allocator<void>,
boost::default_allocator<int[5]>::rebind<void>::other);
BOOST_TEST_TRAIT_SAME(boost::default_allocator<int>,
boost::default_allocator<void>::rebind<int>::other);
}
void test_default_construct()
{
boost::default_allocator<int> a1;
(void)a1;
boost::default_allocator<type> a2;
(void)a2;
boost::default_allocator<int[5]> a3;
(void)a3;
boost::default_allocator<void> a4;
(void)a4;
}
void test_copy()
{
boost::default_allocator<int> a1;
boost::default_allocator<int> a2(a1);
(void)a2;
boost::default_allocator<int[5]> a3;
boost::default_allocator<int[5]> a4(a3);
(void)a4;
boost::default_allocator<void> a5;
boost::default_allocator<void> a6(a5);
(void)a6;
}
void test_construct_other()
{
boost::default_allocator<int> a1;
boost::default_allocator<type> a2(a1);
boost::default_allocator<int[5]> a3(a2);
boost::default_allocator<void> a4(a3);
boost::default_allocator<int> a5(a4);
(void)a5;
}
template<class T>
std::size_t max_size()
{
return ~static_cast<std::size_t>(0) / sizeof(T);
}
void test_max_size()
{
BOOST_TEST_EQ(max_size<int>(),
boost::default_allocator<int>().max_size());
BOOST_TEST_EQ(max_size<type>(),
boost::default_allocator<type>().max_size());
BOOST_TEST_EQ(max_size<int[5]>(),
boost::default_allocator<int[5]>().max_size());
}
template<class T>
void test_allocate()
{
boost::default_allocator<T> 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<int>();
test_allocate<type>();
test_allocate<int[5]>();
}
void test_equals()
{
BOOST_TEST(boost::default_allocator<int>() ==
boost::default_allocator<type>());
BOOST_TEST(boost::default_allocator<type>() ==
boost::default_allocator<int[5]>());
BOOST_TEST(boost::default_allocator<int[5]>() ==
boost::default_allocator<void>());
BOOST_TEST(boost::default_allocator<void>() ==
boost::default_allocator<int>());
}
void test_not_equals()
{
BOOST_TEST(!(boost::default_allocator<int>() !=
boost::default_allocator<type>()));
BOOST_TEST(!(boost::default_allocator<type>() !=
boost::default_allocator<int[5]>()));
BOOST_TEST(!(boost::default_allocator<int[5]>() !=
boost::default_allocator<void>()));
BOOST_TEST(!(boost::default_allocator<void>() !=
boost::default_allocator<int>()));
}
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();
}