source: libcfa/src/containers/array.hfa @ a5e2682

ADTast-experimental
Last change on this file since a5e2682 was a5e2682, checked in by Michael Brooks <mlbrooks@…>, 18 months ago

Improve new-array subscripting to cover missing cases.

Missing cases include acknowledging a[0] and a[1] as required uses; therefore, give them
special overloads. Add comments to explain why.

Missing cases include test coverage of these overloads (where tests actually fail when an overload
is missing). Perhaps surprisingly, you need to use a lot of features at the same time for the need
for several overloads to obtain; make test coverage go there.

Also, switch thesis's demo of mutidimensional transposing/slicing to use (improved) libcfa ar
(pseudo-)trait, in place of former ix trait. Therefore, also port this demo to new array
syntax. (No changes to thesis discussion around this demo yet; these are still pending.) All
in, cause this thesis demo to be runnable again.

  • Property mode set to 100644
File size: 8.4 KB
Line 
1#pragma once
2
3#include <assert.h>
4
5
6forall( __CFA_tysys_id_only_X & ) struct tag {};
7#define ttag(T) ((tag(T)){})
8#define ztag(n) ttag(n)
9
10
11//
12// Single-dim array sruct (with explicit packing and atom)
13//
14
15forall( [N], S & | sized(S), Timmed &, Tbase & ) {
16    struct arpk {
17        S strides[N];
18    };
19
20    // About the choice of integral types offered as subscript overloads:
21    // Intent is to cover these use cases:
22    //    a[0]                                                // i : zero_t
23    //    a[1]                                                // i : one_t
24    //    a[2]                                                // i : int
25    //    float foo( ptrdiff_t i ) { return a[i]; }           // i : ptrdiff_t
26    //    float foo( size_t i ) { return a[i]; }              // i : size_t
27    //    forall( [N] ) ... for( i; N ) { total += a[i]; }    // i : typeof( sizeof(42) )
28    //    for( i; 5 ) { total += a[i]; }                      // i : int
29    //
30    // It gets complicated by:
31    // -  CFA does overloading on concrete types, like int and unsigned int, not on typedefed
32    //    types like size_t.  So trying to overload on ptrdiff_t vs int works in 64-bit mode
33    //    but not in 32-bit mode.
34    // -  Given bug of Trac #247, CFA gives sizeof expressions type unsigned long int, when it
35    //    should give them type size_t.
36    //
37    //                          gcc -m32         cfa -m32 given bug         gcc -m64 (and cfa)
38    // ptrdiff_t                int              int                        long int
39    // size_t                   unsigned int     unsigned int               unsigned long int
40    // typeof( sizeof(42) )     unsigned int     unsigned long int          unsigned long int
41    // int                      int              int                        int
42    //
43    // So the solution must support types {zero_t, one_t, int, unsigned int, long int, unsigned long int}
44    //
45    // The solution cannot rely on implicit conversions (e.g. just have one overload for ptrdiff_t)
46    // because assertion satisfaction requires types to match exacly.  Both higher-dimensional
47    // subscripting and operations on slices use asserted subscript operators.  The test case
48    // array-container/array-sbscr-cases covers the combinations.  Mike beleives that commenting out
49    // any of the current overloads leads to one of those cases failing, either on 64- or 32-bit.
50    // Mike is open to being shown a smaller set of overloads that still passes the test.
51
52    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, zero_t ) {
53        assert( 0 < N );
54        return (Timmed &) a.strides[0];
55    }
56
57    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, one_t ) {
58        assert( 1 < N );
59        return (Timmed &) a.strides[1];
60    }
61
62    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, int i ) {
63        assert( i < N );
64        return (Timmed &) a.strides[i];
65    }
66
67    static inline const Timmed & ?[?]( const arpk(N, S, Timmed, Tbase) & a, int i ) {
68        assert( i < N );
69        return (Timmed &) a.strides[i];
70    }
71
72    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, unsigned int i ) {
73        assert( i < N );
74        return (Timmed &) a.strides[i];
75    }
76
77    static inline const Timmed & ?[?]( const arpk(N, S, Timmed, Tbase) & a, unsigned int i ) {
78        assert( i < N );
79        return (Timmed &) a.strides[i];
80    }
81
82    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, long int i ) {
83        assert( i < N );
84        return (Timmed &) a.strides[i];
85    }
86
87    static inline const Timmed & ?[?]( const arpk(N, S, Timmed, Tbase) & a, long int i ) {
88        assert( i < N );
89        return (Timmed &) a.strides[i];
90    }
91
92    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, unsigned long int i ) {
93        assert( i < N );
94        return (Timmed &) a.strides[i];
95    }
96
97    static inline const Timmed & ?[?]( const arpk(N, S, Timmed, Tbase) & a, unsigned long int i ) {
98        assert( i < N );
99        return (Timmed &) a.strides[i];
100    }
101
102    static inline size_t ?`len( arpk(N, S, Timmed, Tbase) & a ) {
103        return N;
104    }
105
106    static inline void __taglen( tag(arpk(N, S, Timmed, Tbase)), tag(N) ) {}
107
108    // workaround #226 (and array relevance thereof demonstrated in mike102/otype-slow-ndims.cfa)
109    static inline void ?{}( arpk(N, S, Timmed, Tbase) & this ) {
110        void ?{}( S (&inner)[N] ) {}
111        ?{}(this.strides);
112    }
113    static inline void ^?{}( arpk(N, S, Timmed, Tbase) & this ) {
114        void ^?{}( S (&inner)[N] ) {}
115        ^?{}(this.strides);
116    }
117}
118
119//
120// Sugar for declaring array structure instances
121//
122
123forall( Te )
124static inline Te mkar_( tag(Te) ) {}
125
126forall( [N], ZTags ... , Trslt &, Tatom & | { Trslt mkar_( tag(Tatom), ZTags ); } )
127static inline arpk(N, Trslt, Trslt, Tatom) mkar_( tag(Tatom), tag(N), ZTags ) {}
128
129// based on https://stackoverflow.com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros
130
131    // Make a FOREACH macro
132    #define FE_0(WHAT)
133    #define FE_1(WHAT, X) WHAT(X)
134    #define FE_2(WHAT, X, ...) WHAT(X)FE_1(WHAT, __VA_ARGS__)
135    #define FE_3(WHAT, X, ...) WHAT(X)FE_2(WHAT, __VA_ARGS__)
136    #define FE_4(WHAT, X, ...) WHAT(X)FE_3(WHAT, __VA_ARGS__)
137    #define FE_5(WHAT, X, ...) WHAT(X)FE_4(WHAT, __VA_ARGS__)
138    //... repeat as needed
139
140    #define GET_MACRO(_0,_1,_2,_3,_4,_5,NAME,...) NAME
141    #define FOR_EACH(action,...) \
142    GET_MACRO(_0,__VA_ARGS__,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(action,__VA_ARGS__)
143
144#define COMMA_ttag(X) , ttag(X)
145#define array( TE, ...) typeof( mkar_( ttag(TE)  FOR_EACH( COMMA_ttag, __VA_ARGS__ ) ) )
146
147#define COMMA_ztag(X) , ztag(X)
148#define zarray( TE, ...) typeof( mkar_( ttag(TE)  FOR_EACH( COMMA_ztag, __VA_ARGS__ ) ) )
149
150//
151// Sugar for multidimensional indexing
152//
153
154// Core -[[-,-,-]] operator
155
156#ifdef TRY_BROKEN_DESIRED_MD_SUBSCRIPT
157
158// Desired form.  One definition with recursion on IxBC (worked until Jan 2021, see trac #__TODO__)
159
160forall( TA &, TB &, TC &, IxAB, IxBC ... | { TB & ?[?]( TA &, IxAB ); TC & ?[?]( TB &, IxBC ); } )
161static inline TC & ?[?]( TA & this, IxAB ab, IxBC bc ) {
162    return this[ab][bc];
163}
164
165#else
166
167// Workaround form.  Listing all possibilities up to 4 dims.
168
169forall( TA &, TB &, TC &, IxAB_0, IxBC | { TB & ?[?]( TA &, IxAB_0 ); TC & ?[?]( TB &, IxBC ); } )
170static inline TC & ?[?]( TA & this, IxAB_0 ab, IxBC bc ) {
171    return this[ab][bc];
172}
173
174forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1 ); TC & ?[?]( TB &, IxBC ); } )
175static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxBC bc ) {
176    return this[[ab0,ab1]][bc];
177}
178
179forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxAB_2, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1, IxAB_2 ); TC & ?[?]( TB &, IxBC ); } )
180static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxAB_2 ab2, IxBC bc ) {
181    return this[[ab0,ab1,ab2]][bc];
182}
183
184#endif
185
186// Available for users to work around Trac #265
187// If `a[...0...]` isn't working, try `a[...ix0...]` instead.
188
189#define ix0 ((ptrdiff_t)0)
190
191
192
193//
194// Rotation
195//
196
197// Base
198forall( [Nq], Sq & | sized(Sq), Tbase & )
199static inline tag(arpk(Nq, Sq, Tbase, Tbase)) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(Tbase) ) {
200    tag(arpk(Nq, Sq, Tbase, Tbase)) ret;
201    return ret;
202}
203
204// Rec
205forall( [Nq], Sq & | sized(Sq), [N], S & | sized(S), recq &, recr &, Tbase & | { tag(recr) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(recq) ); } )
206static inline tag(arpk(N, S, recr, Tbase)) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(arpk(N, S, recq, Tbase)) ) {
207    tag(arpk(N, S, recr, Tbase)) ret;
208    return ret;
209}
210
211// Wrapper
212extern struct all_t {} all;
213forall( [N], S & | sized(S), Te &, result &, Tbase & | { tag(result) enq_( tag(Tbase), tag(N), tag(S), tag(Te) ); } )
214static inline result & ?[?]( arpk(N, S, Te, Tbase) & this, all_t ) {
215    return (result&) this;
216}
217
218//
219// Trait of array or slice
220//
221
222// desired:
223// trait ar(A &, Tv &, [N]) {
224//     Tv& ?[?]( A&, zero_t );
225//     Tv& ?[?]( A&, one_t  );
226//     Tv& ?[?]( A&, int    );
227//                   ...
228//     size_t ?`len( A& );
229//     void __taglen( tag(C), tag(N) );
230// };
231
232// working around N's not being accepted as arguments to traits
233
234#define ar(A, Tv, N) {                 \
235    Tv& ?[?]( A&, zero_t );            \
236    Tv& ?[?]( A&, one_t );             \
237    Tv& ?[?]( A&, int );               \
238    Tv& ?[?]( A&, unsigned int );      \
239    Tv& ?[?]( A&, long int );          \
240    Tv& ?[?]( A&, unsigned long int ); \
241    size_t ?`len( A& );                \
242    void __taglen( tag(A), tag(N) );   \
243}
Note: See TracBrowser for help on using the repository browser.