EVOLUTION-MANAGER
Edit File: allocate_shared_array.hpp
/* 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/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) }; }; #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<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 sp_bind_allocator<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_; } virtual void dispose() BOOST_SP_NOEXCEPT { boost::alloc_destroy_n(state_.allocator(), boost::first_scalar(sp_array_start<type>(this)), state_.size() * sp_array_count<type>::value); } 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 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 detail::sp_bind_allocator<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 detail::sp_bind_allocator<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 detail::sp_bind_allocator<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 detail::sp_bind_allocator<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