From 50491408b1cc44e6e49041a8307ce4a1c32288eb Mon Sep 17 00:00:00 2001 From: Glen Fernandes Date: Sat, 27 Apr 2019 19:14:10 -0400 Subject: [PATCH] Implement noinit_allocator_adaptor --- doc/core.qbk | 1 + doc/noinit_adaptor.qbk | 141 ++++++++++++++++++++++++++ include/boost/core/noinit_adaptor.hpp | 96 ++++++++++++++++++ test/Jamfile.v2 | 1 + test/noinit_adaptor_test.cpp | 107 +++++++++++++++++++ 5 files changed, 346 insertions(+) create mode 100644 doc/noinit_adaptor.qbk create mode 100644 include/boost/core/noinit_adaptor.hpp create mode 100644 test/noinit_adaptor_test.cpp diff --git a/doc/core.qbk b/doc/core.qbk index 5edceba..aacff9e 100644 --- a/doc/core.qbk +++ b/doc/core.qbk @@ -50,6 +50,7 @@ criteria for inclusion is that the utility component be: [include is_same.qbk] [include lightweight_test.qbk] [include no_exceptions_support.qbk] +[include noinit_adaptor.qbk] [include noncopyable.qbk] [include null_deleter.qbk] [include pointer_traits.qbk] diff --git a/doc/noinit_adaptor.qbk b/doc/noinit_adaptor.qbk new file mode 100644 index 0000000..f622f58 --- /dev/null +++ b/doc/noinit_adaptor.qbk @@ -0,0 +1,141 @@ +[/ +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:noinit_adaptor noinit_adaptor] + +[simplesect Authors] + +* Glen Fernandes + +[endsimplesect] + +[section Overview] + +The header provides the class +template `boost::noinit_adaptor` that converts any allocator into +one whose `construct(ptr)` performs default initialization via placement new, +and whose `destroy(ptr)` invokes `value_type` destructor directly. + +[endsect] + +[section Example] + +The following example shows use of this allocator adaptor to achieve default +initialization of elements of a trivial type, which are later assigned values. + +``` +#include +#include + +int main() +{ + std::vector > > v(5); + std::iota(v.begin(), v.end(), 1); +} +``` + +[endsect] + +[section Reference] + +``` +namespace boost { + +template +struct noinit_adaptor + : A { + template + struct rebind { + typedef noinit_adaptor::template + rebind_alloc > other; + }; + + noinit_adaptor() noexcept; + + template + noinit_adaptor(U&& u) noexcept; + + template + noinit_adaptor(const noinit_adaptor& u) noexcept; + + template + void construct(U* p); + + template + void construct(U* p, V&& v, Args&&... args); + + template + void destroy(U* p); +}; + +template +bool operator==(const noinit_adaptor& lhs, + const noinit_adaptor& rhs) noexcept; + +template +bool operator!=(const noinit_adaptor& lhs, + const noinit_adaptor& rhs) noexcept; + +} /* boost */ +``` + +[section Constructors] + +[variablelist +[[`noinit_adaptor() noexcept;`] +[[variablelist +[[Effects][Value initializes the A base class.]]]]] +[[`template noinit_adaptor(U&& u) noexcept;`] +[[variablelist +[[Requires][`A` shall be constructible from `U`.]] +[[Effects][Initializes the `A` base class with `std::forward(u)`.]]]]] +[[`template noinit_adaptor(const noinit_adaptor& u) noexcept;`] +[[variablelist +[[Requires][`A` shall be constructible from `U`.]] +[[Effects][Initializes the `A` base class with +`static_cast(u)`.]]]]]] + +[endsect] + +[section Member functions] + +[variablelist +[[`template void construct(U* p);`] +[[variablelist +[[Effects][`::new((void*)p) U`.]]]]] +[[`template void construct(U* p, V&& v, +Args&&... args);`] +[[variablelist +[[Effects][`::new(void*)p) U(std::forward(v), +std::forward(args)...)`.]]]]] +[[`template void destroy(U* p);`] +[[variablelist +[[Effects][`p->~U()`.]]]]]] + +[endsect] + +[section Operators] + +[variablelist +[[`template constexpr bool +operator==(const noinit_adaptor& lhs, +const noinit_adaptor& rhs) noexcept;`] +[[variablelist +[[Returns][`static_cast(lhs) == static_cast(rhs)`.]]]]] +[[`template constexpr bool +operator!=(const noinit_adaptor& lhs, +const noinit_adaptor& rhs) noexcept;`] +[[variablelist +[[Returns][`!(lhs == rhs)`.]]]]]] + +[endsect] + +[endsect] + +[endsect] diff --git a/include/boost/core/noinit_adaptor.hpp b/include/boost/core/noinit_adaptor.hpp new file mode 100644 index 0000000..959da95 --- /dev/null +++ b/include/boost/core/noinit_adaptor.hpp @@ -0,0 +1,96 @@ +/* +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_NOINIT_ADAPTOR_HPP +#define BOOST_CORE_NOINIT_ADAPTOR_HPP + +#include +#include +#include +#include + +namespace boost { + +template +struct noinit_adaptor + : A { + template + struct rebind { +#if !defined(BOOST_NO_CXX11_ALLOCATOR) + typedef noinit_adaptor::template + rebind_alloc > other; +#else + typedef noinit_adaptor::other> other; +#endif + }; + + noinit_adaptor() + : A() { } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + noinit_adaptor(U&& u) BOOST_NOEXCEPT + : A(std::forward(u)) { } +#else + template + noinit_adaptor(const U& u) BOOST_NOEXCEPT + : A(u) { } +#endif + + template + noinit_adaptor(const noinit_adaptor& u) BOOST_NOEXCEPT + : A(static_cast(u)) { } + + template + void construct(U* p) { + ::new((void*)p) U; + } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + void construct(U* p, V&& v, Args&&... args) { + ::new((void*)p) U(std::forward(v), std::forward(args)...); + } +#else + template + void construct(U* p, V&& v) { + ::new((void*)p) U(std::forward(v)); + } +#endif +#else + template + void construct(U* p, const V& v) { + ::new((void*)p) U(v); + } +#endif + + template + void destroy(U* p) { + p->~U(); + } +}; + +template +inline bool +operator==(const noinit_adaptor& lhs, + const noinit_adaptor& rhs) BOOST_NOEXCEPT +{ + return static_cast(lhs) == static_cast(rhs); +} + +template +inline bool +operator!=(const noinit_adaptor& lhs, + const noinit_adaptor& rhs) BOOST_NOEXCEPT +{ + return !(lhs == rhs); +} + +} /* boost */ + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 49fe5a9..238c4b9 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -137,6 +137,7 @@ run-fail quick_exit_fail.cpp ; compile use_default_test.cpp ; run default_allocator_test.cpp ; +run noinit_adaptor_test.cpp ; lib lib_typeid : lib_typeid.cpp : shared:LIB_TYPEID_DYN_LINK=1 ; diff --git a/test/noinit_adaptor_test.cpp b/test/noinit_adaptor_test.cpp new file mode 100644 index 0000000..12fb941 --- /dev/null +++ b/test/noinit_adaptor_test.cpp @@ -0,0 +1,107 @@ +/* +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 +#include +#include + +template +class creator + : public boost::default_allocator { +public: + template + struct rebind { + typedef creator other; + }; + + creator(int* count) + : count_(count) { } + + template + creator(const creator& other) + : count_(other.count()) { } + + template + void construct(U*, const V&) { + ++(*count_); + } + + template + void destroy(U*) { + --(*count_); + } + + int* count() const { + return count_; + } + +private: + int* count_; +}; + +template +inline bool +operator==(const creator& lhs, const creator& rhs) +{ + return lhs.count() == rhs.count(); +} + +template +inline bool +operator!=(const creator& lhs, const creator& rhs) +{ + return !(lhs == rhs); +} + +class type { +public: + type() { } + + type(int value) + : value_(value) { } + + int value() const { + return value_; + } + +private: + int value_; +}; + +int main() +{ + { + int c = 0; + std::vector > > v(&c); + BOOST_TEST(c == 0); + v.push_back(1); + BOOST_TEST(v.front() == 1); + v.push_back(2); + BOOST_TEST(c == 0); + v.clear(); + BOOST_TEST(c == 0); + v.resize(5); + BOOST_TEST(c == 0); + v.front() = 1; + } + { + int c = 0; + std::vector > > v(&c); + BOOST_TEST(c == 0); + v.push_back(1); + BOOST_TEST(v.front().value() == 1); + v.push_back(2); + BOOST_TEST(c == 0); + v.clear(); + BOOST_TEST(c == 0); + v.resize(5); + BOOST_TEST(c == 0); + v.front() = 1; + } + return boost::report_errors(); +}