root/branches/newmole/source/container_classes.h

Revision 2542, 57.1 kB (checked in by rjrw, 3 weeks ago)

Merged from trunk r2448:2541

  • Property svn:eol-style set to native
Line 
1/* This file is part of Cloudy and is copyright (C)1978-2008 by Gary J. Ferland and
2 * others.  For conditions of distribution and use see copyright notice in license.txt */
3
4#ifndef _CONTAINER_CLASSES_H_
5#define _CONTAINER_CLASSES_H_
6
7void do_dump_state(const void* buf, size_t nelem, size_t size, FILE* out, int32 magic);
8void do_restore_state(void* buf, size_t nelem, size_t size, FILE *in, int32 magic);
9
10//! define the supported memory layouts of multi_arr / flex_arr
11//!
12//! ARPA_TYPE: arrays of pointers to arrays to ...
13//! C_TYPE: row-major order, exactly as used in C (last index runs fastest)
14//! FLX_TYPE: the one and only layout used by flex_arr
15typedef enum { ARPA_TYPE, C_TYPE, FLX_TYPE, ML_TOP } mem_layout;
16
17// magic numbers to identify each memory layout
18static const int32 MA_VERS[ML_TOP] = { 120070905, 220070803, 320071126 };
19
20#ifdef USE_C_TYPE
21#define MEM_LAYOUT_VAL C_TYPE
22#else
23#define MEM_LAYOUT_VAL ARPA_TYPE
24#endif
25
26#ifdef BOUNDS_CHECK
27#define lgBOUNDSCHECKVAL true
28#else
29#define lgBOUNDSCHECKVAL false
30#endif
31
32//! basic_pntr - base class for generalization of normal pointers that enables bounds checking
33//! it comes with the full set of operators that you would expect for a random access pointer
34template<class T, bool lgBC>
35class basic_pntr
36{
37        static const int p_nd = lgBC ? 3 : 1;
38        T* p_p[p_nd]; // p[0] current pointer, p[1] lower bound, p[2] upper bound
39
40        T* p_index_checked ( const ptrdiff_t n ) const
41        {
42                T* t = p_p[0]+n;
43#ifdef _MSC_VER
44                /* disable warning that conditional expression is constant, true or false in if */
45#               pragma warning( disable : 4127 )
46#endif
47                if( lgBC )
48                {
49                        if( t < p_p[1] || t >= p_p[2] )
50                                OUT_OF_RANGE( "basic_pntr::p_index_checked()" );
51                }
52                return t;
53        }
54        void p_set_vals( T* p0, T* p1, T* p2 )
55        {
56#ifdef _MSC_VER
57                /* disable warning that conditional expression is constant, true or false in if */
58#               pragma warning( disable : 4127 )
59#endif
60                if( lgBC )
61                {
62                        p_p[0] = p0; p_p[1] = p1; p_p[2] = p2;
63                }
64                else
65                        p_p[0] = p0;
66        }
67public:
68        typedef random_access_iterator_tag iterator_category;
69        typedef T            value_type;
70        typedef T&           reference;
71        typedef const T&     const_reference;
72        typedef T*           pointer;
73        typedef const T*     const_pointer;
74        typedef size_t       size_type;
75        typedef ptrdiff_t    difference_type;
76
77        // constructors
78        basic_pntr( T* p0, T* p1, T* p2 )
79        {
80                p_set_vals( p0, p1, p2 );
81        }
82        basic_pntr( T* p0 )
83        {
84                p_set_vals( p0, NULL, NULL );
85        }
86        basic_pntr()
87        {
88                p_set_vals( NULL, NULL, NULL );
89        }
90        basic_pntr( const basic_pntr& t )
91        {
92                *this = t;
93        }
94        // protected destructor (to prevent direct instantiation or destruction via basic_pntr*, see Alexandrescu p13)
95protected:
96        ~basic_pntr() {}
97public:
98        // pre-increment
99        basic_pntr& operator++ ()
100        {
101                ++p_p[0];
102                return *this;
103        }
104        // pre-decrement
105        basic_pntr& operator-- ()
106        {
107                --p_p[0];
108                return *this;
109        }
110        // define operators for += and -=, normal arithmetic is defined separately in
111        // the derived classes; it cannot be done here since they would require implicit
112        // conversion from basic_pntr -> pntr or const_pntr to work; this would also create
113        // an implicit and silent conversion from const_pntr -> pntr, which is illegal...
114        basic_pntr& operator+= ( const ptrdiff_t n ) { p_p[0] += n; return *this; }
115        basic_pntr& operator-= ( const ptrdiff_t n ) { p_p[0] -= n; return *this; }
116        // dereference
117        T& operator* () const
118        {
119                return *(p_index_checked(0));
120        }
121        T* operator-> () const
122        {
123                return p_index_checked(0);
124        }
125        T& operator[] ( const ptrdiff_t n ) const
126        {
127                return *(p_index_checked(n));
128        }
129        // finally, define the boolean operators...
130        bool operator== ( const basic_pntr& t ) const { return p_p[0] == t.p_p[0]; }
131        bool operator!= ( const basic_pntr& t ) const { return p_p[0] != t.p_p[0]; }
132        bool operator<  ( const basic_pntr& t ) const { return p_p[0] <  t.p_p[0]; }
133        bool operator<= ( const basic_pntr& t ) const { return p_p[0] <= t.p_p[0]; }
134        bool operator>  ( const basic_pntr& t ) const { return p_p[0] >  t.p_p[0]; }
135        bool operator>= ( const basic_pntr& t ) const { return p_p[0] >= t.p_p[0]; }
136};
137
138#ifdef __SUNPRO_CC
139// these beauties are needed by the Rogue Wave implementation of STL algorithms used by the
140// Sun Studio compiler, otherwise their STL algorithms won't compile with pntr or const_pntr
141namespace std
142{
143        template<class T, bool lgBC>
144        inline T* __value_type(const basic_pntr<T,lgBC>&)
145        {
146                return static_cast<T*>( NULL );
147        }
148
149        template<class T, bool lgBC>
150        inline typename basic_pntr<T,lgBC>::difference_type* __distance_type(const basic_pntr<T,lgBC>&)
151        {
152                return static_cast<basic_pntr<T,lgBC>::difference_type*>( NULL );
153        }
154}
155#endif
156
157//! pntr - interface class to replace normal pointers
158template<class T, bool lgBC>
159class pntr : public basic_pntr<T,lgBC>
160{
161public:
162        // constructors are not inherited, so define them again
163        pntr( T* p0 ) : basic_pntr<T,lgBC>( p0 ) {}
164        pntr( T* p0, T* p1, T* p2 ) : basic_pntr<T,lgBC>( p0, p1, p2 ) {}
165        pntr() {}
166        // the increment / decrement operators need to be recast...
167        // otherwise expressions like p = ++q would be illegal for iterators...
168        pntr& operator++ () { return static_cast<pntr&>(basic_pntr<T,lgBC>::operator++()); }
169        const pntr operator++ (int) { pntr t = *this; ++(*this); return t; }
170        pntr& operator-- () { return static_cast<pntr&>(basic_pntr<T,lgBC>::operator--()); }
171        const pntr operator-- (int) { pntr t = *this; --(*this); return t; }
172        // define p+n, p-n, p-q
173        const pntr operator+ ( const ptrdiff_t n ) const { pntr s = *this; s += n; return s; }
174        const pntr operator- ( const ptrdiff_t n ) const { pntr s = *this; s -= n; return s; }
175        ptrdiff_t operator- ( const pntr& t ) const { return &(*this[0]) - &t[0]; }
176};
177
178// this defines n+p
179template<class T, bool lgBC>
180inline const pntr<T,lgBC> operator+ ( const ptrdiff_t n, const pntr<T,lgBC>& t )
181{
182        pntr<T,lgBC> s = t;
183        s += n;
184        return s;
185}
186
187//! const_pntr - same as pntr, except that it replaces const pointers rather than normal pointers
188template<class T, bool lgBC>
189class const_pntr : public basic_pntr<T,lgBC>
190{
191public:
192        // constructors are not inherited, so define them again
193        const_pntr( T* p0 ) : basic_pntr<T,lgBC>( p0 ) {}
194        const_pntr( T* p0, T* p1, T* p2 ) : basic_pntr<T,lgBC>( p0, p1, p2 ) {}
195        const_pntr() {}
196        // make sure we can assign a pntr to a const_pntr by creating an implicit conversion to const_pntr
197        const_pntr( const pntr<T,lgBC>& t ) : basic_pntr<T,lgBC>( t ) {}
198        // the increment / decrement operators need to be recast...
199        // otherwise expressions like *p++ = 1. would be legal for const_iterators...
200        const_pntr& operator++ () { return static_cast<const_pntr&>(basic_pntr<T,lgBC>::operator++()); }
201        const const_pntr operator++ (int) { const_pntr t = *this; ++(*this); return t; }
202        const_pntr& operator-- () { return static_cast<const_pntr&>(basic_pntr<T,lgBC>::operator--()); }
203        const const_pntr operator-- (int) { const_pntr t = *this; --(*this); return t; }
204        const_pntr& operator+= ( const ptrdiff_t n )
205        {
206                return static_cast<const_pntr&>(basic_pntr<T,lgBC>::operator+=(n));
207        }
208        const_pntr& operator-= ( const ptrdiff_t n )
209        {
210                return static_cast<const_pntr&>(basic_pntr<T,lgBC>::operator-=(n));
211        }
212        // the dereference operators need to be recast...
213        const T& operator* () const { return static_cast<const T&>(basic_pntr<T,lgBC>::operator*()); }
214        const T* operator-> () const { return static_cast<const T*>(basic_pntr<T,lgBC>::operator->()); }
215        const T& operator[] ( const ptrdiff_t n ) const
216        {
217                return static_cast<const T&>(basic_pntr<T,lgBC>::operator[](n));
218        }
219        // define p+n, p-n, p-q
220        const const_pntr operator+ ( const ptrdiff_t n ) const { const_pntr s = *this; s += n; return s; }
221        const const_pntr operator- ( const ptrdiff_t n ) const { const_pntr s = *this; s -= n; return s; }
222        ptrdiff_t operator- ( const const_pntr& t ) const { return &(*this[0]) - &t[0]; }
223};
224
225// this defines n+p
226template<class T, bool lgBC>
227inline const const_pntr<T,lgBC> operator+ ( const ptrdiff_t n, const const_pntr<T,lgBC>& t )
228{
229        const_pntr<T,lgBC> s = t;
230        s += n;
231        return s;
232}
233
234//! tree_vec - a simple class to store the bounds checking information for multi_arr
235struct tree_vec
236{
237        typedef size_t size_type;
238
239        size_type n;
240        tree_vec *d;
241
242private:
243        void p_clear0()
244        {
245                if( d != NULL )
246                {
247                        for( size_type i = 0; i < n; ++i )
248                                d[i].clear();
249                        delete[] d;
250                }
251        }
252        void p_clear1()
253        {
254                n = 0;
255                d = NULL;
256        }
257
258public:
259        tree_vec()
260        {
261                p_clear1();
262        }
263        ~tree_vec()
264        {
265                p_clear0();
266        }
267        void clear()
268        {
269                p_clear0();
270                p_clear1();
271        }
272        const tree_vec& operator= ( const tree_vec& m )
273        {
274                if( &m != this )
275                {
276                        clear();
277                        n = m.n;
278                        if( m.d != NULL )
279                        {
280                                d = new tree_vec[n];
281                                tree_vec *p = d;
282                                const tree_vec *mp = m.d;
283                                for( size_type i = 0; i < n; ++i )
284                                        *p++ = *mp++;
285                        }
286                }
287                return *this;
288        }
289        tree_vec& getvec(const size_type i, const size_type index[])
290        {
291                if( i == 0 )
292                        return *this;
293                else
294                        return getvec(i-1,index).d[index[i-1]];
295        }
296        const tree_vec& getvec(const size_type i, const size_type index[]) const
297        {
298                if( i == 0 )
299                        return *this;
300                else
301                        return getvec(i-1,index).d[index[i-1]];
302        }
303};
304
305//! multi_geom - this class maintains all the geometry information for multi_arr
306//! keeping it separate makes it easy to clone the information from one multi_arr to another
307template<int d,mem_layout ALLOC=MEM_LAYOUT_VAL>
308class multi_geom
309{
310public:
311        typedef size_t size_type;
312
313        tree_vec v;
314
315        size_type size;  //! allocated size (number of data elements, pointers are not counted)
316        size_type s[d];  //! size of each dimension (only used in C_TYPE layout)
317        size_type st[d]; //! stride for each dimension (only used in C_TYPE layout)
318        size_type nsl[d];//! sizes of each of the pointer arrays
319
320private:
321        void p_clear0()
322        {
323                v.clear();
324        }
325        void p_clear1()
326        {
327                size = 0;
328                for( int i=0; i < d; ++i )
329                {
330                        s[i] = 0;
331                        st[i] = 0;
332                        nsl[i] = 0;
333                }
334        }
335
336public:
337        multi_geom()
338        {
339                p_clear1();
340        }
341        ~multi_geom()
342        {
343                p_clear0();
344        }
345        void clear()
346        {
347                p_clear0();
348                p_clear1();
349        }
350        const multi_geom& operator= ( const multi_geom& m )
351        {
352                if( &m != this )
353                {
354                        clear();
355                        v = m.v;
356                        size = m.size;
357                        for( int i=0; i < d; ++i )
358                        {
359                                s[i] = m.s[i];
360                                st[i] = m.st[i];
361                                nsl[i] = m.nsl[i];
362                        }
363                }
364                return *this;
365        }
366        bool lgInbounds(const size_type n, const size_type index[]) const
367        {
368                if( n != 0 )
369                        return ( lgInbounds(n-1,index) && index[n-1] < v.getvec(n-1,index).n );
370                else
371                        return true;
372        }
373        void reserve(const size_type n, const size_type index[])
374        {
375                ASSERT( n <= d && index[n-1] > 0 && lgInbounds( n-1, index ) );
376
377                tree_vec& w = v.getvec( n-1, index );
378                if( d > n )
379                {
380                        ASSERT( w.d == NULL );
381                        w.d = new tree_vec[ index[n-1] ];
382                }
383                w.n = index[n-1];
384                s[n-1] = max(s[n-1],index[n-1]);
385                nsl[n-1] += index[n-1];
386        }
387        void reserve_recursive(const size_type n, size_type index[])
388        {
389                if( n == 0 )
390                {
391                        reserve( n+1, index );
392                        if( n+1 < d )
393                                reserve_recursive( n+1, index );
394                }
395                else
396                {
397                        size_type top = index[n-1];
398                        for( size_type i=0; i < top; ++i )
399                        {
400                                index[n-1] = i;
401                                reserve( n+1, index );
402                                if( n+1 < d )
403                                        reserve_recursive( n+1, index );
404                        }
405                        index[n-1] = top;
406                }
407        }
408        void finalize(void)
409        {
410#ifdef _MSC_VER
411                /* disable warning that conditional expression is constant, true or false in if */
412#       pragma warning( disable : 4127 )
413#endif
414
415                STATIC_ASSERT ( ALLOC == C_TYPE || ALLOC == ARPA_TYPE );
416
417                if( ALLOC == ARPA_TYPE )
418                {
419                        size_type n1[d], n2[d];
420                        for( int dim=0; dim < d; ++dim )
421                                n1[dim] = n2[dim] = 0L;
422                        // sanity checks
423                        p_setupArray( n1, n2, &v, 0 );
424                        for( int dim=0; dim < d-1; ++dim )
425                                ASSERT( n1[dim] == nsl[dim] && n2[dim] == nsl[dim+1] );
426                        size = nsl[d-1];
427                }
428                else if( ALLOC == C_TYPE )
429                {
430                        st[d-1] = s[d-1];
431                        for( int i = d-2; i >= 0; --i )
432                                st[i] = st[i+1]*s[i];
433                        size = st[0];
434                }
435                else
436                {
437                        TotalInsanity();
438                }
439        }
440
441private:
442        void p_setupArray( size_type n1[], size_type n2[], const tree_vec* w, int l )
443        {
444                for( size_type i=0; i < w->n; ++i )
445                {
446                        n1[l]++;
447                        if( l < d-2 )
448                        {
449                                p_setupArray( n1, n2, &w->d[i], l+1 );
450                        }
451                        n2[l] += w->d[i].n;
452                }
453        }
454};
455
456
457//
458//! The n_pointer and const_n_pointer classes below define indexing into the multi_arr
459//!
460//! NB NB -- The design of these classes is CRUCIAL for CPU performance! Any redesign
461//!          should be thoroughly tested for CPU time regressions on a broad range of
462//!          platforms and compilers!
463//!
464//! The primary goal of the design of these classes should be to make life as easy as
465//! possible for the compiler, NOT the programmer! The design should assure that that
466//! the methods are FULLY INLINED. Without that the resulting code will be severely
467//! crippled!
468//!
469//! Below are a total of 8 specializations for each of these classes. These could be
470//! combined into 2 specialization for each class (one for N > 1 and one for N == 1),
471//! but it turns out that the resulting method is too complicated for most compilers
472//! to inline. Hence we decided to split the methods up into simpler specializations.
473//! As they are written below, nearly every compiler can inline them (at least for the
474//! non-bounds_checking versions)...
475//!
476//! This is the situation on 2008 jan 26:
477//!
478//! Linux IA32/AMD64   ARPA    C    ARPA/BC  C/BC
479//!    g++ 4.3.x        OK     OK     OK      OK   (tested on prerelease)
480//!    g++ 4.2.x        OK     OK     OK      OK
481//!    g++ 4.1.x        OK     OK     OK      OK
482//!    g++ 4.0.x        OK     OK     OK      OK
483//!    g++ 3.4.x        ??     OK     ??      ??
484//!    g++ 3.3.x        ??     OK     ??      ??
485//!
486//!    icc 10.1         OK     OK     OK      OK
487//!    icc 10.0         OK     OK     OK      OK
488//!    icc  9.1         OK     OK     OK      OK
489//!    icc  9.0         OK     OK     OK      OK
490//!
491//!    Sun Studio 12    OK     OK     OK      OK
492//!
493//!    Pathscale 2.3.1  OK     OK     --      --   (only tested on AMD64)
494//!
495//!    Portland 6.1-5   --     --     --      --   (only tested on IA32)
496//!
497//! Linux IA64
498//!    g++ 4.2.x        OK     OK     OK      OK
499//!    g++ 3.3.x        ??     OK?    ??      ??
500//!
501//!    icc 10.1         OK     OK     --      --
502//!    icc 10.0         OK     OK     --      --
503//!    icc  9.1         OK     OK     --      --
504//!    icc  9.0         OK     OK     OK      OK
505//!    icc  8.1         OK     OK     OK      OK
506//!
507//! Windows IA32
508//!    Visual Studio 8  OK     OK     --      --
509//!    icl 10.1         OK     OK     --      --
510//!
511//! Solaris Ultrasparc
512//!    g++ 4.3.x        OK     OK     OK      OK   (tested on prerelease)
513//!    g++ 4.2.x        OK     OK     OK      OK
514//!    g++ 4.1.x        OK     OK     OK      OK
515//!    g++ 4.0.x        OK     OK     OK      OK
516//!    g++ 3.4.x        ??     ??     ??      ??
517//!    g++ 3.3.x        ??     ??     ??      ??
518//!
519//!    Sun Studio 12    OK     OK     OK      OK
520//!
521//! Notes:
522//!   - The tests were carried out on the following simple test code:
523//!
524//!       long test(multi_arr<long,6>& arr)
525//!       {
526//!         return arr[2][3][4][5][6][7];
527//!       }
528//!
529//!     The tests were done both on ARPA_TYPE and C_TYPE arrays, with and without
530//!     bounds-checking enabled (BC indicates bounds-checking enabled). The resulting
531//!     (optimized) assembly was inspected by eye.
532//!
533//!   - "OK" indicates that all methods were inlined and the resulting assembly looked
534//!     optimal; "??" indicates that all methods were inlined, but the assembly looked
535//!     sub-optimal (i.e. not all overhead was optimized away); "--" indicates that at
536//!     least some of the methods were not inlined at all.
537//!
538//! Indexing a multi_arr works as follows. When the compiler encounters arr[i][j][k],
539//! it will first emit a to call multi_arr::operator[] with i as its argument; this
540//! operator will construct a temporary n_pointer as follows
541//!
542//!     arr[i]  -->  n_pointer<T,3>(*p,st[],*v)::operator[](i) -> n_pointer<T,2>
543//!
544//! here p is the base pointer to the data, st contains the strides of a C_TYPE array
545//! (which are not used in ARPA_TYPE arrays) and v points to the tree_vec with the
546//! bounds-checking information. The operator[] of the n_pointer will update p and v
547//! using the value of i. This will only take care of the first index. At this stage
548//! the compiler still needs to emit code for the remainder: n_pointer<T,2>[j][k].
549//! The operator[] of the n_pointer<T,2> will take care of the next index:
550//!
551//!     n_pointer<T,2>::operator[](j)  -->  n_pointer<T,1>
552//!
553//! So another temporary n_pointer is emitted, and p and v are updated again by the
554//! operator[] using j. Now the compiler still needs to emit code for: n_pointer<T,1>[k];
555//! n_pointer<T,1> is special since it will absorb the last index, so it should not
556//! return yet another n_pointer but a (const) reference to the data item itself:
557//!
558//!     n_pointer<T,1>::operator[](k)  -->  T& *(p + k)
559//!     const_n_pointer<T,1>::operator[](k)  -->  const T& *(p + k)
560//
561
562
563// forward definitions
564template<class T, int N, mem_layout ALLOC, bool lgBC> class n_pointer;
565template<class T, int N, mem_layout ALLOC, bool lgBC> class const_n_pointer;
566
567template<class T, int N>
568class n_pointer<T,N,ARPA_TYPE,false>
569{
570        T* p_p;
571        const size_t* p_st;
572        const tree_vec* p_v;
573public:
574        n_pointer(T* p, const size_t* st=NULL, const tree_vec* v=NULL) : p_p(p), p_st(st), p_v(v) {}
575        const n_pointer<T,N-1,ARPA_TYPE,false> operator[] (const size_t i) const
576        {
577                return n_pointer<T,N-1,ARPA_TYPE,false>( *((T**)p_p+i) );
578        }
579};
580
581template<class T, int N>
582class n_pointer<T,N,C_TYPE,false>
583{
584        T* p_p;
585        const size_t* p_st;
586        const tree_vec* p_v;
587public:
588        n_pointer(T* p, const size_t* st, const tree_vec* v=NULL) : p_p(p), p_st(st), p_v(v) {}
589        const n_pointer<T,N-1,C_TYPE,false> operator[] (const size_t i) const
590        {
591                return n_pointer<T,N-1,C_TYPE,false>( p_p+i*p_st[0], p_st+1 );
592        }
593};
594
595template<class T>
596class n_pointer<T,1,ARPA_TYPE,false>
597{
598        T* p_p;
599        const size_t* p_st;
600        const tree_vec* p_v;
601public:
602        n_pointer(T* p, const size_t* st=NULL, const tree_vec* v=NULL) : p_p(p), p_st(st), p_v(v) {}
603        T& operator[] (const size_t i) const
604        {
605                return *(p_p + i);
606        }
607};
608
609template<class T>
610class n_pointer<T,1,C_TYPE,false>
611{
612        T* p_p;
613        const size_t* p_st;
614        const tree_vec* p_v;
615public:
616        n_pointer(T* p, const size_t* st, const tree_vec* v=NULL) : p_p(p), p_st(st), p_v(v) {}
617        T& operator[] (const size_t i) const
618        {
619                return *(p_p + i);
620        }
621};
622
623template<class T, int N>
624class n_pointer<T,N,ARPA_TYPE,true>
625{
626        T* p_p;
627        const size_t* p_st;
628        const tree_vec* p_v;
629public:
630        n_pointer(T* p, const size_t* st, const tree_vec* v) : p_p(p), p_st(st), p_v(v) {}
631        const n_pointer<T,N-1,ARPA_TYPE,true> operator[] (const size_t i) const
632        {
633                if( i >= p_v->n )
634                        OUT_OF_RANGE( "n_pointer::operator[]" );
635                return n_pointer<T,N-1,ARPA_TYPE,true>( *((T**)p_p+i), NULL, &p_v->d[i] );
636        }
637};
638
639template<class T, int N>
640class n_pointer<T,N,C_TYPE,true>
641{
642        T* p_p;
643        const size_t* p_st;
644        const tree_vec* p_v;
645public:
646        n_pointer(T* p, const size_t* st, const tree_vec* v) : p_p(p), p_st(st), p_v(v) {}
647        const n_pointer<T,N-1,C_TYPE,true> operator[] (const size_t i) const
648        {
649                if( i >= p_v->n )
650                        OUT_OF_RANGE( "n_pointer::operator[]" );
651                return n_pointer<T,N-1,C_TYPE,true>( p_p+i*p_st[0], p_st+1, &p_v->d[i] );
652        }
653};
654
655template<class T>
656class n_pointer<T,1,ARPA_TYPE,true>
657{
658        T* p_p;
659        const size_t* p_st;
660        const tree_vec* p_v;
661public:
662        n_pointer(T* p, const size_t* st, const tree_vec* v) : p_p(p), p_st(st), p_v(v) {}
663        T& operator[] (const size_t i) const
664        {
665                if( i >= p_v->n )
666                        OUT_OF_RANGE( "n_pointer::operator[]" );
667                return *(p_p + i);
668        }
669};
670
671template<class T>
672class n_pointer<T,1,C_TYPE,true>
673{
674        T* p_p;
675        const size_t* p_st;
676        const tree_vec* p_v;
677public:
678        n_pointer(T* p, const size_t* st, const tree_vec* v) : p_p(p), p_st(st), p_v(v) {}
679        T& operator[] (const size_t i) const
680        {
681                if( i >= p_v->n )
682                        OUT_OF_RANGE( "n_pointer::operator[]" );
683                return *(p_p + i);
684        }
685};
686
687template<class T, int N>
688class const_n_pointer<T,N,ARPA_TYPE,false>
689{
690        const T* p_p;
691        const size_t* p_st;
692        const tree_vec* p_v;
693public:
694        const_n_pointer(const T* p, const size_t* st=NULL, const tree_vec* v=NULL) : p_p(p), p_st(st), p_v(v) {}
695        const const_n_pointer<T,N-1,ARPA_TYPE,false> operator[] (const size_t i) const
696        {
697                return const_n_pointer<T,N-1,ARPA_TYPE,false>( *((T**)p_p+i) );
698        }
699};
700
701template<class T, int N>
702class const_n_pointer<T,N,C_TYPE,false>
703{
704        const T* p_p;
705        const size_t* p_st;
706        const tree_vec* p_v;
707public:
708        const_n_pointer(const T* p, const size_t* st, const tree_vec* v=NULL) : p_p(p), p_st(st), p_v(v) {}
709        const const_n_pointer<T,N-1,C_TYPE,false> operator[] (const size_t i) const
710        {
711                return const_n_pointer<T,N-1,C_TYPE,false>( p_p+i*p_st[0], p_st+1 );
712        }
713};
714
715template<class T>
716class const_n_pointer<T,1,ARPA_TYPE,false>
717{
718        const T* p_p;
719        const size_t* p_st;
720        const tree_vec* p_v;
721public:
722        const_n_pointer(const T* p, const size_t* st=NULL, const tree_vec* v=NULL) : p_p(p), p_st(st), p_v(v) {}
723        const T& operator[] (const size_t i) const
724        {
725                return *(p_p + i);
726        }
727};
728
729template<class T>
730class const_n_pointer<T,1,C_TYPE,false>
731{
732        const T* p_p;
733        const size_t* p_st;
734        const tree_vec* p_v;
735public:
736        const_n_pointer(const T* p, const size_t* st, const tree_vec* v=NULL) : p_p(p), p_st(st), p_v(v) {}
737        const T& operator[] (const size_t i) const
738        {
739                return *(p_p + i);
740        }
741};
742
743template<class T, int N>
744class const_n_pointer<T,N,ARPA_TYPE,true>
745{
746        const T* p_p;
747        const size_t* p_st;
748        const tree_vec* p_v;
749public:
750        const_n_pointer(const T* p, const size_t* st, const tree_vec* v) : p_p(p), p_st(st), p_v(v) {}
751        const const_n_pointer<T,N-1,ARPA_TYPE,true> operator[] (const size_t i) const
752        {
753                if( i >= p_v->n )
754                        OUT_OF_RANGE( "const_n_pointer::operator[]" );
755                return const_n_pointer<T,N-1,ARPA_TYPE,true>( *((T**)p_p+i), NULL, &p_v->d[i] );
756        }
757};
758
759template<class T, int N>
760class const_n_pointer<T,N,C_TYPE,true>
761{
762        const T* p_p;
763        const size_t* p_st;
764        const tree_vec* p_v;
765public:
766        const_n_pointer(const T* p, const size_t* st, const tree_vec* v) : p_p(p), p_st(st), p_v(v) {}
767        const const_n_pointer<T,N-1,C_TYPE,true> operator[] (const size_t i) const
768        {
769                if( i >= p_v->n )
770                        OUT_OF_RANGE( "const_n_pointer::operator[]" );
771                return const_n_pointer<T,N-1,C_TYPE,true>( p_p+i*p_st[0], p_st+1, &p_v->d[i] );
772        }
773};
774
775template<class T>
776class const_n_pointer<T,1,ARPA_TYPE,true>
777{
778        const T* p_p;
779        const size_t* p_st;
780        const tree_vec* p_v;
781public:
782        const_n_pointer(const T* p, const size_t* st, const tree_vec* v) : p_p(p), p_st(st), p_v(v) {}
783        const T& operator[] (const size_t i) const
784        {
785                if( i >= p_v->n )
786                        OUT_OF_RANGE( "const_n_pointer::operator[]" );
787                return *(p_p + i);
788        }
789};
790
791template<class T>
792class const_n_pointer<T,1,C_TYPE,true>
793{
794        const T* p_p;
795        const size_t* p_st;
796        const tree_vec* p_v;
797public:
798        const_n_pointer(const T* p, const size_t* st, const tree_vec* v) : p_p(p), p_st(st), p_v(v) {}
799        const T& operator[] (const size_t i) const
800        {
801                if( i >= p_v->n )
802                        OUT_OF_RANGE( "const_n_pointer::operator[]" );
803                return *(p_p + i);
804        }
805};
806
807//
808//! multi_arr: generic class for allocating multidimensional arrays.
809//! A typical example of its use could be:
810//!
811//!     multi_arr<double,3> arr; // define a placeholder for the array
812//!                       // the first argument is the type of data it holds
813//!                       // the second argument is the number of dimensions
814//!                       // (between 2 and 6)
815//!
816//!     arr.alloc(3,4,2); // this will allocate a 3x4x2 block of doubles
817//!                       // memory will be allocated by new[] so will
818//!                       // be initialized by the constructor, if present
819//!
820//!     multi_arr<double,3> arr(3,4,2); // shorthand for the above
821//!
822//! The following is an alternative way of allocating the array. It is
823//! very similar to the pre-multi_arr way of allocating arrays. In ARPA_TYPE
824//! arrays this will help you save memory since only the data elements
825//! that are really needed will be allocated. In C_TYPE allocation, the
826//! smallest rectangular block will be allocated that can hold all the data.
827//! This will use more memory in return for somewhat improved CPU speed.
828//! Tests carried out in 2007 showed that the speed advantage of C_TYPE arrays
829//! was only 1 to 2 percent. Hence the memory savings were deemed more important
830//! and ARPA_TYPE arrays were made the default. However, C_TYPE arrays are
831//! guaranteed to be compatible with C code, so these should be used if they
832//! are meant to be passed on to C library routines. The example below allocates
833//! a triangular matrix.
834//!
835//!     arr.reserve(3);
836//!     for( int i=0, i < 3; ++i )
837//!     {
838//!       arr.reserve( i, i+1 ); // note that size does not need to be constant!
839//!       for( int j=0, j < i+1; ++j )
840//!         arr.reserve( i, j, j+1 );
841//!     }
842//!     arr.alloc();
843//!
844//! these are plausible ways to use the multi_arr class:
845//!       
846//!     arr.invalidate(); // this will set float or double arrays to all SNaN
847//!                       // it will set any other type array to all 0xff bytes.
848//!     arr.zero();       // this will set the array to all zero
849//!
850//!     arr[0][0][0] = 1.;
851//!     arr[0][0][1] = 2.;
852//!     double x = arr[0][0][0]*arr[0][0][1];
853//!
854//!     arr.state_do(io,lgRead); // this will write/read the array to/from a state file
855//!                       // depending on the boolean flag lgRead; io should point to a
856//!                       // file that is already opened for binary writing/reading
857//!                       // the file will remain open after access. this allows you to
858//!                       // use state_do() for several arrays in a row
859//!
860//!     multi_arr<double,2,C_TYPE> a(10,10); // allocate C_TYPE array
861//!     C_library_routine( a.data(), ... );  // and call C library routine with it
862//!
863//!     arr.clear();      // this will deallocate the array
864//!                       // the destructor will also automatically deallocate
865//!
866//! the multi_arr class comes with iterators that allow you to speed up memory access
867//! even further. using iterators as shown below will generally speed up the code
868//! significantly since it avoids calculating the array index over and over inside the
869//! body of the loop. especially in tight loops over arrays with high dimension this can
870//! become a significant overhead! a const_iterator is also supplied for read-only access,
871//! but no reverse_iterators. you can define and initialize an iterator as follows
872//!
873//!     multi_arr<double,3>::iterator p = arr.begin(n,k);
874//!
875//! the notation multi_arr