| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704 |
- /*
- Copyright 2012-2017 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_SMART_PTR_ALLOCATE_SHARED_ARRAY_HPP
- #define BOOST_SMART_PTR_ALLOCATE_SHARED_ARRAY_HPP
- #include <boost/smart_ptr/shared_ptr.hpp>
- #include <boost/type_traits/alignment_of.hpp>
- #include <boost/type_traits/has_trivial_assign.hpp>
- #include <boost/type_traits/has_trivial_constructor.hpp>
- #include <boost/type_traits/has_trivial_destructor.hpp>
- #include <boost/type_traits/type_with_alignment.hpp>
- namespace boost {
- namespace detail {
- template<class>
- struct sp_if_array { };
- template<class T>
- struct sp_if_array<T[]> {
- typedef boost::shared_ptr<T[]> type;
- };
- template<class>
- struct sp_if_size_array { };
- template<class T, std::size_t N>
- struct sp_if_size_array<T[N]> {
- typedef boost::shared_ptr<T[N]> type;
- };
- template<class>
- struct sp_array_element { };
- template<class T>
- struct sp_array_element<T[]> {
- typedef T type;
- };
- template<class T, std::size_t N>
- struct sp_array_element<T[N]> {
- typedef T type;
- };
- template<class T>
- struct sp_array_scalar {
- typedef T type;
- };
- template<class T, std::size_t N>
- struct sp_array_scalar<T[N]> {
- typedef typename sp_array_scalar<T>::type type;
- };
- template<class T, std::size_t N>
- struct sp_array_scalar<const T[N]> {
- typedef typename sp_array_scalar<T>::type type;
- };
- template<class T, std::size_t N>
- struct sp_array_scalar<volatile T[N]> {
- typedef typename sp_array_scalar<T>::type type;
- };
- template<class T, std::size_t N>
- struct sp_array_scalar<const volatile T[N]> {
- typedef typename sp_array_scalar<T>::type type;
- };
- template<class T>
- struct sp_array_scalar<T[]> {
- typedef typename sp_array_scalar<T>::type type;
- };
- template<class T>
- struct sp_array_scalar<const T[]> {
- typedef typename sp_array_scalar<T>::type type;
- };
- template<class T>
- struct sp_array_scalar<volatile T[]> {
- typedef typename sp_array_scalar<T>::type type;
- };
- template<class T>
- struct sp_array_scalar<const volatile T[]> {
- typedef typename sp_array_scalar<T>::type type;
- };
- template<class T>
- struct sp_array_count {
- enum {
- value = 1
- };
- };
- template<class T, std::size_t N>
- struct sp_array_count<T[N]> {
- enum {
- value = N * sp_array_count<T>::value
- };
- };
- template<std::size_t N, std::size_t M>
- struct sp_max_size {
- enum {
- value = N < M ? M : N
- };
- };
- template<std::size_t N, std::size_t M>
- struct sp_align_up {
- enum {
- value = (N + M - 1) & ~(M - 1)
- };
- };
- #if !defined(BOOST_NO_CXX11_ALLOCATOR)
- template<class A, class T>
- struct sp_bind_allocator {
- typedef typename std::allocator_traits<A>::template rebind_alloc<T> type;
- };
- #else
- template<class A, class T>
- struct sp_bind_allocator {
- typedef typename A::template rebind<T>::other type;
- };
- #endif
- template<class T>
- BOOST_CONSTEXPR inline std::size_t
- sp_objects(std::size_t size) BOOST_SP_NOEXCEPT
- {
- return (size + sizeof(T) - 1) / sizeof(T);
- }
- template<bool, class = void>
- struct sp_enable { };
- template<class T>
- struct sp_enable<true, T> {
- typedef T type;
- };
- template<bool E, class A, class T>
- inline typename sp_enable<!E && boost::has_trivial_destructor<T>::value>::type
- sp_array_destroy(A&, T*, std::size_t) BOOST_SP_NOEXCEPT { }
- template<bool E, class A, class T>
- inline typename sp_enable<!E &&
- !boost::has_trivial_destructor<T>::value>::type
- sp_array_destroy(A&, T* start, std::size_t size)
- {
- while (size > 0) {
- start[--size].~T();
- }
- }
- #if !defined(BOOST_NO_CXX11_ALLOCATOR)
- template<bool E, class A, class T>
- inline typename sp_enable<E>::type
- sp_array_destroy(A& allocator, T* start, std::size_t size)
- {
- while (size > 0) {
- std::allocator_traits<A>::destroy(allocator, start + --size);
- }
- }
- #endif
- template<bool E, class A, class T>
- inline typename sp_enable<!E &&
- boost::has_trivial_constructor<T>::value &&
- boost::has_trivial_assign<T>::value &&
- boost::has_trivial_destructor<T>::value>::type
- sp_array_construct(A&, T* start, std::size_t size)
- {
- for (std::size_t i = 0; i < size; ++i) {
- start[i] = T();
- }
- }
- template<bool E, class A, class T>
- inline typename sp_enable<!E &&
- boost::has_trivial_constructor<T>::value &&
- boost::has_trivial_assign<T>::value &&
- boost::has_trivial_destructor<T>::value>::type
- sp_array_construct(A&, T* start, std::size_t size, const T* list,
- std::size_t count)
- {
- for (std::size_t i = 0; i < size; ++i) {
- start[i] = list[i % count];
- }
- }
- #if !defined(BOOST_NO_EXCEPTIONS)
- template<bool E, class A, class T>
- inline typename sp_enable<!E &&
- !(boost::has_trivial_constructor<T>::value &&
- boost::has_trivial_assign<T>::value &&
- boost::has_trivial_destructor<T>::value)>::type
- sp_array_construct(A& none, T* start, std::size_t size)
- {
- std::size_t i = 0;
- try {
- for (; i < size; ++i) {
- ::new(static_cast<void*>(start + i)) T();
- }
- } catch (...) {
- sp_array_destroy<E>(none, start, i);
- throw;
- }
- }
- template<bool E, class A, class T>
- inline typename sp_enable<!E &&
- !(boost::has_trivial_constructor<T>::value &&
- boost::has_trivial_assign<T>::value &&
- boost::has_trivial_destructor<T>::value)>::type
- sp_array_construct(A& none, T* start, std::size_t size, const T* list,
- std::size_t count)
- {
- std::size_t i = 0;
- try {
- for (; i < size; ++i) {
- ::new(static_cast<void*>(start + i)) T(list[i % count]);
- }
- } catch (...) {
- sp_array_destroy<E>(none, start, i);
- throw;
- }
- }
- #else
- template<bool E, class A, class T>
- inline typename sp_enable<!E &&
- !(boost::has_trivial_constructor<T>::value &&
- boost::has_trivial_assign<T>::value &&
- boost::has_trivial_destructor<T>::value)>::type
- sp_array_construct(A&, T* start, std::size_t size)
- {
- for (std::size_t i = 0; i < size; ++i) {
- ::new(static_cast<void*>(start + i)) T();
- }
- }
- template<bool E, class A, class T>
- inline typename sp_enable<!E &&
- !(boost::has_trivial_constructor<T>::value &&
- boost::has_trivial_assign<T>::value &&
- boost::has_trivial_destructor<T>::value)>::type
- sp_array_construct(A&, T* start, std::size_t size, const T* list,
- std::size_t count)
- {
- for (std::size_t i = 0; i < size; ++i) {
- ::new(static_cast<void*>(start + i)) T(list[i % count]);
- }
- }
- #endif
- #if !defined(BOOST_NO_CXX11_ALLOCATOR)
- #if !defined(BOOST_NO_EXCEPTIONS)
- template<bool E, class A, class T>
- inline typename sp_enable<E>::type
- sp_array_construct(A& allocator, T* start, std::size_t size)
- {
- std::size_t i = 0;
- try {
- for (i = 0; i < size; ++i) {
- std::allocator_traits<A>::construct(allocator, start + i);
- }
- } catch (...) {
- sp_array_destroy<E>(allocator, start, i);
- throw;
- }
- }
- template<bool E, class A, class T>
- inline typename sp_enable<E>::type
- sp_array_construct(A& allocator, T* start, std::size_t size, const T* list,
- std::size_t count)
- {
- std::size_t i = 0;
- try {
- for (i = 0; i < size; ++i) {
- std::allocator_traits<A>::construct(allocator, start + i,
- list[i % count]);
- }
- } catch (...) {
- sp_array_destroy<E>(allocator, start, i);
- throw;
- }
- }
- #else
- template<bool E, class A, class T>
- inline typename sp_enable<E>::type
- sp_array_construct(A& allocator, T* start, std::size_t size)
- {
- for (std::size_t i = 0; i < size; ++i) {
- std::allocator_traits<A>::construct(allocator, start + i);
- }
- }
- template<bool E, class A, class T>
- inline typename sp_enable<E>::type
- sp_array_construct(A& allocator, T* start, std::size_t size, const T* list,
- std::size_t count)
- {
- for (std::size_t i = 0; i < size; ++i) {
- std::allocator_traits<A>::construct(allocator, start + i,
- list[i % count]);
- }
- }
- #endif
- #endif
- template<class A, class T>
- inline typename sp_enable<boost::has_trivial_constructor<T>::value>::type
- sp_array_default(A&, T*, std::size_t) BOOST_SP_NOEXCEPT { }
- #if !defined(BOOST_NO_EXCEPTIONS)
- template<class A, class T>
- inline typename sp_enable<!boost::has_trivial_constructor<T>::value>::type
- sp_array_default(A& none, T* start, std::size_t size)
- {
- std::size_t i = 0;
- try {
- for (; i < size; ++i) {
- ::new(static_cast<void*>(start + i)) T;
- }
- } catch (...) {
- sp_array_destroy<false>(none, start, i);
- throw;
- }
- }
- #else
- template<bool E, class A, class T>
- inline typename sp_enable<!boost::has_trivial_constructor<T>::value>::type
- sp_array_default(A&, T* start, std::size_t size)
- {
- for (std::size_t i = 0; i < size; ++i) {
- ::new(static_cast<void*>(start + i)) T;
- }
- }
- #endif
- template<class A>
- class sp_array_state {
- public:
- typedef A type;
- template<class U>
- sp_array_state(const U& _allocator, std::size_t _size) BOOST_SP_NOEXCEPT
- : allocator_(_allocator),
- size_(_size) { }
- A& allocator() BOOST_SP_NOEXCEPT {
- return allocator_;
- }
- std::size_t size() const BOOST_SP_NOEXCEPT {
- return size_;
- }
- private:
- A allocator_;
- std::size_t size_;
- };
- template<class A, std::size_t N>
- class sp_size_array_state {
- public:
- typedef A type;
- template<class U>
- sp_size_array_state(const U& _allocator, std::size_t) BOOST_SP_NOEXCEPT
- : allocator_(_allocator) { }
- A& allocator() BOOST_SP_NOEXCEPT {
- return allocator_;
- }
- BOOST_CONSTEXPR std::size_t size() const BOOST_SP_NOEXCEPT {
- return N;
- }
- private:
- A allocator_;
- };
- #if !defined(BOOST_NO_CXX11_ALLOCATOR)
- template<class A>
- struct sp_use_construct {
- enum {
- value = true
- };
- };
- template<class T>
- struct sp_use_construct<std::allocator<T> > {
- enum {
- value = false
- };
- };
- #else
- template<class>
- struct sp_use_construct {
- enum {
- value = false
- };
- };
- #endif
- template<class T, class U>
- struct sp_array_alignment {
- enum {
- value = sp_max_size<boost::alignment_of<T>::value,
- boost::alignment_of<U>::value>::value
- };
- };
- template<class T, class U>
- struct sp_array_offset {
- enum {
- value = sp_align_up<sizeof(T), sp_array_alignment<T, U>::value>::value
- };
- };
- template<class T, class U>
- struct sp_array_storage {
- enum {
- value = sp_array_alignment<T, U>::value
- };
- typedef typename boost::type_with_alignment<value>::type type;
- };
- template<class T, class U>
- inline U*
- sp_array_start(void* base) BOOST_SP_NOEXCEPT
- {
- enum {
- size = sp_array_offset<T, U>::value
- };
- return reinterpret_cast<U*>(static_cast<char*>(base) + size);
- }
- template<class A, class T>
- class sp_array_creator {
- typedef typename A::value_type scalar;
- enum {
- offset = sp_array_offset<T, scalar>::value
- };
- typedef typename sp_array_storage<T, scalar>::type type;
- public:
- template<class U>
- sp_array_creator(const U& other, std::size_t size) BOOST_SP_NOEXCEPT
- : other_(other),
- size_(sp_objects<type>(offset + sizeof(scalar) * size)) { }
- T* create() {
- return reinterpret_cast<T*>(other_.allocate(size_));
- }
- void destroy(T* base) {
- other_.deallocate(reinterpret_cast<type*>(base), size_);
- }
- private:
- typename sp_bind_allocator<A, type>::type other_;
- std::size_t size_;
- };
- struct sp_default { };
- template<class T, bool E = sp_use_construct<T>::value>
- class sp_array_base
- : public sp_counted_base {
- typedef typename T::type allocator;
- public:
- typedef typename allocator::value_type type;
- template<class A>
- sp_array_base(const A& other, std::size_t size, type* start)
- : state_(other, size) {
- sp_array_construct<E>(state_.allocator(), start, state_.size());
- }
- template<class A>
- sp_array_base(const A& other, std::size_t size, const type* list,
- std::size_t count, type* start)
- : state_(other, size) {
- sp_array_construct<E>(state_.allocator(), start, state_.size(), list,
- count);
- }
- template<class A>
- sp_array_base(sp_default, const A& other, std::size_t size, type* start)
- : state_(other, size) {
- sp_array_default(state_.allocator(), start, state_.size());
- }
- T& state() BOOST_SP_NOEXCEPT {
- return state_;
- }
- virtual void dispose() {
- sp_array_destroy<E>(state_.allocator(),
- sp_array_start<sp_array_base, type>(this), state_.size());
- }
- virtual void destroy() {
- sp_array_creator<allocator, sp_array_base> other(state_.allocator(),
- state_.size());
- this->~sp_array_base();
- other.destroy(this);
- }
- virtual void* get_deleter(const sp_typeinfo&) {
- return 0;
- }
- virtual void* get_local_deleter(const sp_typeinfo&) {
- return 0;
- }
- virtual void* get_untyped_deleter() {
- return 0;
- }
- private:
- T state_;
- };
- template<class A, class T>
- struct sp_array_result {
- public:
- template<class U>
- sp_array_result(const U& other, std::size_t size)
- : creator_(other, size),
- result_(creator_.create()) { }
- ~sp_array_result() {
- if (result_) {
- creator_.destroy(result_);
- }
- }
- T* get() const {
- return result_;
- }
- void release() {
- result_ = 0;
- }
- private:
- sp_array_result(const sp_array_result&);
- sp_array_result& operator=(const sp_array_result&);
- sp_array_creator<A, T> creator_;
- T* result_;
- };
- } /* detail */
- template<class T, class A>
- inline typename detail::sp_if_array<T>::type
- allocate_shared(const A& allocator, std::size_t count)
- {
- typedef typename detail::sp_array_element<T>::type type;
- typedef typename detail::sp_array_scalar<T>::type scalar;
- typedef typename detail::sp_bind_allocator<A, scalar>::type other;
- typedef detail::sp_array_state<other> state;
- typedef detail::sp_array_base<state> base;
- std::size_t size = count * detail::sp_array_count<type>::value;
- detail::sp_array_result<other, base> result(allocator, size);
- detail::sp_counted_base* node = result.get();
- scalar* start = detail::sp_array_start<base, scalar>(node);
- ::new(static_cast<void*>(node)) base(allocator, size, start);
- result.release();
- return shared_ptr<T>(detail::sp_internal_constructor_tag(),
- reinterpret_cast<type*>(start), detail::shared_count(node));
- }
- template<class T, class A>
- inline typename detail::sp_if_size_array<T>::type
- allocate_shared(const A& allocator)
- {
- enum {
- size = detail::sp_array_count<T>::value
- };
- typedef typename detail::sp_array_element<T>::type type;
- typedef typename detail::sp_array_scalar<T>::type scalar;
- typedef typename detail::sp_bind_allocator<A, scalar>::type other;
- typedef detail::sp_size_array_state<other, size> state;
- typedef detail::sp_array_base<state> base;
- detail::sp_array_result<other, base> result(allocator, size);
- detail::sp_counted_base* node = result.get();
- scalar* start = detail::sp_array_start<base, scalar>(node);
- ::new(static_cast<void*>(node)) base(allocator, size, start);
- result.release();
- return shared_ptr<T>(detail::sp_internal_constructor_tag(),
- reinterpret_cast<type*>(start), detail::shared_count(node));
- }
- template<class T, class A>
- inline typename detail::sp_if_array<T>::type
- allocate_shared(const A& allocator, std::size_t count,
- const typename detail::sp_array_element<T>::type& value)
- {
- typedef typename detail::sp_array_element<T>::type type;
- typedef typename detail::sp_array_scalar<T>::type scalar;
- typedef typename detail::sp_bind_allocator<A, scalar>::type other;
- typedef detail::sp_array_state<other> state;
- typedef detail::sp_array_base<state> base;
- std::size_t size = count * detail::sp_array_count<type>::value;
- detail::sp_array_result<other, base> result(allocator, size);
- detail::sp_counted_base* node = result.get();
- scalar* start = detail::sp_array_start<base, scalar>(node);
- ::new(static_cast<void*>(node)) base(allocator, size,
- reinterpret_cast<const scalar*>(&value),
- detail::sp_array_count<type>::value, start);
- result.release();
- return shared_ptr<T>(detail::sp_internal_constructor_tag(),
- reinterpret_cast<type*>(start), detail::shared_count(node));
- }
- template<class T, class A>
- inline typename detail::sp_if_size_array<T>::type
- allocate_shared(const A& allocator,
- const typename detail::sp_array_element<T>::type& value)
- {
- enum {
- size = detail::sp_array_count<T>::value
- };
- typedef typename detail::sp_array_element<T>::type type;
- typedef typename detail::sp_array_scalar<T>::type scalar;
- typedef typename detail::sp_bind_allocator<A, scalar>::type other;
- typedef detail::sp_size_array_state<other, size> state;
- typedef detail::sp_array_base<state> base;
- detail::sp_array_result<other, base> result(allocator, size);
- detail::sp_counted_base* node = result.get();
- scalar* start = detail::sp_array_start<base, scalar>(node);
- ::new(static_cast<void*>(node)) base(allocator, size,
- reinterpret_cast<const scalar*>(&value),
- detail::sp_array_count<type>::value, start);
- result.release();
- return shared_ptr<T>(detail::sp_internal_constructor_tag(),
- reinterpret_cast<type*>(start), detail::shared_count(node));
- }
- template<class T, class A>
- inline typename detail::sp_if_array<T>::type
- allocate_shared_noinit(const A& allocator, std::size_t count)
- {
- typedef typename detail::sp_array_element<T>::type type;
- typedef typename detail::sp_array_scalar<T>::type scalar;
- typedef typename detail::sp_bind_allocator<A, scalar>::type other;
- typedef detail::sp_array_state<other> state;
- typedef detail::sp_array_base<state, false> base;
- std::size_t size = count * detail::sp_array_count<type>::value;
- detail::sp_array_result<other, base> result(allocator, size);
- detail::sp_counted_base* node = result.get();
- scalar* start = detail::sp_array_start<base, scalar>(node);
- ::new(static_cast<void*>(node)) base(detail::sp_default(), allocator,
- size, start);
- result.release();
- return shared_ptr<T>(detail::sp_internal_constructor_tag(),
- reinterpret_cast<type*>(start), detail::shared_count(node));
- }
- template<class T, class A>
- inline typename detail::sp_if_size_array<T>::type
- allocate_shared_noinit(const A& allocator)
- {
- enum {
- size = detail::sp_array_count<T>::value
- };
- typedef typename detail::sp_array_element<T>::type type;
- typedef typename detail::sp_array_scalar<T>::type scalar;
- typedef typename detail::sp_bind_allocator<A, scalar>::type other;
- typedef detail::sp_size_array_state<other, size> state;
- typedef detail::sp_array_base<state, false> base;
- detail::sp_array_result<other, base> result(allocator, size);
- detail::sp_counted_base* node = result.get();
- scalar* start = detail::sp_array_start<base, scalar>(node);
- ::new(static_cast<void*>(node)) base(detail::sp_default(), allocator,
- size, start);
- result.release();
- return shared_ptr<T>(detail::sp_internal_constructor_tag(),
- reinterpret_cast<type*>(start), detail::shared_count(node));
- }
- } /* boost */
- #endif
|