1 // ==========================================================================
2 // $Source: /var/lib/cvs/Givaro/src/kernel/memory/givaromm.h,v $
3 // Copyright(c)'1994-2009 by The Givaro group
4 // This file is part of Givaro.
5 // Givaro is governed by the CeCILL-B license under French law
6 // and abiding by the rules of distribution of free software.
7 // see the COPYRIGHT file for more details.
8 // Author: T. Gautier
9 // $Id: givaromm.h,v 1.7 2011-02-02 16:23:56 briceboyer Exp $
10 // ==========================================================================
11 
12 /** @file givaromm.h
13  * @ingroup memory
14  * @brief Memory management in Givaro
15  * two memory managers:
16  * - the first one handle a set on free-list of blocs ;
17  * - the second one implement a reference mecanism on the bloc.
18  * .
19  * The latter used method of the former.
20  */
21 #ifndef __GIVARO_mm_H
22 #define __GIVARO_mm_H
23 
24 #include <cstring>            // gcc 4.3
25 #include <stddef.h>           // size_t definition
26 #include <iostream>         // ostream definition
27 #include <new>
28 #include "givaro/givmodule.h"
29 #include "givaro/givbasictype.h"
30 #ifdef GIVARO_DEBUG
31 #include "givaro/giverror.h"
32 #endif
33 
34 #include <givaro/givconfig.h>
35 namespace Givaro {
36 
37     // ==================================================================== //
38 
39     //!  Static informations of memory allocation
40     class GivMMInfo {
41     public:
42         GivMMInfo();
43         ~GivMMInfo();
44         size_t physalloc; // size in bytes of physical allocated bloc
45         size_t logalloc;  // size in bytes of "logical" allocated bloc
46         size_t  sizetab;    // length of next arrays
47         size_t* tabbloc;  // size of all the blocs
48         size_t* tablog;     // number of each logical allocated bloc
49         size_t* tabphy;     // number of each physical allocated bloc
50         std::ostream& print( std::ostream& so ) const;
51     };
52 
53     //! IO
54     inline std::ostream& operator<<( std::ostream& o, const GivMMInfo& T)
55     { return T.print(o); }
56 
57     // --------------------------------------------------------
58     //! Data structure of a bloc.
59     //! Each bloc in TabFree[id] has a data field of size TabSize[id]
60     class BlocFreeList {
61         union header {
62             int index ;             // - index in free list
63             BlocFreeList* nextfree; // - pointer to the next free bloc (of the same size)
64             double dummy; 			// - here to force alignment on data on 8bytes boundary
65         } u;
66         int64_t data[1];
67 
68         // -- Array of list of free bloc
69         static BlocFreeList* TabFree[];
70         static const size_t TabSize[] ;
71         static const int lenTables;
72         static int search_binary( size_t sz ) ;
73 
74         friend class GivMMInfo;
75         friend class GivMMFreeList;
76         friend class GivMMRefCount;
77     };
78 
79 
80     // --------------------------------------------------------
81     //! Implementation of a memory manager with free-lists.
82     //! All members are static methods.
83     class GivMMFreeList {
84     public:
85 
86         // -- Free all internal data structures
87         static void Destroy();
88 
89         // -- Allocation of a new bloc.
90         // These two next functions returns a pointer or 0.
91         // The frequently required bloc is treated in a special version
92         // in order to speed-up the allocation.
93         static BlocFreeList* _allocate (const size_t sz);
allocate(const size_t sz)94         inline static void* allocate (const size_t sz)
95         {
96 #ifdef GIVARO_DEBUG
97             if (sz ==0) return 0 ;
98 #endif
99             size_t index;
100             BlocFreeList* tmp;
101             if ((sz <= 32) && ((tmp=BlocFreeList::TabFree[index =sz-1]) !=0)) {
102                 BlocFreeList::TabFree[index] = tmp->u.nextfree;
103                 tmp->u.index = (int)index;
104 #ifdef GIVARO_STATMEM
105                 tablog[index] ++; logalloc += BlocFreeList::TabSize[index];
106 #endif
107                 return (void*) tmp->data;
108             }
109             tmp = _allocate(sz);
110             return tmp->data ;
111         }
112 
113         // -- Reallocation of a bloc.
114         // The function returns a pointer to the possibly new
115         // bloc. If the bloc must be moved then only oldsize are
116         // recopied.
117         static void* resize (void* p, const size_t oldsize, const size_t newsize);
118 
119         // -- Free the bloc pointed by p and allocated by the manager GivMMFreeList.
120         inline static void desallocate(void* p, const size_t = 0)
121         {
122             if (p==0) return ;
123             BlocFreeList* tmp = reinterpret_cast<BlocFreeList*>(((char*)p) -
124                                                                 (sizeof(BlocFreeList)-sizeof(int64_t)));
125             int index = tmp->u.index;
126 #ifdef GIVARO_DEBUG
127             if ((index <0) || (index >= BlocFreeList::lenTables))
128                 throw GivError("[GivMMFreeList::desallocate]: bad pointer.");
129 #endif
130             tmp->u.nextfree = BlocFreeList::TabFree[index];
131             BlocFreeList::TabFree[index] = tmp;
132         }
133 
134         // -- Recopy size bytes pointed by src into bytes pointer by dest
135         static void memcpy( void* dest, const void* src, const size_t size );
136 
137         // -- Returns some memory usage informations
138         static const GivMMInfo& Usage();
139 
140         //private:
141         // -- bug (on CW10): must comment the private part to initialize next field
142         static GivMMInfo info;
143 
144 #ifdef GIVARO_STATMEM
145         friend class GivMMInfo;
146         friend class GivMMRefCount;
147         static size_t& physalloc;  // total amount of physical allocated bloc
148         static size_t& logalloc;   // total amoun of "logical" allocated bloc
149         static size_t*& tablog;      // number of each logical allocated bloc
150         static size_t*& tabphy;      // number of each physical allocated bloc
151 #endif
152 
153         // -- Initialization module
154     public:
155         static GivModule Module;
156     private:
157         static void Init(int* argc, char***argv);
158         static void End();
159         friend class GivModule;
160     };
161 
162 
163     //! Memory management with reference counter on allocated data.
164     //! The memory manager uses the BlocFreeList data structure
165     //! and stores the refcounter in the field data[0]
166     class GivMMRefCount {
167     public:
168         // -- Allocation of a new bloc of size at least s
allocate(const size_t s)169         inline static void* allocate (const size_t s)
170         {
171 
172 #ifdef GIVARO_DEBUG
173             if (s ==0) return 0 ;
174 #endif
175             int index;
176             BlocFreeList* tmp;
177             size_t sz = s + sizeof(int64_t);
178             if ((sz <= 32) && ((tmp=BlocFreeList::TabFree[index =int(sz-1)]) !=0)) {
179                 BlocFreeList::TabFree[index] = tmp->u.nextfree;
180                 tmp->u.index = index;
181 #ifdef GIVARO_STATMEM
182                 GivMMFreeList::tablog[index] ++; GivMMFreeList::logalloc += BlocFreeList::TabSize[index];
183 #endif
184                 tmp->data[0] = 1 ;
185                 return (void*) &(tmp->data[1]);
186             }
187             tmp = GivMMFreeList::_allocate(sz);
188             tmp->data[0] = 1 ;
189 
190 
191             return (void*) &(tmp->data[1]);
192         }
193 
194         // -- Reallocation of a bloc. See description in GivMMFreeList's class.
195         // Here, if ref count on p is >1 then a new bloc is allocated.
196         static void* resize (void* p, const size_t oldsize, const size_t newsize);
197 
198         // -- Free the bloc allocated by the manager GivMMRefCount.
199         inline static void desallocate(void* p, const size_t = 0)
200         {
201             if (p==0) return ;
202             BlocFreeList* tmp = reinterpret_cast<BlocFreeList*>((char *) p - sizeof(BlocFreeList) ) ;
203             if ( --(tmp->data[0]) ==0) {
204                 int index = tmp->u.index;
205 #ifdef GIVARO_DEBUG
206                 if ((index <0) || (index >= BlocFreeList::lenTables))
207                     GivError::throw_error(GivError("[GivMMRefCount::desallocate]: bad pointer."));
208 #endif
209 #ifdef GIVARO_JGD
210                 if ((index <0) || (index >= BlocFreeList::lenTables))
211                     cerr << "[GivMMRefCount::desallocate]: bad pointer with index " << index << ", doing nothing ..." << endl;
212                 else {
213 #endif
214                     tmp->u.nextfree = BlocFreeList::TabFree[index];
215                     BlocFreeList::TabFree[index] = tmp;
216 #ifdef GIVARO_JGD
217                 }
218 #endif
219             }
220         }
221 
222         // -- Assignement of pointer:
assign(void ** dest,void * src)223         inline static void* assign (void** dest, void*src)
224         {
225             if (src == *dest) return *dest ;
226             if (*dest !=0) GivMMRefCount::desallocate( *dest );
227             if (src ==0) return *dest=src;
228             BlocFreeList* s = reinterpret_cast<BlocFreeList*>(((char*)src) - sizeof(BlocFreeList));
229 #ifdef GIVARO_DEBUG
230             if ((s->u.index <0) || (s->u.index >= BlocFreeList::lenTables))
231                 GivError::throw_error(GivError("[GivMMRefCount::assign]: bad pointer 'src'."));
232 #endif
233             ++(s->data[0]);
234             return *dest = src ;
235         }
236 
237         // -- Increment, decrement and getvalue of the refcount.
238         // Returns the value after increment/decrment.
incrc(void * p)239         inline static int incrc(void* p)
240         {
241             if (p ==0) return 0;
242             BlocFreeList* bp = reinterpret_cast<BlocFreeList*>(((char*)p) - sizeof(BlocFreeList));
243 #ifdef GIVARO_DEBUG
244             if ((bp->u.index <0) || (bp->u.index >= BlocFreeList::lenTables))
245                 throw GivError("[GivMMRefCount::incrc]: bad pointer.");
246 #endif
247             return int(++(bp->data[0]));
248         }
decrc(void * p)249         inline static int decrc(void* p)
250         {
251             if (p ==0) return 0;
252             BlocFreeList* bp = reinterpret_cast<BlocFreeList*>(((char*)p) - sizeof(BlocFreeList));
253 #ifdef GIVARO_DEBUG
254             if ((bp->u.index <0) || (bp->u.index >= BlocFreeList::lenTables))
255                 throw GivError("[GivMMRefCount::incrc]: bad pointer.");
256 #endif
257             return int(--(bp->data[0]));
258         }
getrc(void * p)259         inline static int getrc(void* p)
260         {
261             if (p ==0) return 0;
262             BlocFreeList* bp = reinterpret_cast<BlocFreeList*>(((char*)p) - sizeof(BlocFreeList));
263 #ifdef GIVARO_DEBUG
264             if ((bp->u.index <0) || (bp->u.index >= BlocFreeList::lenTables))
265                 throw GivError("[GivMMRefCount::incrc]: bad pointer.");
266 #endif
267             return int(bp->data[0]);
268         }
269     };
270 
271 
272     //! Memory manager that allocates array of object of type T for
273     template<class T>
274     class GivaroMM {
275     public:
276         typedef T* ptT;
277         // -- Allocation of a new bloc contains s unintialized elements
278         static T* allocate (const size_t s);
279         // -- Desallocation of bloc
280         static void desallocate ( T* bloc, const size_t sz =0 );
281         // -- Initialize each element pointed by bloc with value V
282         static void initone( T*p, const T& V = T());
283         static void initialize(T* bloc, const size_t s, const T& V =T());
284         // -- Call destructor on each elements pointed by bloc
285         static void destroy(T* bloc, const size_t s);
286     };
287 
288 
289     //! @bug implem does not belong here
290     //@{
291     template<class T>
allocate(const size_t s)292     inline T* GivaroMM<T>::allocate (const size_t s)
293     { return (T*)GivMMFreeList::allocate(s*sizeof(T)); }
294     template<class T>
desallocate(T * bloc,const size_t sz)295     inline void GivaroMM<T>::desallocate(T* bloc, const size_t sz)
296     { GivMMFreeList::desallocate((void*)bloc,sz); }
297     template<class T>
initone(T * p,const T & V)298     inline void GivaroMM<T>::initone( T* p, const T& V)
299     { new (p) T(V); }
300     template<class T>
initialize(T * bloc,const size_t s,const T & V)301     inline void GivaroMM<T>::initialize(T* bloc, const size_t s, const T& V)
302     { for (size_t i=0; i<s; i++) GivaroMM<T>::initone(&(bloc[i]), V); }
303     template<class T>
destroy(T * bloc,const size_t s)304     inline void GivaroMM<T>::destroy(T* bloc, const size_t s)
305     { for (size_t i=0; i<s; i++) bloc[i].~T(); }
306     //@}
307 
308     // -- specialized version: for basic C++ type and pointer on this type
309 #define GIVARO_MM_SPECIALIZED(TYPE) \
310     template<> class GivaroMM<TYPE> {\
311     public: \
312             typedef TYPE* ptType;\
313         typedef TYPE Type;\
314         static ptType allocate (const size_t s);\
315         static void desallocate ( ptType bloc, const size_t sz =0 );\
316         static void initone( ptType p, const Type V = 0);\
317         static void initialize(ptType bloc, const size_t s, const Type V =0);\
318         static void destroy(GivaroMM<TYPE>::ptType bloc, const size_t s);\
319     };\
320     inline GivaroMM<TYPE>::ptType GivaroMM<TYPE>::allocate (const size_t s)\
321     { return (GivaroMM<TYPE>::ptType)GivMMFreeList::allocate(s*sizeof(GivaroMM<TYPE>::Type)); }\
322     inline void GivaroMM<TYPE>::desallocate(GivaroMM<TYPE>::ptType bloc, const size_t sz)\
323     { GivMMFreeList::desallocate((void*)bloc,sz); }\
324     inline void GivaroMM<TYPE>::initone( GivaroMM<TYPE>::ptType p, const GivaroMM<TYPE>::Type v) \
325     { *p = v; }\
326     inline void GivaroMM<TYPE>::initialize(GivaroMM<TYPE>::ptType bloc, const size_t s, const GivaroMM<TYPE>::Type V)\
327     { for (size_t i=0; i<s; i++) bloc[i] = V; }\
328     inline void GivaroMM<TYPE>::destroy(GivaroMM<TYPE>::ptType bloc, const size_t s){}
329 
330 #if 0
331     GIVARO_MM_SPECIALIZED(char)
332     GIVARO_MM_SPECIALIZED(short)
333     GIVARO_MM_SPECIALIZED(int)
334     GIVARO_MM_SPECIALIZED(long)
335     GIVARO_MM_SPECIALIZED(float)
336     GIVARO_MM_SPECIALIZED(double)
337 
338     GIVARO_MM_SPECIALIZED(unsigned char)
339     GIVARO_MM_SPECIALIZED(unsigned short)
340     GIVARO_MM_SPECIALIZED(unsigned int)
341     GIVARO_MM_SPECIALIZED(unsigned long)
342 
343     GIVARO_MM_SPECIALIZED(char*)
344     GIVARO_MM_SPECIALIZED(short*)
345     GIVARO_MM_SPECIALIZED(int*)
346     GIVARO_MM_SPECIALIZED(long*)
347     GIVARO_MM_SPECIALIZED(float*)
348     GIVARO_MM_SPECIALIZED(double*)
349 
350     GIVARO_MM_SPECIALIZED(unsigned char*)
351     GIVARO_MM_SPECIALIZED(unsigned short*)
352     GIVARO_MM_SPECIALIZED(unsigned int*)
353     GIVARO_MM_SPECIALIZED(unsigned long*)
354 #endif
355 
356 } // namespace Givaro
357 
358 #endif // __GIVARO_mm_H
359 
360 /* -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
361 // vim:sts=4:sw=4:ts=4:et:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s
362