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