Changeset ce02877 for libcfa/src/collections/array.hfa
- Timestamp:
- Jul 29, 2024, 1:32:51 PM (4 months ago)
- Branches:
- master
- Children:
- f3d2a4f
- Parents:
- 38e20a80 (diff), 1661ad7 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/collections/array.hfa
r38e20a80 rce02877 1 1 #pragma once 2 2 3 #include <assert.h>3 //#include <assert.h> 4 4 5 5 … … 8 8 #define ztag(n) ttag(n) 9 9 10 #ifdef __CFA_DEBUG__ 11 #define subcheck( arr, sub, lb, ub ) \ 12 if ( (sub) < (lb) || (sub) >= (ub) ) \ 13 abort( "subscript %ld exceeds dimension range [%d,%zd) for array %p.\n", \ 14 (sub), (lb), (ub), (arr) ) 15 #else 16 #define subcheck( arr, sub, lb, ub ) do {} while (0) 17 #endif 10 18 11 19 // … … 36 44 // 37 45 forall( [N], S & | sized(S), Timmed &, Tbase & ) { 38 39 // 40 // Single-dim array sruct (with explicit packing and atom) 41 // 42 struct arpk { 43 S strides[N]; 44 }; 45 46 // About the choice of integral types offered as subscript overloads: 47 // Intent is to cover these use cases: 48 // a[0] // i : zero_t 49 // a[1] // i : one_t 50 // a[2] // i : int 51 // float foo( ptrdiff_t i ) { return a[i]; } // i : ptrdiff_t 52 // float foo( size_t i ) { return a[i]; } // i : size_t 53 // forall( [N] ) ... for( i; N ) { total += a[i]; } // i : typeof( sizeof(42) ) 54 // for( i; 5 ) { total += a[i]; } // i : int 55 // 56 // It gets complicated by: 57 // - CFA does overloading on concrete types, like int and unsigned int, not on typedefed 58 // types like size_t. So trying to overload on ptrdiff_t vs int works in 64-bit mode 59 // but not in 32-bit mode. 60 // - Given bug of Trac #247, CFA gives sizeof expressions type unsigned long int, when it 61 // should give them type size_t. 62 // 63 // gcc -m32 cfa -m32 given bug gcc -m64 (and cfa) 64 // ptrdiff_t int int long int 65 // size_t unsigned int unsigned int unsigned long int 66 // typeof( sizeof(42) ) unsigned int unsigned long int unsigned long int 67 // int int int int 68 // 69 // So the solution must support types {zero_t, one_t, int, unsigned int, long int, unsigned long int} 70 // 71 // The solution cannot rely on implicit conversions (e.g. just have one overload for ptrdiff_t) 72 // because assertion satisfaction requires types to match exacly. Both higher-dimensional 73 // subscripting and operations on slices use asserted subscript operators. The test case 74 // array-container/array-sbscr-cases covers the combinations. Mike beleives that commenting out 75 // any of the current overloads leads to one of those cases failing, either on 64- or 32-bit. 76 // Mike is open to being shown a smaller set of overloads that still passes the test. 77 78 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, zero_t ) { 79 assert( 0 < N ); 80 return (Timmed &) a.strides[0]; 81 } 82 83 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, one_t ) { 84 assert( 1 < N ); 85 return (Timmed &) a.strides[1]; 86 } 87 88 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, int i ) { 89 assert( i < N ); 90 return (Timmed &) a.strides[i]; 91 } 92 93 static inline const Timmed & ?[?]( const arpk(N, S, Timmed, Tbase) & a, int i ) { 94 assert( i < N ); 95 return (Timmed &) a.strides[i]; 96 } 97 98 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, unsigned int i ) { 99 assert( i < N ); 100 return (Timmed &) a.strides[i]; 101 } 102 103 static inline const Timmed & ?[?]( const arpk(N, S, Timmed, Tbase) & a, unsigned int i ) { 104 assert( i < N ); 105 return (Timmed &) a.strides[i]; 106 } 107 108 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, long int i ) { 109 assert( i < N ); 110 return (Timmed &) a.strides[i]; 111 } 112 113 static inline const Timmed & ?[?]( const arpk(N, S, Timmed, Tbase) & a, long int i ) { 114 assert( i < N ); 115 return (Timmed &) a.strides[i]; 116 } 117 118 static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, unsigned long int i ) { 119 assert( i < N ); 120 return (Timmed &) a.strides[i]; 121 } 122 123 static inline const Timmed & ?[?]( const arpk(N, S, Timmed, Tbase) & a, unsigned long int i ) { 124 assert( i < N ); 125 return (Timmed &) a.strides[i]; 126 } 127 128 static inline size_t ?`len( arpk(N, S, Timmed, Tbase) & a ) { 129 return N; 130 } 131 132 static inline void __taglen( tag(arpk(N, S, Timmed, Tbase)), tag(N) ) {} 46 // 47 // Single-dim array struct (with explicit packing and atom) 48 // 49 struct arpk { 50 S strides[N]; 51 }; 52 53 // About the choice of integral types offered as subscript overloads: 54 // Intent is to cover these use cases: 55 // a[0] // i : zero_t 56 // a[1] // i : one_t 57 // a[2] // i : int 58 // float foo( ptrdiff_t i ) { return a[i]; } // i : ptrdiff_t 59 // float foo( size_t i ) { return a[i]; } // i : size_t 60 // forall( [N] ) ... for( i; N ) { total += a[i]; } // i : typeof( sizeof(42) ) 61 // for( i; 5 ) { total += a[i]; } // i : int 62 // 63 // It gets complicated by: 64 // - CFA does overloading on concrete types, like int and unsigned int, not on typedefed 65 // types like size_t. So trying to overload on ptrdiff_t vs int works in 64-bit mode 66 // but not in 32-bit mode. 67 // - Given bug of Trac #247, CFA gives sizeof expressions type unsigned long int, when it 68 // should give them type size_t. 69 // 70 // gcc -m32 cfa -m32 given bug gcc -m64 (and cfa) 71 // ptrdiff_t int int long int 72 // size_t unsigned int unsigned int unsigned long int 73 // typeof( sizeof(42) ) unsigned int unsigned long int unsigned long int 74 // int int int int 75 // 76 // So the solution must support types {zero_t, one_t, int, unsigned int, long int, unsigned long int} 77 // 78 // The solution cannot rely on implicit conversions (e.g. just have one overload for ptrdiff_t) 79 // because assertion satisfaction requires types to match exacly. Both higher-dimensional 80 // subscripting and operations on slices use asserted subscript operators. The test case 81 // array-container/array-sbscr-cases covers the combinations. Mike beleives that commenting out 82 // any of the current overloads leads to one of those cases failing, either on 64- or 32-bit. 83 // Mike is open to being shown a smaller set of overloads that still passes the test. 84 85 static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, zero_t ) { 86 //assert( 0 < N ); 87 subcheck( a, 0L, 0, N ); 88 return (Timmed &)a.strides[0]; 89 } 90 91 static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, one_t ) { 92 //assert( 1 < N ); 93 subcheck( a, 1L, 0, N ); 94 return (Timmed &)a.strides[1]; 95 } 96 97 static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, int i ) { 98 //assert( i < N ); 99 subcheck( a, (long int)i, 0, N ); 100 return (Timmed &)a.strides[i]; 101 } 102 103 static inline const Timmed & ?[?]( const arpk( N, S, Timmed, Tbase ) & a, int i ) { 104 //assert( i < N ); 105 subcheck( a, (long int)i, 0, N ); 106 return (Timmed &)a.strides[i]; 107 } 108 109 static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, unsigned int i ) { 110 //assert( i < N ); 111 subcheck( a, (long int)i, 0, N ); 112 return (Timmed &)a.strides[i]; 113 } 114 115 static inline const Timmed & ?[?]( const arpk( N, S, Timmed, Tbase ) & a, unsigned int i ) { 116 //assert( i < N ); 117 subcheck( a, (unsigned long int)i, 0, N ); 118 return (Timmed &)a.strides[i]; 119 } 120 121 static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, long int i ) { 122 //assert( i < N ); 123 subcheck( a, i, 0, N ); 124 return (Timmed &)a.strides[i]; 125 } 126 127 static inline const Timmed & ?[?]( const arpk( N, S, Timmed, Tbase ) & a, long int i ) { 128 //assert( i < N ); 129 subcheck( a, i, 0, N ); 130 return (Timmed &)a.strides[i]; 131 } 132 133 static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, unsigned long int i ) { 134 //assert( i < N ); 135 subcheck( a, i, 0, N ); 136 return (Timmed &)a.strides[i]; 137 } 138 139 static inline const Timmed & ?[?]( const arpk( N, S, Timmed, Tbase ) & a, unsigned long int i ) { 140 //assert( i < N ); 141 subcheck( a, i, 0, N ); 142 return (Timmed &)a.strides[i]; 143 } 144 145 static inline size_t ?`len( arpk( N, S, Timmed, Tbase ) & a ) { 146 return N; 147 } 148 149 static inline void __taglen( tag(arpk( N, S, Timmed, Tbase )), tag(N) ) {} 133 150 } 134 151 135 152 // RAII pattern has workarounds for 136 153 // - Trac 226: Simplest handling would be, require immediate element to be otype, let autogen 137 // 138 // 139 // 154 // raii happen. Performance on even a couple dimensions is unacceptable because of exponential 155 // thunk creation: ?{}() needs all four otype funcs from next level, so does ^?{}(), so do the 156 // other two. This solution offers ?{}() that needs only ?{}(), and similar for ^?{}. 140 157 141 158 forall( [N], S & | sized(S), Timmed &, Tbase & | { void ?{}( Timmed & ); } ) 142 static inline void ?{}( arpk( N, S, Timmed, Tbase) & this ) {143 144 145 146 for (i; N) ?{}( (Timmed &)this.strides[i] );159 static inline void ?{}( arpk( N, S, Timmed, Tbase ) & this ) { 160 void ?{}( S (&)[N] ) {} 161 ?{}(this.strides); 162 163 for (i; N) ?{}( (Timmed &)this.strides[i] ); 147 164 } 148 165 149 166 forall( [N], S & | sized(S), Timmed &, Tbase & | { void ^?{}( Timmed & ); } ) 150 static inline void ^?{}( arpk( N, S, Timmed, Tbase) & this ) {151 152 153 154 155 ^?{}( (Timmed &)this.strides[N-i-1] );156 167 static inline void ^?{}( arpk( N, S, Timmed, Tbase ) & this ) { 168 void ^?{}( S (&)[N] ) {} 169 ^?{}(this.strides); 170 171 for (i; N ) { 172 ^?{}( (Timmed &)this.strides[N-i-1] ); 173 } 157 174 } 158 175 … … 165 182 166 183 forall( [N], ZTags ... , Trslt &, Tatom & | { Trslt mkar_( tag(Tatom), ZTags ); } ) 167 static inline arpk( N, Trslt, Trslt, Tatom) mkar_( tag(Tatom), tag(N), ZTags ) {}184 static inline arpk( N, Trslt, Trslt, Tatom) mkar_( tag(Tatom), tag(N), ZTags ) {} 168 185 169 186 // based on https://stackoverflow.com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros 170 187 171 172 173 174 175 176 177 178 179 180 181 182 188 // Make a FOREACH macro 189 #define FE_0(WHAT) 190 #define FE_1(WHAT, X) WHAT(X) 191 #define FE_2(WHAT, X, ...) WHAT(X)FE_1(WHAT, __VA_ARGS__) 192 #define FE_3(WHAT, X, ...) WHAT(X)FE_2(WHAT, __VA_ARGS__) 193 #define FE_4(WHAT, X, ...) WHAT(X)FE_3(WHAT, __VA_ARGS__) 194 #define FE_5(WHAT, X, ...) WHAT(X)FE_4(WHAT, __VA_ARGS__) 195 //... repeat as needed 196 197 #define GET_MACRO(_0,_1,_2,_3,_4,_5,NAME,...) NAME 198 #define FOR_EACH(action,...) \ 199 GET_MACRO(_0,__VA_ARGS__,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(action,__VA_ARGS__) 183 200 184 201 #define COMMA_ttag(X) , ttag(X) … … 200 217 forall( TA &, TB &, TC &, IxAB, IxBC ... | { TB & ?[?]( TA &, IxAB ); TC & ?[?]( TB &, IxBC ); } ) 201 218 static inline TC & ?[?]( TA & this, IxAB ab, IxBC bc ) { 202 219 return this[ab][bc]; 203 220 } 204 221 … … 209 226 forall( TA &, TB &, TC &, IxAB_0, IxBC | { TB & ?[?]( TA &, IxAB_0 ); TC & ?[?]( TB &, IxBC ); } ) 210 227 static inline TC & ?[?]( TA & this, IxAB_0 ab, IxBC bc ) { 211 228 return this[ab][bc]; 212 229 } 213 230 214 231 forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1 ); TC & ?[?]( TB &, IxBC ); } ) 215 232 static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxBC bc ) { 216 233 return this[[ab0,ab1]][bc]; 217 234 } 218 235 219 236 forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxAB_2, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1, IxAB_2 ); TC & ?[?]( TB &, IxBC ); } ) 220 237 static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxAB_2 ab2, IxBC bc ) { 221 238 return this[[ab0,ab1,ab2]][bc]; 222 239 } 223 240 … … 237 254 // Base 238 255 forall( [Nq], Sq & | sized(Sq), Tbase & ) 239 static inline tag(arpk( Nq, Sq, Tbase, Tbase)) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(Tbase) ) {240 tag(arpk(Nq, Sq, Tbase, Tbase)) ret;241 256 static inline tag(arpk( Nq, Sq, Tbase, Tbase )) enq_( tag(Tbase ), tag(Nq), tag(Sq), tag(Tbase ) ) { 257 tag(arpk( Nq, Sq, Tbase, Tbase )) ret; 258 return ret; 242 259 } 243 260 244 261 // Rec 245 262 forall( [Nq], Sq & | sized(Sq), [N], S & | sized(S), recq &, recr &, Tbase & | { tag(recr) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(recq) ); } ) 246 static inline tag(arpk( N, S, recr, Tbase)) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(arpk(N, S, recq, Tbase)) ) {247 tag(arpk(N, S, recr, Tbase)) ret;248 263 static inline tag(arpk( N, S, recr, Tbase )) enq_( tag(Tbase ), tag(Nq), tag(Sq), tag(arpk( N, S, recq, Tbase )) ) { 264 tag(arpk( N, S, recr, Tbase )) ret; 265 return ret; 249 266 } 250 267 … … 252 269 extern struct all_t {} all; 253 270 forall( [N], S & | sized(S), Te &, result &, Tbase & | { tag(result) enq_( tag(Tbase), tag(N), tag(S), tag(Te) ); } ) 254 static inline result & ?[?]( arpk( N, S, Te, Tbase) & this, all_t ) {255 271 static inline result & ?[?]( arpk( N, S, Te, Tbase ) & this, all_t ) { 272 return (result&) this; 256 273 } 257 274 … … 263 280 // forall(A &, Tv &, [N]) 264 281 // trait ar { 265 // 266 // 267 // Tv& ?[?]( A&, int);268 // 269 // 270 // 282 // Tv& ?[?]( A&, zero_t ); 283 // Tv& ?[?]( A&, one_t ); 284 // Tv& ?[?]( A&, int ); 285 // ... 286 // size_t ?`len( A& ); 287 // void __taglen( tag(C), tag(N) ); 271 288 // }; 272 289 273 290 // working around N's not being accepted as arguments to traits 274 291 275 #define ar( A, Tv, N) {\276 Tv& ?[?]( A&, zero_t );\277 Tv& ?[?]( A&, one_t );\278 Tv& ?[?]( A&, int );\279 Tv& ?[?]( A&, unsigned int );\280 Tv& ?[?]( A&, long int );\281 Tv& ?[?]( A&, unsigned long int );\282 size_t ?`len( A& );\283 void __taglen( tag(A), tag(N) );\284 } 292 #define ar( A, Tv, N ) { \ 293 Tv& ?[?]( A&, zero_t ); \ 294 Tv& ?[?]( A&, one_t ); \ 295 Tv& ?[?]( A&, int ); \ 296 Tv& ?[?]( A&, unsigned int ); \ 297 Tv& ?[?]( A&, long int ); \ 298 Tv& ?[?]( A&, unsigned long int ); \ 299 size_t ?`len( A& ); \ 300 void __taglen( tag(A), tag(N) ); \ 301 }
Note: See TracChangeset
for help on using the changeset viewer.