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