/* 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 #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace detail { template struct sp_array_element { typedef typename boost::remove_cv::type>::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) }; }; template BOOST_CONSTEXPR inline std::size_t sp_objects(std::size_t size) BOOST_SP_NOEXCEPT { return (size + sizeof(T) - 1) / sizeof(T); } 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_; }; 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 inline U* sp_array_start(T* base) BOOST_SP_NOEXCEPT { enum { size = sp_array_offset::value }; return reinterpret_cast(reinterpret_cast(base) + size); } template class sp_array_creator { typedef typename A::value_type element; enum { offset = sp_array_offset::value }; typedef typename boost::type_with_alignment::value>::type type; public: template sp_array_creator(const U& other, std::size_t size) BOOST_SP_NOEXCEPT : other_(other), size_(sp_objects(offset + sizeof(element) * size)) { } T* create() { return reinterpret_cast(other_.allocate(size_)); } void destroy(T* base) { other_.deallocate(reinterpret_cast(base), size_); } private: typename boost::allocator_rebind::type other_; std::size_t size_; }; template class BOOST_SYMBOL_VISIBLE 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, type* start, std::size_t size) : state_(other, size) { boost::alloc_construct_n(state_.allocator(), boost::first_scalar(start), state_.size() * sp_array_count::value); } template sp_array_base(const A& other, type* start, std::size_t size, const U& list) : state_(other, size) { enum { count = sp_array_count::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(this)), state_.size() * sp_array_count::value); } void destroy() BOOST_SP_NOEXCEPT BOOST_OVERRIDE { sp_array_creator 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 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 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 creator_; T* result_; }; } /* detail */ template inline typename enable_if_::value, shared_ptr >::type allocate_shared(const A& allocator, std::size_t count) { typedef typename detail::sp_array_element::type element; typedef typename allocator_rebind::type other; typedef detail::sp_array_state state; typedef detail::sp_array_base base; detail::sp_array_result result(allocator, count); base* node = result.get(); element* start = detail::sp_array_start(node); ::new(static_cast(node)) base(allocator, start, count); result.release(); return shared_ptr(detail::sp_internal_constructor_tag(), start, detail::shared_count(static_cast(node))); } template inline typename enable_if_::value, shared_ptr >::type allocate_shared(const A& allocator) { enum { count = extent::value }; typedef typename detail::sp_array_element::type element; typedef typename allocator_rebind::type other; typedef detail::sp_size_array_state::value> state; typedef detail::sp_array_base base; detail::sp_array_result result(allocator, count); base* node = result.get(); element* start = detail::sp_array_start(node); ::new(static_cast(node)) base(allocator, start, count); result.release(); return shared_ptr(detail::sp_internal_constructor_tag(), start, detail::shared_count(static_cast(node))); } template inline typename enable_if_::value, shared_ptr >::type allocate_shared(const A& allocator, std::size_t count, const typename remove_extent::type& value) { typedef typename detail::sp_array_element::type element; typedef typename allocator_rebind::type other; typedef detail::sp_array_state state; typedef detail::sp_array_base base; detail::sp_array_result result(allocator, count); base* node = result.get(); element* start = detail::sp_array_start(node); ::new(static_cast(node)) base(allocator, start, count, value); result.release(); return shared_ptr(detail::sp_internal_constructor_tag(), start, detail::shared_count(static_cast(node))); } template inline typename enable_if_::value, shared_ptr >::type allocate_shared(const A& allocator, const typename remove_extent::type& value) { enum { count = extent::value }; typedef typename detail::sp_array_element::type element; typedef typename allocator_rebind::type other; typedef detail::sp_size_array_state::value> state; typedef detail::sp_array_base base; detail::sp_array_result result(allocator, count); base* node = result.get(); element* start = detail::sp_array_start(node); ::new(static_cast(node)) base(allocator, start, count, value); result.release(); return shared_ptr(detail::sp_internal_constructor_tag(), start, detail::shared_count(static_cast(node))); } template inline typename enable_if_::value, shared_ptr >::type allocate_shared_noinit(const A& allocator, std::size_t count) { return boost::allocate_shared(boost::noinit_adapt(allocator), count); } template inline typename enable_if_::value, shared_ptr >::type allocate_shared_noinit(const A& allocator) { return boost::allocate_shared(boost::noinit_adapt(allocator)); } } /* boost */ #endif