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