| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577 |
- /*
- Copyright 2012-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_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/enable_if.hpp>
- #include <boost/type_traits/is_bounded_array.hpp>
- #include <boost/type_traits/is_unbounded_array.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/remove_all_extents.hpp>
- #include <boost/type_traits/remove_cv.hpp>
- #include <boost/type_traits/remove_extent.hpp>
- #include <boost/type_traits/type_with_alignment.hpp>
- namespace boost {
- namespace detail {
- template<class T>
- struct sp_array_scalar {
- typedef typename boost::remove_cv<typename
- boost::remove_all_extents<T>::type>::type type;
- };
- template<class T, class U>
- struct sp_array_count {
- enum {
- value = sizeof(T) / sizeof(U)
- };
- };
- 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 E, class A, class T>
- inline typename boost::enable_if_<!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 boost::enable_if_<!E &&
- !boost::has_trivial_destructor<T>::value>::type
- sp_array_destroy(A&, T* ptr, std::size_t size)
- {
- while (size > 0) {
- ptr[--size].~T();
- }
- }
- #if !defined(BOOST_NO_CXX11_ALLOCATOR)
- template<bool E, class A, class T>
- inline typename boost::enable_if_<E>::type
- sp_array_destroy(A& allocator, T* ptr, std::size_t size)
- {
- while (size > 0) {
- std::allocator_traits<A>::destroy(allocator, ptr + --size);
- }
- }
- #endif
- template<bool E, class A, class T>
- class sp_destroyer {
- public:
- sp_destroyer(A& allocator, T* ptr) BOOST_SP_NOEXCEPT
- : allocator_(allocator),
- ptr_(ptr),
- size_(0) { }
- ~sp_destroyer() {
- sp_array_destroy<E>(allocator_, ptr_, size_);
- }
- std::size_t& size() BOOST_SP_NOEXCEPT {
- return size_;
- }
- private:
- sp_destroyer(const sp_destroyer&);
- sp_destroyer& operator=(const sp_destroyer&);
- A& allocator_;
- T* ptr_;
- std::size_t size_;
- };
- template<bool E, class A, class T>
- inline typename boost::enable_if_<!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* ptr, std::size_t size)
- {
- for (std::size_t i = 0; i < size; ++i) {
- ptr[i] = T();
- }
- }
- template<bool E, class A, class T>
- inline typename boost::enable_if_<!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* ptr, std::size_t size, const T* list,
- std::size_t count)
- {
- for (std::size_t i = 0; i < size; ++i) {
- ptr[i] = list[i % count];
- }
- }
- template<bool E, class A, class T>
- inline typename boost::enable_if_<!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* ptr, std::size_t size)
- {
- sp_destroyer<E, A, T> hold(none, ptr);
- for (std::size_t& i = hold.size(); i < size; ++i) {
- ::new(static_cast<void*>(ptr + i)) T();
- }
- hold.size() = 0;
- }
- template<bool E, class A, class T>
- inline typename boost::enable_if_<!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* ptr, std::size_t size, const T* list,
- std::size_t count)
- {
- sp_destroyer<E, A, T> hold(none, ptr);
- for (std::size_t& i = hold.size(); i < size; ++i) {
- ::new(static_cast<void*>(ptr + i)) T(list[i % count]);
- }
- hold.size() = 0;
- }
- #if !defined(BOOST_NO_CXX11_ALLOCATOR)
- template<bool E, class A, class T>
- inline typename boost::enable_if_<E>::type
- sp_array_construct(A& allocator, T* ptr, std::size_t size)
- {
- sp_destroyer<E, A, T> hold(allocator, ptr);
- for (std::size_t& i = hold.size(); i < size; ++i) {
- std::allocator_traits<A>::construct(allocator, ptr + i);
- }
- hold.size() = 0;
- }
- template<bool E, class A, class T>
- inline typename boost::enable_if_<E>::type
- sp_array_construct(A& allocator, T* ptr, std::size_t size, const T* list,
- std::size_t count)
- {
- sp_destroyer<E, A, T> hold(allocator, ptr);
- for (std::size_t& i = hold.size(); i < size; ++i) {
- std::allocator_traits<A>::construct(allocator, ptr + i,
- list[i % count]);
- }
- hold.size() = 0;
- }
- #endif
- template<class A, class T>
- inline typename
- boost::enable_if_<boost::has_trivial_constructor<T>::value>::type
- sp_array_default(A&, T*, std::size_t) BOOST_SP_NOEXCEPT { }
- template<class A, class T>
- inline typename
- boost::enable_if_<!boost::has_trivial_constructor<T>::value>::type
- sp_array_default(A& none, T* ptr, std::size_t size)
- {
- sp_destroyer<false, A, T> hold(none, ptr);
- for (std::size_t& i = hold.size(); i < size; ++i) {
- ::new(static_cast<void*>(ptr + i)) T;
- }
- hold.size() = 0;
- }
- 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 BOOST_SYMBOL_VISIBLE 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() BOOST_SP_NOEXCEPT {
- sp_array_destroy<E>(state_.allocator(),
- sp_array_start<sp_array_base, type>(this), state_.size());
- }
- virtual void destroy() BOOST_SP_NOEXCEPT {
- 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&) BOOST_SP_NOEXCEPT {
- return 0;
- }
- virtual void* get_local_deleter(const sp_typeinfo&) BOOST_SP_NOEXCEPT {
- return 0;
- }
- virtual void* get_untyped_deleter() BOOST_SP_NOEXCEPT {
- 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 enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
- allocate_shared(const A& allocator, std::size_t count)
- {
- typedef typename remove_extent<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, scalar>::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 enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
- allocate_shared(const A& allocator)
- {
- typedef typename remove_extent<T>::type type;
- typedef typename detail::sp_array_scalar<T>::type scalar;
- typedef typename detail::sp_bind_allocator<A, scalar>::type other;
- enum {
- size = detail::sp_array_count<T, scalar>::value
- };
- 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 enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
- allocate_shared(const A& allocator, std::size_t count,
- const typename remove_extent<T>::type& value)
- {
- typedef typename remove_extent<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;
- enum {
- total = detail::sp_array_count<type, scalar>::value
- };
- std::size_t size = count * total;
- 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), total, 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 enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
- allocate_shared(const A& allocator,
- const typename remove_extent<T>::type& value)
- {
- typedef typename remove_extent<T>::type type;
- typedef typename detail::sp_array_scalar<T>::type scalar;
- typedef typename detail::sp_bind_allocator<A, scalar>::type other;
- enum {
- size = detail::sp_array_count<T, scalar>::value
- };
- 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, scalar>::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 enable_if_<is_unbounded_array<T>::value, shared_ptr<T> >::type
- allocate_shared_noinit(const A& allocator, std::size_t count)
- {
- typedef typename remove_extent<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, scalar>::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 enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
- allocate_shared_noinit(const A& allocator)
- {
- typedef typename remove_extent<T>::type type;
- typedef typename detail::sp_array_scalar<T>::type scalar;
- typedef typename detail::sp_bind_allocator<A, scalar>::type other;
- enum {
- size = detail::sp_array_count<T, scalar>::value
- };
- 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
|