123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- /*
- 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/core/allocator_access.hpp>
- #include <boost/core/alloc_construct.hpp>
- #include <boost/core/first_scalar.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/extent.hpp>
- #include <boost/type_traits/is_bounded_array.hpp>
- #include <boost/type_traits/is_unbounded_array.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_element {
- typedef typename boost::remove_cv<typename
- boost::remove_extent<T>::type>::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)
- };
- };
- 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<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_;
- };
- 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 U, class T>
- inline U*
- sp_array_start(T* base) BOOST_SP_NOEXCEPT
- {
- enum {
- size = sp_array_offset<T, U>::value
- };
- return reinterpret_cast<U*>(reinterpret_cast<char*>(base) + size);
- }
- template<class A, class T>
- class sp_array_creator {
- typedef typename A::value_type element;
- enum {
- offset = sp_array_offset<T, element>::value
- };
- typedef typename boost::type_with_alignment<sp_array_alignment<T,
- element>::value>::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(element) * size)) { }
- T* create() {
- return reinterpret_cast<T*>(other_.allocate(size_));
- }
- void destroy(T* base) {
- other_.deallocate(reinterpret_cast<type*>(base), size_);
- }
- private:
- typename boost::allocator_rebind<A, type>::type other_;
- std::size_t size_;
- };
- template<class T>
- 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, type* start, std::size_t size)
- : state_(other, size) {
- boost::alloc_construct_n(state_.allocator(),
- boost::first_scalar(start),
- state_.size() * sp_array_count<type>::value);
- }
- template<class A, class U>
- sp_array_base(const A& other, type* start, std::size_t size, const U& list)
- : state_(other, size) {
- enum {
- count = sp_array_count<type>::value
- };
- boost::alloc_construct_n(state_.allocator(),
- boost::first_scalar(start), state_.size() * count,
- boost::first_scalar(&list), count);
- }
- T& state() BOOST_SP_NOEXCEPT {
- return state_;
- }
- void dispose() BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
- boost::alloc_destroy_n(state_.allocator(),
- boost::first_scalar(sp_array_start<type>(this)),
- state_.size() * sp_array_count<type>::value);
- }
- void destroy() BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
- sp_array_creator<allocator, sp_array_base> other(state_.allocator(),
- state_.size());
- this->~sp_array_base();
- other.destroy(this);
- }
- void* get_deleter(const sp_typeinfo_&) BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
- return 0;
- }
- void* get_local_deleter(const sp_typeinfo_&)
- BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
- return 0;
- }
- void* get_untyped_deleter() BOOST_SP_NOEXCEPT BOOST_OVERRIDE {
- 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 BOOST_SP_NOEXCEPT {
- return result_;
- }
- void release() BOOST_SP_NOEXCEPT {
- 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 detail::sp_array_element<T>::type element;
- typedef typename allocator_rebind<A, element>::type other;
- typedef detail::sp_array_state<other> state;
- typedef detail::sp_array_base<state> base;
- detail::sp_array_result<other, base> result(allocator, count);
- base* node = result.get();
- element* start = detail::sp_array_start<element>(node);
- ::new(static_cast<void*>(node)) base(allocator, start, count);
- result.release();
- return shared_ptr<T>(detail::sp_internal_constructor_tag(), start,
- detail::shared_count(static_cast<detail::sp_counted_base*>(node)));
- }
- template<class T, class A>
- inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
- allocate_shared(const A& allocator)
- {
- enum {
- count = extent<T>::value
- };
- typedef typename detail::sp_array_element<T>::type element;
- typedef typename allocator_rebind<A, element>::type other;
- typedef detail::sp_size_array_state<other, extent<T>::value> state;
- typedef detail::sp_array_base<state> base;
- detail::sp_array_result<other, base> result(allocator, count);
- base* node = result.get();
- element* start = detail::sp_array_start<element>(node);
- ::new(static_cast<void*>(node)) base(allocator, start, count);
- result.release();
- return shared_ptr<T>(detail::sp_internal_constructor_tag(), start,
- detail::shared_count(static_cast<detail::sp_counted_base*>(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 detail::sp_array_element<T>::type element;
- typedef typename allocator_rebind<A, element>::type other;
- typedef detail::sp_array_state<other> state;
- typedef detail::sp_array_base<state> base;
- detail::sp_array_result<other, base> result(allocator, count);
- base* node = result.get();
- element* start = detail::sp_array_start<element>(node);
- ::new(static_cast<void*>(node)) base(allocator, start, count, value);
- result.release();
- return shared_ptr<T>(detail::sp_internal_constructor_tag(), start,
- detail::shared_count(static_cast<detail::sp_counted_base*>(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)
- {
- enum {
- count = extent<T>::value
- };
- typedef typename detail::sp_array_element<T>::type element;
- typedef typename allocator_rebind<A, element>::type other;
- typedef detail::sp_size_array_state<other, extent<T>::value> state;
- typedef detail::sp_array_base<state> base;
- detail::sp_array_result<other, base> result(allocator, count);
- base* node = result.get();
- element* start = detail::sp_array_start<element>(node);
- ::new(static_cast<void*>(node)) base(allocator, start, count, value);
- result.release();
- return shared_ptr<T>(detail::sp_internal_constructor_tag(), start,
- detail::shared_count(static_cast<detail::sp_counted_base*>(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)
- {
- return boost::allocate_shared<T>(boost::noinit_adapt(allocator), count);
- }
- template<class T, class A>
- inline typename enable_if_<is_bounded_array<T>::value, shared_ptr<T> >::type
- allocate_shared_noinit(const A& allocator)
- {
- return boost::allocate_shared<T>(boost::noinit_adapt(allocator));
- }
- } /* boost */
- #endif
|