1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
/*** Copyright 2010 ***** S.A.R.L. ***
* File : utility.hpp
* Date : 08/01/2010
*** ***/
#ifndef UTILITY_HPP_INC_08_01_2010__252705754_
#define UTILITY_HPP_INC_08_01_2010__252705754_ 1
#include <boost/operators.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/utility/in_place_factory.hpp>
#include <boost/static_assert.hpp>
#include <new>
#include <assert.h>
#define TOOLS_ASSERT_REL(x) do{assert(x);}while(0)
namespace tools
{
namespace mpl = boost::mpl;
template< typename T, size_t N >
struct MemoryBlock
{
T* addr_at(size_t pos) { TOOLS_ASSERT_REL(pos >= 0 && pos < N); return reinterpret_cast<T*>(block_) + pos; }
T const* addr_at(size_t pos) const { TOOLS_ASSERT_REL(pos >= 0 && pos < N); return reinterpret_cast<T*>(block_) + pos; }
template< size_t Pos >
T* addr_at() { BOOST_STATIC_ASSERT( Pos >= 0 && Pos < N ); return reinterpret_cast<T*>(block_) + Pos; }
template< size_t Pos >
T const* addr_at() const { BOOST_STATIC_ASSERT( Pos >= 0 && Pos < N ); return reinterpret_cast<T*>(block_) + Pos; }
private:
char block_[ sizeof(T) * N ];
};
template< typename T, size_t N >
class OnStackInitializableArray : boost::equality_comparable< OnStackInitializableArray<T,N> >
{
BOOST_STATIC_ASSERT(( N > 0 && "YOU CANNOT SPECIFY A NULL ARRAY" )); // concept check
typedef MemoryBlock< T, N > ArrayT;
typedef OnStackInitializableArray MyType;
public:
typedef T value_type;
typedef T* iterator;
typedef T const* const_iterator;
enum { static_size = N };
static size_t size() { return N; }
bool empty() const { return !IsInit(); }
//! default construction of all members, with compilation-time unrolled loop.
// warning: built-in compilator resource limit of template recursion. constated at 491 on gcc4.0.1
void Assign0()
{
if (init_)
Destruct();
mpl::for_each< mpl::range_c<size_t, 0, N> >( InPlaceConstructMetaFctor0(array_) );
init_ = true;
}
//! construction of all members calling a constructor taking one argument of type TypeOfConstructoArgument1 (type self deducted)
template< typename TypeOfConstructoArgument1 >
void Assign1(TypeOfConstructoArgument1 const& value)
{
if (init_)
Destruct();
mpl::for_each< mpl::range_c<size_t, 0, N> >( InPlaceConstructMetaFctor1<TypeOfConstructoArgument1>(array_, value) );
init_ = true;
}
//! boost in place factory version, if you want to use a constructor with more than one argument (up tp 10)
template< typename AutoDeducedFactoryT >
void AssignN(AutoDeducedFactoryT const& inPlaceFactory)
{
if (init_)
Destruct();
mpl::for_each< mpl::range_c<size_t, 0, N> >( InPlaceConstructMetaFctorN<AutoDeducedFactoryT>(array_, inPlaceFactory) );
init_ = true;
}
//! destruct contained objects and switch back to uninitialized state
void Destruct()
{
if (init_)
{
mpl::for_each< mpl::range_c<size_t, 0, N> >( DestructMetaFctor(array_) );
}
init_ = false;
}
bool IsInit() const { return init_; }
// access to members -- compile time index:
template< size_t Pos >
T& get() { AssertIsInit_(); return *array_.template addr_at<Pos>(); }
template< size_t Pos >
T const& get() const { AssertIsInit_(); return *array_.template addr_at<Pos>(); }
// access to members -- runtime index:
T& at(size_t i) { AssertIsInit_(); return *array_.template addr_at(i); }
T const& at(size_t i) const { AssertIsInit_(); return *array_.template addr_at(i); }
// by operator []:
T& operator [] (size_t i) { return at(i); }
T const& operator[] (size_t i) const { return at(i); }
T& front() { AssertIsInit_(); return get<0>(); }
T const& front() const { AssertIsInit_(); return get<0>(); }
T& back() { AssertIsInit_(); return get<N-1>(); }
T const& back() const { AssertIsInit_(); return get<N-1>(); }
// iteration
iterator begin() { AssertIsInit_(); return array_.template addr_at<0>(); }
const_iterator begin() const { AssertIsInit_(); return array_.template addr_at<0>(); }
iterator end() { return array_.template addr_at<N-1>() + 1; }
const_iterator end() const { return array_.template addr_at<N-1>() + 1; }
//
bool operator == (MyType const& rhs) const { /*todo*/ }
MyType& operator = (MyType const& rhs) { /*todo*/ }
// structors:
OnStackInitializableArray() : init_(false) {}
~OnStackInitializableArray() { Destruct(); }
private:
ArrayT array_;
bool init_;
void AssertIsInit_() { TOOLS_ASSERT_REL(IsInit() && "UN-INITIALIZED ACCESS ATTEMPT"); }
// == internal functors repository ==
// functor that will be passed to mpl::for_each
// it will construct-in-place with default constructor.
struct InPlaceConstructMetaFctor0
{
InPlaceConstructMetaFctor0(ArrayT& arrayref) : arrayref_(arrayref) {}
template< typename MplPlacedType > void operator () (MplPlacedType v)
{
new (arrayref_.template addr_at(v)) T(); // default
}
private:
ArrayT& arrayref_;
};
// version for one argument, and that will be all. newt arities of construction will use in place factories from boost.
template< typename CtorArg1 >
struct InPlaceConstructMetaFctor1
{
InPlaceConstructMetaFctor1(ArrayT& arrayref, CtorArg1 const& value) : arrayref_(arrayref), value_(value) {}
template< typename MplPlacedType > void operator () (MplPlacedType)
{
new (arrayref_.template addr_at<MplPlacedType::value>()) T(value_);
}
private:
ArrayT& arrayref_;
CtorArg1 const& value_;
};
// version for any other number of arguments, since they are embedded into the factory
template< typename FactoryT >
struct InPlaceConstructMetaFctorN
{
InPlaceConstructMetaFctorN(ArrayT& arrayref, FactoryT const& factory) : arrayref_(arrayref), factory_(factory) {}
template< typename MplPlacedType > void operator () (MplPlacedType)
{
factory_.template apply<T>(arrayref_.template addr_at<MplPlacedType::value>());
}
private:
ArrayT& arrayref_;
FactoryT const& factory_;
};
// when the class is destructed, we have to call the desctors on our objects if they are initialized.
struct DestructMetaFctor
{
DestructMetaFctor(ArrayT& arrayref) : arrayref_(arrayref) {}
template< typename MplPlacedType > void operator () (MplPlacedType)
{
arrayref_.template addr_at<MplPlacedType::value>()->~T(); // call destructor
}
private:
ArrayT& arrayref_;
};
};
}
#endif //UTILITY_HPP_INC_08_01_2010__252705754_ |
Partager