Ignore:
Timestamp:
Apr 25, 2025, 7:39:09 AM (6 months ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
master
Children:
65bd3c2
Parents:
b195498
Message:

change backquote call to regular call

Location:
libcfa/src/collections
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/collections/list.hfa

    rb195498 r6b33e89  
    1010// Created On       : Wed Apr 22 18:00:00 2020
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Apr 20 19:04:50 2025
    13 // Update Count     : 51
     12// Last Modified On : Thu Apr 24 18:12:59 2025
     13// Update Count     : 72
    1414//
    1515
     
    7272
    7373// The origin is the position encountered at the start of iteration, signifying, "need to advance to the first element,"
    74 // and at the end of iteration, signifying, "no more elements."  Normal comsumption of an iterator runs ?`moveNext as
    75 // the first step, and uses the return of ?`moveNext as a guard, before dereferencing the iterator.  So normal
     74// and at the end of iteration, signifying, "no more elements."  Normal comsumption of an iterator runs "advance" as
     75// the first step, and uses the return of "advance" as a guard, before dereferencing the iterator.  So normal
    7676// consumption of an iterator does not dereference an iterator in origin position.  The value of a pointer (underlying a
    7777// refence) that is exposed publicly as an iteraor, and also a pointer stored internally in a link field, is tagged, to
     
    128128
    129129static inline forall( tE &, tLinks & | embedded( tE, tLinks, dlink( tE ) ) ) {
     130        bool isListed( tE & node ) {
     131                verify( &node != 0p );
     132                dlink( tE ) & node_links = node`inner;
     133                return (node_links.prev != 0p) || (node_links.next != 0p);
     134        }
     135
     136        bool isEmpty( dlist( tE, tLinks ) & list ) {
     137                tE * firstPtr = list.next;
     138                if ( ORIGIN_TAG_QUERY(( size_t)firstPtr) ) firstPtr = 0p;
     139                return firstPtr == 0p;
     140        }
     141
     142        tE & first( dlist( tE, tLinks ) & list ) {
     143                tE * firstPtr = list.next;
     144                if ( ORIGIN_TAG_QUERY( (size_t)firstPtr ) ) firstPtr = 0p;
     145                return *firstPtr;
     146        }
     147
     148        tE & last( dlist( tE, tLinks ) & list ) {
     149                tE * lastPtr = list.prev;
     150                if ( ORIGIN_TAG_QUERY( (size_t)lastPtr) ) lastPtr = 0p;
     151                return *lastPtr;
     152        }
     153
    130154        tE & insert_before( tE & before, tE & node ) {
    131155                verify( &before != 0p );
     
    194218        }
    195219
    196         tE & ?`first( dlist( tE, tLinks ) & list ) {
    197                 tE * firstPtr = list.next;
    198                 if ( ORIGIN_TAG_QUERY( (size_t)firstPtr ) ) firstPtr = 0p;
    199                 return *firstPtr;
    200         }
    201 
    202         tE & ?`last( dlist( tE, tLinks ) & list ) {
    203                 tE * lastPtr = list.prev;
    204                 if ( ORIGIN_TAG_QUERY( (size_t)lastPtr) ) lastPtr = 0p;
    205                 return *lastPtr;
    206         }
    207 
    208         bool ?`isEmpty( dlist( tE, tLinks ) & list ) {
    209                 tE * firstPtr = list.next;
    210                 if ( ORIGIN_TAG_QUERY(( size_t)firstPtr) ) firstPtr = 0p;
    211                 return firstPtr == 0p;
    212         }
    213 
    214         bool ?`isListed( tE & node ) {
    215                 verify( &node != 0p );
    216                 dlink( tE ) & node_links = node`inner;
    217                 return (node_links.prev != 0p) || (node_links.next != 0p);
    218         }
    219 
    220         tE & ?`elems( dlist( tE, tLinks ) & list ) {
     220        tE & iter( dlist( tE, tLinks ) & list ) {
    221221                tE * origin = $get_list_origin_addr( list );
    222222                return *origin;
    223223        }
    224         tE & ?`head( dlist( tE, tLinks ) & list ) {
    225                 return list`elems;
    226         }
    227 
    228         bool ?`moveNext( tE && refx ) {
     224
     225        bool recede( tE && refx ) {
     226                tE && ref_inner = refx;
     227                tE & oldReferent = *(tE*)ORIGIN_TAG_CLEAR( (size_t)&ref_inner );
     228                &ref_inner = oldReferent`inner.prev;
     229                return &ref_inner != 0p && ! ORIGIN_TAG_QUERY( (size_t)&ref_inner );
     230        }
     231
     232        bool advance( tE && refx ) {
    229233                tE && ref_inner = refx;
    230234                tE & oldReferent = *(tE*)ORIGIN_TAG_CLEAR( (size_t)&ref_inner );
     
    232236                return &ref_inner != 0p && ! ORIGIN_TAG_QUERY( (size_t)&ref_inner );
    233237        }
    234         bool ?`next( tE && refx ) {                                                     // alternate name
    235                 return refx`moveNext;
    236         }
    237 
    238         bool ?`movePrev( tE && refx ) {
    239                 tE && ref_inner = refx;
    240                 tE & oldReferent = *(tE*)ORIGIN_TAG_CLEAR( (size_t)&ref_inner );
    241                 &ref_inner = oldReferent`inner.prev;
    242                 return &ref_inner != 0p && ! ORIGIN_TAG_QUERY( (size_t)&ref_inner );
    243         }
    244         bool ?`prev( tE && refx ) {                                                     // alternate name
    245                 return refx`movePrev;
    246         }
    247 
    248         bool ?`hasNext( tE & node ) {
    249                 return node`moveNext;
    250         }
    251 
    252         bool ?`hasPrev( tE & node ) {
    253                 return node`movePrev;
    254         }
    255 
    256         tE & ?`next( tE & node ) {
    257                 if ( node`moveNext ) return node;
     238
     239    bool isFirst( tE & node ) {
     240        return recede( node );
     241    }
     242
     243    bool isLast( tE & node ) {
     244        return advance( node );
     245    }
     246
     247        tE & prev( tE & node ) {
     248                if ( recede( node ) ) return node;
    258249                return *0p;
    259250        }
    260251
    261         tE & ?`prev( tE & node ) {
    262                 if ( node`movePrev ) return node;
     252        tE & next( tE & node ) {
     253                if ( advance( node ) ) return node;
    263254                return *0p;
    264255        }
    265256
    266257        tE & insert_first( dlist( tE, tLinks ) & list, tE & node ) {
    267                 insert_after( list`elems, node );
     258                insert_after( iter( list ), node );
    268259                return node;
    269260        }
    270261
    271262        tE & insert_last( dlist( tE, tLinks ) & list, tE & node ) {
    272                 insert_before( list`elems, node );
    273                 return node;
    274         }
    275         tE &  insert( dlist( tE, tLinks ) & list, tE & node ) { // alternate name
     263                insert_before( iter( list ), node );
     264                return node;
     265        }
     266        tE & insert( dlist( tE, tLinks ) & list, tE & node ) { // synonym for insert_last
    276267                insert_last( list, node );
    277268                return node;
     
    279270
    280271        tE & remove_first( dlist( tE, tLinks ) & list ) {
    281                 return remove( list`first );
     272                tE & first_node = first( list );
     273                if ( &first_node ) return remove( first_node );
     274                return first_node;
    282275        }
    283276
    284277        tE & remove_last( dlist( tE, tLinks ) & list ) {
    285                 return remove( list`last );
     278                tE & last_node = last( list );
     279                if ( &last_node ) return remove( last_node );
     280                return last_node;
    286281        }
    287282
     
    322317//      }
    323318
    324         tE & try_pop_front( dlist( tE, tLinks ) & list ) {
    325                 tE & first_inlist = list`first;
    326                 tE & first_item = first_inlist;
    327                 if ( &first_item ) remove( first_inlist );
    328                 return first_item;
    329         }
    330 
    331         tE & try_pop_back( dlist( tE, tLinks ) & list ) {
    332                 tE & last_inlist = list`last;
    333                 tE & last_item = last_inlist;
    334                 if ( &last_item ) remove( last_inlist );
    335                 return last_item;
    336         }
    337 
    338 
    339319        #if ! defined(NDEBUG) && (defined(__CFA_DEBUG__) || defined(__CFA_VERIFY__))
    340320        bool $validate_fwd( dlist( tE, tLinks ) & this ) {
    341                 if ( ! & this`first ) return &this`last == 0p;
     321                if ( ! & first( this ) ) return &last( this ) == 0p;
    342322
    343323                tE & lagElem = *0p;
    344                 while ( tE & it = this`elems; it`moveNext ) {
    345                         if ( & lagElem == 0p &&  &it != & this`first ) return false;
     324                while ( tE & it = iter( this ); advance( it ) ) {
     325                        if ( & lagElem == 0p &&  &it != & first( this ) ) return false;
    346326                        &lagElem = &it;
    347327                }
    348328
    349                 if ( &lagElem != &this`last ) return false;
    350 
    351                 // TODO: verify that it is back at this`elems;
     329                if ( &lagElem != &last( this ) ) return false;
     330
     331                // TODO: verify that it is back at iter( this );
    352332                return true;
    353333        }
    354334
    355335        bool $validate_rev( dlist( tE, tLinks ) & this ) {
    356                 if ( ! & this`last ) return &this`first == 0p;
     336                if ( ! & last( this ) ) return &first( this ) == 0p;
    357337
    358338                tE & lagElem = *0p;
    359                 while ( tE & it = this`elems; it`movePrev ) {
    360                         if ( &lagElem == 0p && &it != & this`last ) return false;
     339                while ( tE & it = iter( this ); recede( it ) ) {
     340                        if ( &lagElem == 0p && &it != & last( this ) ) return false;
    361341                        &lagElem = &it;
    362342                }
    363343
    364                 if ( &lagElem != &this`first ) return false;
    365 
    366                 // TODO: verify that it is back at this`elems;
     344                if ( &lagElem != &first( this ) ) return false;
     345
     346                // TODO: verify that it is back at iter( this );
    367347                return true;
    368348        }
     
    375355
    376356// TEMPORARY, until foreach statement created.
    377 #define FOREACH( list, index ) for ( typeof((list)`head) & (index) = (list)`head; (index)`next; )
    378 #define FOREACH_REV( list, index ) for ( typeof((list)`head) & (index) = (list)`head; (index)`prev; )
    379 #define FOREACH_COND( list, index, expr ) for ( typeof((list)`head) & (index) = (list)`head; (index)`next && !(expr); )
    380 #define FOREACH_REV_COND( list, index, expr ) for ( typeof((list)`head) & (index) = (list)`head; (index)`prev && !(expr); )
     357#define FOREACH( list, index ) for ( typeof(iter( list )) & (index) = iter( list ); advance( index ); )
     358#define FOREACH_REV( list, index ) for ( typeof(iter( list )) & (index) = iter( list ); recede( index ); )
     359#define FOREACH_COND( list, index, expr ) for ( typeof(iter( list )) & (index) = iter( list ); advance( index ) && !(expr); )
     360#define FOREACH_REV_COND( list, index, expr ) for ( typeof(iter( list )) & (index) = iter( list ); recede( index ) && !(expr); )
  • libcfa/src/collections/lockfree.hfa

    rb195498 r6b33e89  
    1616        };
    1717
    18         static inline void ?{}(mcs_queue(T) & this) { this.tail = 0p; }
    19         static inline bool empty(const mcs_queue(T) & this) { return !this.tail; }
    20 
    21         static inline forall(| { T * volatile & ?`next ( T * ); })
    22         {
     18        static inline void ?{}( mcs_queue(T) & this ) { this.tail = 0p; }
     19        static inline bool empty( const mcs_queue(T) & this ) { return ! this.tail; }
     20
     21        static inline forall( | { T * volatile & next ( T * ); }) {
    2322                // Adds an element to the list
    2423                // Multi-Thread Safe, Lock-Free
    25                 T * push(mcs_queue(T) & this, T * elem) __attribute__((artificial));
    26                 T * push(mcs_queue(T) & this, T * elem) {
    27                         /* paranoid */ verify(!(elem`next));
     24                T * push( mcs_queue(T) & this, T * elem ) __attribute__((artificial));
     25                T * push( mcs_queue(T) & this, T * elem ) {
     26                        /* paranoid */ verify( ! next( elem ) );
    2827                        // Race to add to the tail
    29                         T * prev = __atomic_exchange_n(&this.tail, elem, __ATOMIC_SEQ_CST);
     28                        T * prev_val = __atomic_exchange_n(&this.tail, elem, __ATOMIC_SEQ_CST);
    3029                        // If we aren't the first, we need to tell the person before us
    3130                        // No need to
    32                         if (prev) prev`next = elem;
    33                         return prev;
     31                        if ( prev_val ) next( prev_val ) = elem;
     32                        return prev_val;
    3433                }
    3534
     
    3736                // Passing an element that is not the head is undefined behavior
    3837                // NOT Multi-Thread Safe, concurrent pushes are safe
    39                 T * advance(mcs_queue(T) & this, T * elem) __attribute__((artificial));
    40                 T * advance(mcs_queue(T) & this, T * elem) {
     38                T * advance( mcs_queue(T) & this, T * elem ) __attribute__((artificial));
     39                T * advance( mcs_queue(T) & this, T * elem ) {
    4140                        T * expected = elem;
    4241                        // Check if this is already the last item
     
    4443
    4544                        // If not wait for next item to show-up, filled by push
    46                         while (!(elem`next)) Pause();
     45                        while ( ! next( elem ) ) Pause();
    4746
    4847                        // we need to return if the next link was empty
    49                         T * ret = elem`next;
     48                        T * ret = next( elem );
    5049
    5150                        // invalidate link to reset to initial state
    52                         elem`next = 0p;
     51                        next( elem ) = 0p;
    5352                        return ret;
    5453                }
     
    6564        };
    6665
    67         static inline void ?{}(mpsc_queue(T) & this) {
     66        static inline void ?{}( mpsc_queue(T) & this ) {
    6867                ((mcs_queue(T)&)this){};
    6968                this.head = 0p;
    7069        }
    7170
    72         static inline forall(| { T * volatile & ?`next ( T * ); })
    73         {
     71        static inline forall( | { T * volatile & next ( T * ); }) {
    7472                // Added a new element to the queue
    7573                // Multi-Thread Safe, Lock-Free
    76                 T * push(mpsc_queue(T) & this, T * elem) __attribute__((artificial));
    77                 T * push(mpsc_queue(T) & this, T * elem) {
    78                         T * prev = push((mcs_queue(T)&)this, elem);
    79                         if (!prev) this.head = elem;
    80                         return prev;
     74                T * push( mpsc_queue(T) & this, T * elem ) __attribute__((artificial));
     75                T * push( mpsc_queue(T) & this, T * elem ) {
     76                        T * prev_val = push( (mcs_queue(T)&)this, elem );
     77                        if ( ! prev_val ) this.head = elem;
     78                        return prev_val;
    8179                }
    8280
    8381                // Pop an element from the queue
    8482                // return the element that was removed
    85                 // next is set to the new head of the queue
     83                // head is set to the new head of the queue
    8684                // NOT Multi-Thread Safe
    87                 T * pop(mpsc_queue(T) & this, T *& next) __attribute__((artificial));
    88                 T * pop(mpsc_queue(T) & this, T *& next) {
     85                T * pop( mpsc_queue(T) & this, T *& head ) __attribute__((artificial));
     86                T * pop( mpsc_queue(T) & this, T *& head ) {
    8987                        T * elem = this.head;
    9088                        // If head is empty just return
    91                         if (!elem) return 0p;
     89                        if ( ! elem ) return 0p;
    9290
    9391                        // If there is already someone in the list, then it's easy
    94                         if (elem`next) {
    95                                 this.head = next = elem`next;
     92                        if ( next( elem ) ) {
     93                                this.head = head = next( elem );
    9694                                // force memory sync
    9795                                __atomic_thread_fence(__ATOMIC_SEQ_CST);
    9896
    9997                                // invalidate link to reset to initial state
    100                                 elem`next = 0p;
     98                                next( elem ) = 0p;
    10199                        }
    102100                        // Otherwise, there might be a race where it only looks but someone is enqueuing
     
    106104                                // after that point, it could overwrite the write in push
    107105                                this.head = 0p;
    108                                 next = advance((mcs_queue(T)&)this, elem);
     106                                head = advance( (mcs_queue(T)&)this, elem );
    109107
    110108                                // Only write to the head if there is a next element
    111109                                // it is the only way we can guarantee we are not overwriting
    112110                                // a write made in push
    113                                 if (next) this.head = next;
    114                         }
    115 
     111                                if ( head ) this.head = head;
     112                        }
    116113                        // return removed element
    117114                        return elem;
     
    119116
    120117                // Same as previous function
    121                 T * pop(mpsc_queue(T) & this) {
     118                T * pop( mpsc_queue(T) & this ) {
    122119                        T * _ = 0p;
    123120                        return pop(this, _);
     
    144141        static inline bool is_poisoned( const poison_list(T) & this ) { return 1p == this.head; }
    145142
    146         static inline forall(| { T * volatile & ?`next ( T * ); })
     143        static inline forall( | { T * volatile & next( T * ); })
    147144        {
    148145                // Adds an element to the list
    149146                // Multi-Thread Safe, Lock-Free
    150                 bool push(poison_list(T) & this, T * elem) __attribute__((artificial));
    151                 bool push(poison_list(T) & this, T * elem) {
    152                         /* paranoid */ verify(0p == (elem`next));
    153                         __atomic_store_n( &elem`next, (T*)1p, __ATOMIC_RELAXED );
     147                bool push( poison_list(T) & this, T * elem ) __attribute__((artificial));
     148                bool push( poison_list(T) & this, T * elem ) {
     149                        /* paranoid */ verify( 0p == next( elem ) );
     150                        __atomic_store_n( &next( elem ), (T *)1p, __ATOMIC_RELAXED );
    154151
    155152                        // read the head up-front
     
    164161
    165162                                        // We should never succeed the CAS if it's poisonned and the elem should be 1p.
    166                                         /* paranoid */ verify( expected  != 1p );
    167                                         /* paranoid */ verify( elem`next == 1p );
     163                                        /* paranoid */ verify( expected != 1p );
     164                                        /* paranoid */ verify( next( elem ) == 1p );
    168165
    169166                                        // If we aren't the first, we need to tell the person before us
    170167                                        // No need to
    171                                         elem`next = expected;
     168                                        next( elem ) = expected;
    172169                                        return true;
    173170                                }
     
    178175                // Passing an element that is not the head is undefined behavior
    179176                // NOT Multi-Thread Safe, concurrent pushes are safe
    180                 T * advance(T * elem) __attribute__((artificial));
    181                 T * advance(T * elem) {
     177                T * advance( T * elem ) __attribute__((artificial));
     178                T * advance( T * elem ) {
    182179                        T * ret;
    183180
    184181                        // Wait for next item to show-up, filled by push
    185                         while (1p == (ret = __atomic_load_n(&elem`next, __ATOMIC_RELAXED))) Pause();
     182                        while (1p == (ret = __atomic_load_n( &next( elem ), __ATOMIC_RELAXED ) ) ) Pause();
    186183
    187184                        return ret;
     
    189186
    190187                // Poison the queue, preveting new pushes and returning the head
    191                 T * poison(poison_list(T) & this) __attribute__((artificial));
    192                 T * poison(poison_list(T) & this) {
     188                T * poison( poison_list(T) & this ) __attribute__((artificial));
     189                T * poison( poison_list(T) & this ) {
    193190                        T * ret = __atomic_exchange_n( &this.head, (T*)1p, __ATOMIC_SEQ_CST );
    194191                        /* paranoid */ verifyf( ret != (T*)1p, "Poison list %p poisoned more than once!", &this );
     
    215212}; // Link
    216213
    217 forall( T /*| sized(T)*/ | { Link(T) * ?`next( T * ); } ) {
     214forall( T /*| sized(T)*/ | { Link(T) * next( T * ); } ) {
    218215        struct StackLF {
    219216                Link(T) stack;
     
    226223
    227224                void push( StackLF(T) & this, T & n ) with(this) {
    228                         *( &n )`next = stack;                                           // atomic assignment unnecessary, or use CAA
     225                        *next( &n ) = stack;                                            // atomic assignment unnecessary, or use CAA
    229226                        for () {                                                                        // busy wait
    230                                 if ( __atomic_compare_exchange_n( &stack.atom, &( &n )`next->atom, (Link(T))@{ (LinkData(T))@{ &n, ( &n )`next->data.count + 1} }.atom, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) break; // attempt to update top node
     227                                if ( __atomic_compare_exchange_n( &stack.atom, &next( &n )->atom, (Link(T))@{ (LinkData(T))@{ &n, next( &n )->data.count + 1} }.atom, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) break; // attempt to update top node
    231228                        } // for
    232229                } // push
     
    236233                        for () {                                                                        // busy wait
    237234                                if ( t.data.top == 0p ) return 0p;              // empty stack ?
    238                                 Link(T) * next = ( t.data.top )`next;
     235                                Link(T) * next = next( t.data.top );
    239236                                if ( __atomic_compare_exchange_n( &stack.atom, &t.atom, (Link(T))@{ (LinkData(T))@{ next->data.top, t.data.count } }.atom, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) return t.data.top; // attempt to update top node
    240237                        } // for
     
    246243                                // TODO: Avoiding some problems with double fields access.
    247244                                LinkData(T) * data = &link->data;
    248                                 T * next = (T *)&(*data).top;
    249                                 if ( next == node ) {
    250                                         data->top = ( node )`next->data.top;
     245                                T * ntop = (T *)&(*data).top;
     246                                if ( ntop == node ) {
     247                                        data->top = next( node )->data.top;
    251248                                        return true;
    252249                                }
    253                                 if ( next == 0p ) return false;
    254                                 link = ( next )`next;
     250                                if ( ntop == 0p ) return false;
     251                                link = next( ntop );
    255252                        }
    256253                }
  • libcfa/src/collections/vector2.hfa

    rb195498 r6b33e89  
    1010// Created On       : Thu Jun 23 22:00:00 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 14 08:40:53 2023
    13 // Update Count     : 2
     12// Last Modified On : Wed Apr 23 14:39:51 2025
     13// Update Count     : 6
    1414//
    1515
     
    254254        }
    255255
    256         while ( vector_permit(T) & liveIter = this.live_iters_$`elems; liveIter`moveNext ) {
     256        while ( vector_permit(T) & liveIter = iter( this.live_iters_$ ); advance( liveIter ) ) {
    257257            liveIter.item_$ += (newItems - this.buffer_first_$);
    258258        }
     
    350350        *insertTarget = val;
    351351
    352         while ( vector_permit(T) & liveIter = col.live_iters_$`elems; liveIter`moveNext ) {
     352        while ( vector_permit(T) & liveIter = iter( col.live_iters_$ ); advance( liveIter ) ) {
    353353            if ( inRange_$(liveIter.item_$, insertTarget, col.elems_end_$) ) {
    354354                liveIter.item_$ += 1;
Note: See TracChangeset for help on using the changeset viewer.