Refactor make_array_helper and array_deleter

Reduce the amount of code in allocate_array_helper, make_array_helper, and
array_deleter using the empty base class optimization technique.
This commit is contained in:
Glen Fernandes
2014-02-02 22:00:08 -08:00
parent aede0039bf
commit 63a05a3576
5 changed files with 135 additions and 277 deletions

View File

@ -11,7 +11,6 @@
#include <boost/smart_ptr/detail/allocate_array_helper.hpp>
#include <boost/smart_ptr/detail/array_deleter.hpp>
#include <boost/smart_ptr/detail/array_traits.hpp>
#include <boost/smart_ptr/detail/sp_if_array.hpp>
#include <boost/type_traits/remove_cv.hpp>

View File

@ -9,45 +9,53 @@
#ifndef BOOST_SMART_PTR_DETAIL_ALLOCATE_ARRAY_HELPER_HPP
#define BOOST_SMART_PTR_DETAIL_ALLOCATE_ARRAY_HELPER_HPP
#include <boost/smart_ptr/detail/array_size_base.hpp>
#include <boost/smart_ptr/detail/array_traits.hpp>
#include <boost/type_traits/alignment_of.hpp>
namespace boost {
namespace detail {
template<typename A, typename T, typename Y = char>
class allocate_array_helper;
class allocate_array_helper
: array_size_base<T> {
using array_size_base<T>::size;
template<typename A, typename T, typename Y>
class allocate_array_helper<A, T[], Y> {
template<typename A9, typename T9, typename Y9>
template<typename A_, typename T_, typename Y_>
friend class allocate_array_helper;
typedef typename A::template rebind<Y> ::other A2;
typedef typename A::template rebind<char>::other A3;
typedef typename A::template rebind<char>::other A3;
public:
typedef typename A2::value_type value_type;
typedef typename A2::pointer pointer;
typedef typename A2::const_pointer const_pointer;
typedef typename A2::reference reference;
typedef typename array_inner<T>::type type;
typedef typename A2::value_type value_type;
typedef typename A2::pointer pointer;
typedef typename A2::const_pointer const_pointer;
typedef typename A2::reference reference;
typedef typename A2::const_reference const_reference;
typedef typename A2::size_type size_type;
typedef typename A2::size_type size_type;
typedef typename A2::difference_type difference_type;
template<typename U>
struct rebind {
typedef allocate_array_helper<A, T[], U> other;
typedef allocate_array_helper<A, T, U> other;
};
allocate_array_helper(const A& allocator_, std::size_t size_, T** data_)
allocate_array_helper(const A& allocator_, type** data_)
: allocator(allocator_),
size(sizeof(T) * size_),
data(data_) {
}
allocate_array_helper(const A& allocator_, std::size_t size_, type** data_)
: array_size_base<T>(size_),
allocator(allocator_),
data(data_) {
}
template<class U>
allocate_array_helper(const allocate_array_helper<A, T[], U>& other)
: allocator(other.allocator),
size(other.size),
allocate_array_helper(const allocate_array_helper<A, T, U>& other)
: array_size_base<T>(other),
allocator(other.allocator),
data(other.data) {
}
@ -64,22 +72,22 @@ namespace boost {
}
pointer allocate(size_type count, const void* value = 0) {
std::size_t a1 = boost::alignment_of<T>::value;
std::size_t a1 = boost::alignment_of<type>::value;
std::size_t n1 = count * sizeof(Y) + a1 - 1;
char* p1 = A3(allocator).allocate(n1 + size, value);
char* p2 = p1 + n1;
char* p1 = A3(allocator).allocate(size + n1, value);
char* p2 = p1 + n1;
while (std::size_t(p2) % a1 != 0) {
p2--;
}
*data = reinterpret_cast<T*>(p2);
return reinterpret_cast<Y*>(p1);
*data = reinterpret_cast<type*>(p2);
return reinterpret_cast<Y*>(p1);
}
void deallocate(pointer memory, size_type count) {
std::size_t a1 = boost::alignment_of<T>::value;
std::size_t a1 = boost::alignment_of<type>::value;
std::size_t n1 = count * sizeof(Y) + a1 - 1;
char* p1 = reinterpret_cast<char*>(memory);
A3(allocator).deallocate(p1, n1 + size);
char* p1 = reinterpret_cast<char*>(memory);
A3(allocator).deallocate(p1, size + n1);
}
void construct(pointer memory, const Y& value) {
@ -91,110 +99,18 @@ namespace boost {
}
template<typename U>
bool operator==(const allocate_array_helper<A, T[], U>& other) const {
bool operator==(const allocate_array_helper<A, T, U>& other) const {
return allocator == other.allocator;
}
template<typename U>
bool operator!=(const allocate_array_helper<A, T[], U>& other) const {
bool operator!=(const allocate_array_helper<A, T, U>& other) const {
return !(*this == other);
}
private:
A2 allocator;
std::size_t size;
T** data;
};
template<typename A, typename T, std::size_t N, typename Y>
class allocate_array_helper<A, T[N], Y> {
template<typename A9, typename T9, typename Y9>
friend class allocate_array_helper;
typedef typename A::template rebind<Y> ::other A2;
typedef typename A::template rebind<char>::other A3;
public:
typedef typename A2::value_type value_type;
typedef typename A2::pointer pointer;
typedef typename A2::const_pointer const_pointer;
typedef typename A2::reference reference;
typedef typename A2::const_reference const_reference;
typedef typename A2::size_type size_type;
typedef typename A2::difference_type difference_type;
template<typename U>
struct rebind {
typedef allocate_array_helper<A, T[N], U> other;
};
allocate_array_helper(const A& allocator_, T** data_)
: allocator(allocator_),
data(data_) {
}
template<class U>
allocate_array_helper(const allocate_array_helper<A, T[N], U>& other)
: allocator(other.allocator),
data(other.data) {
}
pointer address(reference value) const {
return allocator.address(value);
}
const_pointer address(const_reference value) const {
return allocator.address(value);
}
size_type max_size() const {
return allocator.max_size();
}
pointer allocate(size_type count, const void* value = 0) {
std::size_t a1 = boost::alignment_of<T>::value;
std::size_t n1 = count * sizeof(Y) + a1 - 1;
char* p1 = A3(allocator).allocate(n1 + N1, value);
char* p2 = p1 + n1;
while (std::size_t(p2) % a1 != 0) {
p2--;
}
*data = reinterpret_cast<T*>(p2);
return reinterpret_cast<Y*>(p1);
}
void deallocate(pointer memory, size_type count) {
std::size_t a1 = boost::alignment_of<T>::value;
std::size_t n1 = count * sizeof(Y) + a1 - 1;
char* p1 = reinterpret_cast<char*>(memory);
A3(allocator).deallocate(p1, n1 + N1);
}
void construct(pointer memory, const Y& value) {
allocator.construct(memory, value);
}
void destroy(pointer memory) {
allocator.destroy(memory);
}
template<typename U>
bool operator==(const allocate_array_helper<A, T[N], U>& other) const {
return allocator == other.allocator;
}
template<typename U>
bool operator!=(const allocate_array_helper<A, T[N], U>& other) const {
return !(*this == other);
}
private:
enum {
N1 = N * sizeof(T)
};
A2 allocator;
T** data;
type** data;
};
}
}

View File

@ -15,13 +15,38 @@
namespace boost {
namespace detail {
template<typename T>
class array_deleter;
struct array_count_base;
template<typename T>
class array_deleter<T[]> {
struct array_count_base<T[]> {
array_count_base(std::size_t size_)
: size(size_) {
}
std::size_t size;
};
template<typename T, std::size_t N>
struct array_count_base<T[N]> {
enum {
size = N
};
};
template<typename T>
class array_deleter
: array_count_base<T> {
using array_count_base<T>::size;
public:
typedef typename array_inner<T>::type type;
array_deleter()
: object(0) {
}
array_deleter(std::size_t size_)
: size(size_),
: array_count_base<T>(size_),
object(0) {
}
@ -31,18 +56,18 @@ namespace boost {
}
}
void init(T* memory) {
void init(type* memory) {
array_init(memory, size);
object = memory;
}
template<std::size_t N>
void init(T* memory, const T* value) {
array_init<T, N>(memory, size, value);
void init(type* memory, const type* value) {
array_init<type, N>(memory, size, value);
object = memory;
}
void noinit(T* memory) {
void noinit(type* memory) {
array_noinit(memory, size);
object = memory;
}
@ -55,49 +80,8 @@ namespace boost {
}
private:
std::size_t size;
T* object;
};
template<typename T, std::size_t N>
class array_deleter<T[N]> {
public:
array_deleter()
: object(0) {
}
~array_deleter() {
if (object) {
array_destroy(object, N);
}
}
void init(T* memory) {
array_init(memory, N);
object = memory;
}
template<std::size_t M>
void init(T* memory, const T* value) {
array_init<T, M>(memory, N, value);
object = memory;
}
void noinit(T* memory) {
array_noinit(memory, N);
object = memory;
}
void operator()(const void*) {
if (object) {
array_destroy(object, N);
object = 0;
}
}
private:
T* object;
};
type* object;
};
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 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_SIZE_BASE_HPP
#define BOOST_SMART_PTR_DETAIL_ARRAY_SIZE_BASE_HPP
#include <cstddef>
namespace boost {
namespace detail {
template<typename T>
struct array_size_base;
template<typename T>
struct array_size_base<T[]> {
array_size_base(std::size_t size_)
: size(size_ * sizeof(T)) {
}
std::size_t size;
};
template<typename T, std::size_t N>
struct array_size_base<T[N]> {
enum {
size = N * sizeof(T)
};
};
}
}
#endif

View File

@ -9,40 +9,47 @@
#ifndef BOOST_SMART_PTR_DETAIL_MAKE_ARRAY_HELPER_HPP
#define BOOST_SMART_PTR_DETAIL_MAKE_ARRAY_HELPER_HPP
#include <boost/smart_ptr/detail/array_size_base.hpp>
#include <boost/smart_ptr/detail/array_traits.hpp>
#include <boost/type_traits/alignment_of.hpp>
namespace boost {
namespace detail {
template<typename T, typename Y = char>
class make_array_helper;
class make_array_helper
: array_size_base<T> {
using array_size_base<T>::size;
template<typename T, typename Y>
class make_array_helper<T[], Y> {
template<typename T2, typename Y2>
friend class make_array_helper;
public:
typedef Y value_type;
typedef Y* pointer;
typedef const Y* const_pointer;
typedef Y& reference;
typedef const Y& const_reference;
typedef typename array_inner<T>::type type;
typedef Y value_type;
typedef Y* pointer;
typedef const Y* const_pointer;
typedef Y& reference;
typedef const Y& const_reference;
typedef std::size_t size_type;
typedef ptrdiff_t difference_type;
typedef ptrdiff_t difference_type;
template<typename U>
struct rebind {
typedef make_array_helper<T[], U> other;
typedef make_array_helper<T, U> other;
};
make_array_helper(std::size_t size_, T** data_)
: size(sizeof(T) * size_),
make_array_helper(type** data_)
: data(data_) {
}
make_array_helper(std::size_t size_, type** data_)
: array_size_base<T>(size_),
data(data_) {
}
template<class U>
make_array_helper(const make_array_helper<T[], U>& other)
: size(other.size),
make_array_helper(const make_array_helper<T, U>& other)
: array_size_base<T>(other),
data(other.data) {
}
@ -59,15 +66,15 @@ namespace boost {
}
pointer allocate(size_type count, const void* = 0) {
std::size_t a1 = boost::alignment_of<T>::value;
std::size_t a1 = boost::alignment_of<type>::value;
std::size_t n1 = count * sizeof(Y) + a1 - 1;
void* p1 = ::operator new(n1 + size);
char* p2 = static_cast<char*>(p1) + n1;
void* p1 = ::operator new(n1 + size);
char* p2 = static_cast<char*>(p1) + n1;
while (std::size_t(p2) % a1 != 0) {
p2--;
}
*data = reinterpret_cast<T*>(p2);
return reinterpret_cast<Y*>(p1);
*data = reinterpret_cast<type*>(p2);
return reinterpret_cast<Y*>(p1);
}
void deallocate(pointer memory, size_type) {
@ -85,102 +92,17 @@ namespace boost {
}
template<typename U>
bool operator==(const make_array_helper<T[], U>&) const {
bool operator==(const make_array_helper<T, U>&) const {
return true;
}
template<typename U>
bool operator!=(const make_array_helper<T[], U>& other) const {
bool operator!=(const make_array_helper<T, U>& other) const {
return !(*this == other);
}
private:
std::size_t size;
T** data;
};
template<typename T, std::size_t N, typename Y>
class make_array_helper<T[N], Y> {
template<typename T2, typename Y2>
friend class make_array_helper;
public:
typedef Y value_type;
typedef Y* pointer;
typedef const Y* const_pointer;
typedef Y& reference;
typedef const Y& const_reference;
typedef std::size_t size_type;
typedef ptrdiff_t difference_type;
template<typename U>
struct rebind {
typedef make_array_helper<T[N], U> other;
};
make_array_helper(T** data_)
: data(data_) {
}
template<class U>
make_array_helper(const make_array_helper<T[N], U>& other)
: data(other.data) {
}
pointer address(reference value) const {
return &value;
}
const_pointer address(const_reference value) const {
return &value;
}
size_type max_size() const {
return static_cast<std::size_t>(-1) / sizeof(Y);
}
pointer allocate(size_type count, const void* = 0) {
std::size_t a1 = boost::alignment_of<T>::value;
std::size_t n1 = count * sizeof(Y) + a1 - 1;
void* p1 = ::operator new(n1 + N1);
char* p2 = static_cast<char*>(p1) + n1;
while (std::size_t(p2) % a1 != 0) {
p2--;
}
*data = reinterpret_cast<T*>(p2);
return reinterpret_cast<Y*>(p1);
}
void deallocate(pointer memory, size_type) {
void* p1 = memory;
::operator delete(p1);
}
void construct(pointer memory, const Y& value) {
void* p1 = memory;
::new(p1) Y(value);
}
void destroy(pointer memory) {
memory->~Y();
}
template<typename U>
bool operator==(const make_array_helper<T[N], U>&) const {
return true;
}
template<typename U>
bool operator!=(const make_array_helper<T[N], U>& other) const {
return !(*this == other);
}
private:
enum {
N1 = N * sizeof(T)
};
T** data;
type** data;
};
}
}