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

ADTast-experimental
Last change on this file since b797d97 was a5e2682, checked in by Michael Brooks <mlbrooks@…>, 20 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
RevLine 
[a5e2682]1#pragma once
2
[8d76f2b]3#include <assert.h>
[c7625e0]4
5
[6e50a6b]6forall( __CFA_tysys_id_only_X & ) struct tag {};
[c7625e0]7#define ttag(T) ((tag(T)){})
[6e50a6b]8#define ztag(n) ttag(n)
[c7625e0]9
10
11//
12// Single-dim array sruct (with explicit packing and atom)
13//
14
[63f42a8]15forall( [N], S & | sized(S), Timmed &, Tbase & ) {
[c7625e0]16    struct arpk {
[6e50a6b]17        S strides[N];
[c7625e0]18    };
19
[9fa538c]20    // About the choice of integral types offered as subscript overloads:
21    // Intent is to cover these use cases:
[a5e2682]22    //    a[0]                                                // i : zero_t
23    //    a[1]                                                // i : one_t
24    //    a[2]                                                // i : int
[9fa538c]25    //    float foo( ptrdiff_t i ) { return a[i]; }           // i : ptrdiff_t
[a5e2682]26    //    float foo( size_t i ) { return a[i]; }              // i : size_t
[9fa538c]27    //    forall( [N] ) ... for( i; N ) { total += a[i]; }    // i : typeof( sizeof(42) )
28    //    for( i; 5 ) { total += a[i]; }                      // i : int
[a5e2682]29    //
[9fa538c]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.
[d1abc63c]36    //
[a5e2682]37    //                          gcc -m32         cfa -m32 given bug         gcc -m64 (and cfa)
[9fa538c]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
[a5e2682]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    }
[9fa538c]61
62    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, int i ) {
[8d76f2b]63        assert( i < N );
[c7625e0]64        return (Timmed &) a.strides[i];
65    }
66
[d1abc63c]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
[9fa538c]72    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, unsigned int i ) {
[8d76f2b]73        assert( i < N );
[63a4b92]74        return (Timmed &) a.strides[i];
75    }
76
[d1abc63c]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
[9fa538c]82    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, long int i ) {
[8d76f2b]83        assert( i < N );
[63a4b92]84        return (Timmed &) a.strides[i];
85    }
86
[d1abc63c]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
[9fa538c]92    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, unsigned long int i ) {
[8d76f2b]93        assert( i < N );
[9fa538c]94        return (Timmed &) a.strides[i];
95    }
96
[d1abc63c]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
[9fa538c]102    static inline size_t ?`len( arpk(N, S, Timmed, Tbase) & a ) {
[6e50a6b]103        return N;
[c7625e0]104    }
105
[a5e2682]106    static inline void __taglen( tag(arpk(N, S, Timmed, Tbase)), tag(N) ) {}
107
[c7625e0]108    // workaround #226 (and array relevance thereof demonstrated in mike102/otype-slow-ndims.cfa)
[9fa538c]109    static inline void ?{}( arpk(N, S, Timmed, Tbase) & this ) {
[6e50a6b]110        void ?{}( S (&inner)[N] ) {}
[c7625e0]111        ?{}(this.strides);
112    }
[9fa538c]113    static inline void ^?{}( arpk(N, S, Timmed, Tbase) & this ) {
[6e50a6b]114        void ^?{}( S (&inner)[N] ) {}
[c7625e0]115        ^?{}(this.strides);
116    }
117}
118
119//
120// Sugar for declaring array structure instances
121//
122
123forall( Te )
[9fa538c]124static inline Te mkar_( tag(Te) ) {}
[c7625e0]125
[b9dae14c]126forall( [N], ZTags ... , Trslt &, Tatom & | { Trslt mkar_( tag(Tatom), ZTags ); } )
[9fa538c]127static inline arpk(N, Trslt, Trslt, Tatom) mkar_( tag(Tatom), tag(N), ZTags ) {}
[c7625e0]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)
[d1abc63c]133    #define FE_1(WHAT, X) WHAT(X)
[c7625e0]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
[d1abc63c]140    #define GET_MACRO(_0,_1,_2,_3,_4,_5,NAME,...) NAME
[c7625e0]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
[63a4b92]156#ifdef TRY_BROKEN_DESIRED_MD_SUBSCRIPT
157
[c7625e0]158// Desired form.  One definition with recursion on IxBC (worked until Jan 2021, see trac #__TODO__)
159
[63a4b92]160forall( TA &, TB &, TC &, IxAB, IxBC ... | { TB & ?[?]( TA &, IxAB ); TC & ?[?]( TB &, IxBC ); } )
[9fa538c]161static inline TC & ?[?]( TA & this, IxAB ab, IxBC bc ) {
[c7625e0]162    return this[ab][bc];
163}
164
[d1abc63c]165#else
[c7625e0]166
[63a4b92]167// Workaround form.  Listing all possibilities up to 4 dims.
[c7625e0]168
[63a4b92]169forall( TA &, TB &, TC &, IxAB_0, IxBC | { TB & ?[?]( TA &, IxAB_0 ); TC & ?[?]( TB &, IxBC ); } )
[9fa538c]170static inline TC & ?[?]( TA & this, IxAB_0 ab, IxBC bc ) {
[63a4b92]171    return this[ab][bc];
[c7625e0]172}
173
[63a4b92]174forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1 ); TC & ?[?]( TB &, IxBC ); } )
[9fa538c]175static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxBC bc ) {
[63a4b92]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 ); } )
[9fa538c]180static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxAB_2 ab2, IxBC bc ) {
[63a4b92]181    return this[[ab0,ab1,ab2]][bc];
182}
183
184#endif
185
[a5e2682]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
[c7625e0]193//
194// Rotation
195//
196
197// Base
[63f42a8]198forall( [Nq], Sq & | sized(Sq), Tbase & )
[6448f7d]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}
[c7625e0]203
204// Rec
[63f42a8]205forall( [Nq], Sq & | sized(Sq), [N], S & | sized(S), recq &, recr &, Tbase & | { tag(recr) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(recq) ); } )
[6448f7d]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}
[c7625e0]210
211// Wrapper
[058ece2]212extern struct all_t {} all;
[63f42a8]213forall( [N], S & | sized(S), Te &, result &, Tbase & | { tag(result) enq_( tag(Tbase), tag(N), tag(S), tag(Te) ); } )
[9fa538c]214static inline result & ?[?]( arpk(N, S, Te, Tbase) & this, all_t ) {
[c7625e0]215    return (result&) this;
216}
217
218//
219// Trait of array or slice
220//
221
[a5e2682]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.