Chris@102: /* Chris@102: * Copyright (c) 2012-2014 Glen Joseph Fernandes Chris@102: * glenfe at live dot com Chris@102: * Chris@102: * Distributed under the Boost Software License, Chris@102: * Version 1.0. (See accompanying file LICENSE_1_0.txt Chris@102: * or copy at http://boost.org/LICENSE_1_0.txt) Chris@102: */ Chris@102: #ifndef BOOST_SMART_PTR_DETAIL_ARRAY_ALLOCATOR_HPP Chris@102: #define BOOST_SMART_PTR_DETAIL_ARRAY_ALLOCATOR_HPP Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: namespace boost { Chris@102: namespace detail { Chris@102: struct ms_init_tag { }; Chris@102: struct ms_noinit_tag { }; Chris@102: Chris@102: template Chris@102: struct ms_allocator_state; Chris@102: Chris@102: template Chris@102: struct ms_allocator_state { Chris@102: typedef typename array_base::type type; Chris@102: Chris@102: ms_allocator_state(std::size_t size_, Chris@102: type** result_) Chris@102: : size(size_ * array_total::size), Chris@102: result(result_) { Chris@102: } Chris@102: Chris@102: std::size_t size; Chris@102: Chris@102: union { Chris@102: type** result; Chris@102: type* object; Chris@102: }; Chris@102: }; Chris@102: Chris@102: template Chris@102: struct ms_allocator_state { Chris@102: typedef typename array_base::type type; Chris@102: Chris@102: ms_allocator_state(type** result_) Chris@102: : result(result_) { Chris@102: } Chris@102: Chris@102: enum { Chris@102: size = array_total::size Chris@102: }; Chris@102: Chris@102: union { Chris@102: type** result; Chris@102: type* object; Chris@102: }; Chris@102: }; Chris@102: Chris@102: template Chris@102: class as_allocator Chris@102: : public A { Chris@102: template Chris@102: friend class as_allocator; Chris@102: Chris@102: #if !defined(BOOST_NO_CXX11_ALLOCATOR) Chris@102: typedef std::allocator_traits AT; Chris@102: typedef typename AT::template rebind_alloc CA; Chris@102: typedef typename AT::template rebind_traits CT; Chris@102: #else Chris@102: typedef typename A::template rebind::other CA; Chris@102: #endif Chris@102: Chris@102: public: Chris@102: typedef A allocator_type; Chris@102: Chris@102: #if !defined(BOOST_NO_CXX11_ALLOCATOR) Chris@102: typedef typename AT::value_type value_type; Chris@102: typedef typename AT::pointer pointer; Chris@102: typedef typename AT::const_pointer const_pointer; Chris@102: typedef typename AT::void_pointer void_pointer; Chris@102: typedef typename AT::const_void_pointer const_void_pointer; Chris@102: typedef typename AT::size_type size_type; Chris@102: typedef typename AT::difference_type difference_type; Chris@102: #else Chris@102: typedef typename A::value_type value_type; Chris@102: typedef typename A::pointer pointer; Chris@102: typedef typename A::const_pointer const_pointer; Chris@102: typedef typename A::size_type size_type; Chris@102: typedef typename A::difference_type difference_type; Chris@102: typedef typename A::reference reference; Chris@102: typedef typename A::const_reference const_reference; Chris@102: typedef void* void_pointer; Chris@102: typedef const void* const_void_pointer; Chris@102: #endif Chris@102: Chris@102: template Chris@102: struct rebind { Chris@102: #if !defined(BOOST_NO_CXX11_ALLOCATOR) Chris@102: typedef as_allocator, T, R> other; Chris@102: #else Chris@102: typedef as_allocator::other, T, R> other; Chris@102: #endif Chris@102: }; Chris@102: Chris@102: typedef typename array_base::type type; Chris@102: Chris@102: as_allocator(const A& allocator_, type** result) Chris@102: : A(allocator_), Chris@102: data(result) { Chris@102: } Chris@102: Chris@102: as_allocator(const A& allocator_, std::size_t size, Chris@102: type** result) Chris@102: : A(allocator_), Chris@102: data(size, result) { Chris@102: } Chris@102: Chris@102: template Chris@102: as_allocator(const as_allocator& other) Chris@102: : A(other.allocator()), Chris@102: data(other.data) { Chris@102: } Chris@102: Chris@102: pointer allocate(size_type count, const_void_pointer = 0) { Chris@102: enum { Chris@102: M = boost::alignment_of::value Chris@102: }; Chris@102: std::size_t n1 = count * sizeof(value_type); Chris@102: std::size_t n2 = data.size * sizeof(type); Chris@102: std::size_t n3 = n2 + M; Chris@102: CA ca(allocator()); Chris@102: void* p1 = ca.allocate(n1 + n3); Chris@102: void* p2 = static_cast(p1) + n1; Chris@102: (void)boost::alignment::align(M, n2, p2, n3); Chris@102: *data.result = static_cast(p2); Chris@102: return static_cast(p1); Chris@102: } Chris@102: Chris@102: void deallocate(pointer memory, size_type count) { Chris@102: enum { Chris@102: M = boost::alignment_of::value Chris@102: }; Chris@102: std::size_t n1 = count * sizeof(value_type); Chris@102: std::size_t n2 = data.size * sizeof(type) + M; Chris@102: char* p1 = reinterpret_cast(memory); Chris@102: CA ca(allocator()); Chris@102: ca.deallocate(p1, n1 + n2); Chris@102: } Chris@102: Chris@102: const A& allocator() const { Chris@102: return static_cast(*this); Chris@102: } Chris@102: Chris@102: A& allocator() { Chris@102: return static_cast(*this); Chris@102: } Chris@102: Chris@102: void set(type* memory) { Chris@102: data.object = memory; Chris@102: } Chris@102: Chris@102: void operator()() { Chris@102: if (data.object) { Chris@102: R tag; Chris@102: release(tag); Chris@102: } Chris@102: } Chris@102: Chris@102: private: Chris@102: void release(ms_init_tag) { Chris@102: #if !defined(BOOST_NO_CXX11_ALLOCATOR) Chris@102: as_destroy(allocator(), data.object, data.size); Chris@102: #else Chris@102: ms_destroy(data.object, data.size); Chris@102: #endif Chris@102: } Chris@102: Chris@102: void release(ms_noinit_tag) { Chris@102: ms_destroy(data.object, data.size); Chris@102: } Chris@102: Chris@102: ms_allocator_state data; Chris@102: }; Chris@102: Chris@102: template Chris@102: bool operator==(const as_allocator& a1, Chris@102: const as_allocator& a2) { Chris@102: return a1.allocator() == a2.allocator(); Chris@102: } Chris@102: Chris@102: template Chris@102: bool operator!=(const as_allocator& a1, Chris@102: const as_allocator& a2) { Chris@102: return a1.allocator() != a2.allocator(); Chris@102: } Chris@102: Chris@102: template Chris@102: class ms_allocator; Chris@102: Chris@102: template Chris@102: class ms_allocator { Chris@102: template Chris@102: friend class ms_allocator; Chris@102: Chris@102: public: Chris@102: typedef typename array_base::type type; Chris@102: Chris@102: typedef Y value_type; Chris@102: typedef Y* pointer; Chris@102: typedef const Y* const_pointer; Chris@102: typedef std::size_t size_type; Chris@102: typedef std::ptrdiff_t difference_type; Chris@102: typedef Y& reference; Chris@102: typedef const Y& const_reference; Chris@102: Chris@102: template Chris@102: struct rebind { Chris@102: typedef ms_allocator other; Chris@102: }; Chris@102: Chris@102: ms_allocator(type** result) Chris@102: : data(result) { Chris@102: } Chris@102: Chris@102: ms_allocator(std::size_t size, type** result) Chris@102: : data(size, result) { Chris@102: } Chris@102: Chris@102: template Chris@102: ms_allocator(const ms_allocator& other) Chris@102: : data(other.data) { Chris@102: } Chris@102: Chris@102: pointer allocate(size_type count, const void* = 0) { Chris@102: enum { Chris@102: M = boost::alignment_of::value Chris@102: }; Chris@102: std::size_t n1 = count * sizeof(Y); Chris@102: std::size_t n2 = data.size * sizeof(type); Chris@102: std::size_t n3 = n2 + M; Chris@102: void* p1 = ::operator new(n1 + n3); Chris@102: void* p2 = static_cast(p1) + n1; Chris@102: (void)boost::alignment::align(M, n2, p2, n3); Chris@102: *data.result = static_cast(p2); Chris@102: return static_cast(p1); Chris@102: } Chris@102: Chris@102: void deallocate(pointer memory, size_type) { Chris@102: void* p1 = memory; Chris@102: ::operator delete(p1); Chris@102: } Chris@102: Chris@102: #if defined(BOOST_NO_CXX11_ALLOCATOR) Chris@102: pointer address(reference value) const { Chris@102: return &value; Chris@102: } Chris@102: Chris@102: const_pointer address(const_reference value) const { Chris@102: return &value; Chris@102: } Chris@102: Chris@102: size_type max_size() const { Chris@102: enum { Chris@102: N = static_cast(-1) / sizeof(Y) Chris@102: }; Chris@102: return N; Chris@102: } Chris@102: Chris@102: void construct(pointer memory, const_reference value) { Chris@102: void* p1 = memory; Chris@102: ::new(p1) Y(value); Chris@102: } Chris@102: Chris@102: void destroy(pointer memory) { Chris@102: (void)memory; Chris@102: memory->~Y(); Chris@102: } Chris@102: #endif Chris@102: Chris@102: void set(type* memory) { Chris@102: data.object = memory; Chris@102: } Chris@102: Chris@102: void operator()() { Chris@102: if (data.object) { Chris@102: ms_destroy(data.object, data.size); Chris@102: } Chris@102: } Chris@102: Chris@102: private: Chris@102: ms_allocator_state data; Chris@102: }; Chris@102: Chris@102: template Chris@102: bool operator==(const ms_allocator&, Chris@102: const ms_allocator&) { Chris@102: return true; Chris@102: } Chris@102: Chris@102: template Chris@102: bool operator!=(const ms_allocator&, Chris@102: const ms_allocator&) { Chris@102: return false; Chris@102: } Chris@102: Chris@102: class ms_in_allocator_tag { Chris@102: public: Chris@102: void operator()(const void*) { Chris@102: } Chris@102: }; Chris@102: } Chris@102: } Chris@102: Chris@102: #endif