Bonjour aux curieux

vala j'ai programmé ca au boulot pour un certain besoin.
Je vous prierai de respecter le code copyrighté pour le moment. (pas discuté avec le patron mais je sais qu'il ne serait pas contre une publication vu la généricité de l'outil, donc je me permet)

c'est plus pour discuter de son utilité de toute façon.

c'est comme boost::array, mais avec des élements non initialisés dans un premier temps, que l'on peut initialiser a tout moment.

ceci pour éviter les trucs du genre:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
boost::optional< boost::array< T, N > > myArray_;
car T doit être default-constructible !! pas bon.
car je n'aime pas les types a moitiés construits.
quel interet d'avoir un array optionel si ce qui est dedans est "optionel" aussi ?

sinon il y aurait toujours:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
boost::array< boost::scoped_ptr<T>, N > myArray_;
pas bon non plus car utilise le heap, plus lent, et plus fragmenté !

sinon l'inverse du début:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
boost::array< boost::optional< T >, N > myArray_;
j'étais content avec ca, mais les optionels stockent un bool pour connaître l'état de l'initialisation. Avec l'alignement cela donne un sizeof de 8 pour T=int !

faute de trouver mieux, j'ai mis les mains dedans.
voila ce que j'ai sorti:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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_
exemple d'utilisation:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
 
class VeryRestricted
{
    VeryRestricted() {}
    VeryRestricted(VeryRestricted const&) {}
    VeryRestricted& operator = (VeryRestricted const& rhs) {}
public:
    VeryRestricted(std::string myName) : n_(myName) {}
    std::string n_;
};
 
int main(int, char**)
{
    typedef tools::OnStackInitializableArray< VeryRestricted, 2 >
        VRArrayT;
    VRArrayT vrArray;   
    vrArray.Assign1("youpi");  // both 2 members are init to youpi
    vrArray.get<1>().n_ = "toto";
    VRArrayT::const_iterator it = vrArray.begin();
    while (it != vrArray.end())
    {
        std::cout << it->n_ << std::endl;
        ++it;
    }
}
voilà qui affiche donc youpi et toto dans la console.

les fonctionnalités:

  • assignation a tous les membres déroulée à la compilation
  • tout sur la pile
  • presque compatible conteurs STL (a peu pres comme boost::array)
  • ne fait jamais de copies d'objets temporaires inutile (in place factory pour les constructeurs a plusieurs paramètres)
  • permet au compilateur d'optimiser les accès aux cellules avec index constant.
  • aucun requirements sur le type T


désavantages:

  • la pile est assez limitée dans un programme usuellement.
  • limité à N=491 sur le Mac du boulot, un ti peu plus sur gcc4.4 mais pas loin, et déjà 15 secondes de compilation sur mon portable.
  • pas très propre avec les Assign0,1,N (boost.preprocessor?)
  • il manque la possibilité de construire chaque cellule avec des paramètres de construction différents. (vivement C++0x et les variadics)


vos avis ?