- Timestamp:
- Mar 24, 2026, 10:50:51 PM (7 days ago)
- Branches:
- master
- Children:
- e426c6f
- Parents:
- 402f249
- Location:
- libcfa/src/collections
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/collections/list.hfa
r402f249 r6cbc5a62 10 10 // Created On : Wed Apr 22 18:00:00 2020 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Aug 7 10:46:08 202513 // Update Count : 7512 // Last Modified On : Tue Mar 24 11:25:34 2026 13 // Update Count : 98 14 14 // 15 15 … … 72 72 73 73 // 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 "advance" as 75 // the first step, and uses the return of "advance" as a guard, before dereferencing the iterator. So normal76 // consumption of an iterator does not dereference an iterator in origin position. The value of a pointer (underlying a77 // refence) that is exposed publicly as an iteraor, and also a pointer stored internally in a link field, is tagged, to78 // indicate "is the origin" (internally, is the list-head sentinel node), or untagged, to indicate "is a regular node."79 // Intent is to help a user who dereferences an iterator in origin position (which would be an API-use error on their80 // part), byfailing fast.74 // and at the end of iteration, signifying, "no more elements." Normal comsumption of an iterator runs "advance" as the 75 // first step, and uses the return of "advance" as a guard, before dereferencing the iterator. So normal consumption of 76 // an iterator does not dereference an iterator in origin position. The value of a pointer (underlying a refence) that 77 // is exposed publicly as an iteraor, and also a pointer stored internally in a link field, is tagged, to indicate "is 78 // the origin" (internally, is the list-head sentinel node), or untagged, to indicate "is a regular node." Intent is to 79 // help a user who dereferences an iterator in origin position (which would be an API-use error on their part), by 80 // failing fast. 81 81 82 82 #ifdef __EXPERIMENTAL_DISABLE_OTAG__ // Perf experimention alt mode 83 83 84 // With origin tagging disabled, iteration never reports "no more elements."85 // In this mode, the list API is buggy.86 // This mode is used to quantify the cost of the normal tagging scheme.87 88 #define ORIGIN_TAG_SET(p) (p)89 #define ORIGIN_TAG_CLEAR(p) (p)90 #define ORIGIN_TAG_QUERY(p) 091 #define ORIGIN_TAG_ASGN(p, v) (p)92 #define ORIGIN_TAG_EITHER(p, v) (p)93 #define ORIGIN_TAG_NEQ(v1, v2) 084 // With origin tagging disabled, iteration never reports "no more elements." 85 // In this mode, the list API is buggy. 86 // This mode is used to quantify the cost of the normal tagging scheme. 87 88 #define ORIGIN_TAG_SET(p) (p) 89 #define ORIGIN_TAG_CLEAR(p) (p) 90 #define ORIGIN_TAG_QUERY(p) 0 91 #define ORIGIN_TAG_ASGN(p, v) (p) 92 #define ORIGIN_TAG_EITHER(p, v) (p) 93 #define ORIGIN_TAG_NEQ(v1, v2) 0 94 94 95 95 #else // Normal 96 96 97 #if defined( __x86_64 )98 // Preferred case: tag in the most-significant bit. Dereference99 // has been shown to segfault consistently. Maintenance should100 // list more architectures as "ok" here, to let them use the101 // preferred case, when valid.102 #define ORIGIN_TAG_BITNO ( 8 * sizeof( size_t ) - 1 )103 #else104 // Fallback case: tag in the least-significant bit. Dereference105 // will often give an alignment error, but may not, e.g. if106 // accessing a char-typed member. 32-bit x86 uses the most-107 // significant bit for real room on the heap.108 #define ORIGIN_TAG_BITNO 0109 #endif110 111 #define ORIGIN_TAG_MASK (((size_t)1) << ORIGIN_TAG_BITNO)112 113 #define ORIGIN_TAG_SET(p) ((p) | ORIGIN_TAG_MASK)114 #define ORIGIN_TAG_CLEAR(p) ((p) & ~ORIGIN_TAG_MASK)115 #define ORIGIN_TAG_QUERY(p) ((p) & ORIGIN_TAG_MASK)116 117 #define ORIGIN_TAG_ASGN(p, v) ( \118 verify( ! ORIGIN_TAG_QUERY(p) && "p had no tagbit" ), \119 ORIGIN_TAG_EITHER((p), (v)) \120 )121 122 #define ORIGIN_TAG_EITHER(p, v) ( \123 verify( ! ORIGIN_TAG_CLEAR(v) && "v is a pure tagbit" ), \124 ( (p) | (v) ) \125 )126 127 #define ORIGIN_TAG_NEQ(v1, v2) ( \128 verify( ! ORIGIN_TAG_CLEAR(v1) && "v1 is a pure tagbit" ), \129 verify( ! ORIGIN_TAG_CLEAR(v2) && "v2 is a pure tagbit" ), \130 ( (v1) ^ (v2) ) \131 )97 #if defined( __x86_64 ) 98 // Preferred case: tag in the most-significant bit. Dereference 99 // has been shown to segfault consistently. Maintenance should 100 // list more architectures as "ok" here, to let them use the 101 // preferred case, when valid. 102 #define ORIGIN_TAG_BITNO ( 8 * sizeof( size_t ) - 1 ) 103 #else 104 // Fallback case: tag in the least-significant bit. Dereference 105 // will often give an alignment error, but may not, e.g. if 106 // accessing a char-typed member. 32-bit x86 uses the most- 107 // significant bit for real room on the heap. 108 #define ORIGIN_TAG_BITNO 0 109 #endif 110 111 #define ORIGIN_TAG_MASK (((size_t)1) << ORIGIN_TAG_BITNO) 112 113 #define ORIGIN_TAG_SET(p) ((p) | ORIGIN_TAG_MASK) 114 #define ORIGIN_TAG_CLEAR(p) ((p) & ~ORIGIN_TAG_MASK) 115 #define ORIGIN_TAG_QUERY(p) ((p) & ORIGIN_TAG_MASK) 116 117 #define ORIGIN_TAG_ASGN(p, v) ( \ 118 verify( ! ORIGIN_TAG_QUERY(p) && "p had no tagbit" ), \ 119 ORIGIN_TAG_EITHER((p), (v)) \ 120 ) 121 122 #define ORIGIN_TAG_EITHER(p, v) ( \ 123 verify( ! ORIGIN_TAG_CLEAR(v) && "v is a pure tagbit" ), \ 124 ( (p) | (v) ) \ 125 ) 126 127 #define ORIGIN_TAG_NEQ(v1, v2) ( \ 128 verify( ! ORIGIN_TAG_CLEAR(v1) && "v1 is a pure tagbit" ), \ 129 verify( ! ORIGIN_TAG_CLEAR(v2) && "v2 is a pure tagbit" ), \ 130 ( (v1) ^ (v2) ) \ 131 ) 132 132 133 133 #endif 134 134 135 135 136 137 136 #ifdef __EXPERIMENTAL_LOOSE_SINGLES__ // Perf experimention alt mode 138 137 139 // In loose-singles mode, the ability to answer an "is listed" query is disabled, as is "to insert an element,140 // it must not be listed already" checking. The user must know separately whether an element is listed.141 // Other than inserting it, any list-api action on an unlisted element is undefined. Notably, list iteration142 // starting from an unlisted element is not defined to respond "no more elements," and may instead continue143 // iterating from a formerly occupied list position. This mode matches LQ usage.144 145 #define NOLOOSE(...)146 #define LOOSEONLY(...) __VA_ARGS__138 // In loose-singles mode, the ability to answer an "is listed" query is disabled, as is "to insert an element, 139 // it must not be listed already" checking. The user must know separately whether an element is listed. 140 // Other than inserting it, any list-api action on an unlisted element is undefined. Notably, list iteration 141 // starting from an unlisted element is not defined to respond "no more elements," and may instead continue 142 // iterating from a formerly occupied list position. This mode matches LQ usage. 143 144 #define NOLOOSE(...) 145 #define LOOSEONLY(...) __VA_ARGS__ 147 146 148 147 #else // Normal 149 148 150 #define NOLOOSE(...) __VA_ARGS__151 #define LOOSEONLY(...)149 #define NOLOOSE(...) __VA_ARGS__ 150 #define LOOSEONLY(...) 152 151 153 152 #endif … … 190 189 static inline forall( tE &, tLinks & | embedded( tE, tLinks, dlink( tE ) ) ) { 191 190 bool isListed( tE & node ) { 192 NOLOOSE(191 NOLOOSE( 193 192 verify( &node != 0p ); 194 193 dlink( tE ) & node_links = node`inner; … … 196 195 ) 197 196 LOOSEONLY( 198 verify(false && "isListed is undefined");197 verify(false && "isListed is undefined"); 199 198 return true; 200 199 ) … … 224 223 225 224 dlink( tE ) & linkToInsert = node`inner; 226 NOLOOSE(225 NOLOOSE( 227 226 verify( linkToInsert.next == 0p ); 228 227 verify( linkToInsert.prev == 0p ); … … 242 241 return node; 243 242 } 243 // FIXME: Change from pointer to reference for node, when tuple type can handle references. 244 forall( List ... | { void insert_before( tE & before, List ); } ) 245 void insert_before( tE & before, tE * node, List args ) { 246 insert_before( before, *node ); 247 insert_before( before, args ); 248 } 249 void insert_before( tE & before, tE * node ) { 250 insert_before( before, *node ); 251 } 244 252 245 253 tE & insert_after( tE & after, tE & node ) { … … 248 256 249 257 dlink( tE ) & linkToInsert = node`inner; 250 NOLOOSE(258 NOLOOSE( 251 259 verify( linkToInsert.prev == 0p ); 252 260 verify( linkToInsert.next == 0p ); … … 265 273 asm( "" : : : "memory" ); 266 274 return node; 275 } 276 // FIXME: Change from pointer to reference for node, when tuple type can handle references. 277 forall( List ... | { void insert_after( tE & after, List ); } ) 278 void insert_after( tE & after, tE * node, List args ) { 279 insert_after( after, *node ); 280 insert_after( after, args ); 281 } 282 void insert_after( tE & after, tE * node ) { 283 insert_after( after, *node ); 267 284 } 268 285 … … 281 298 after_links.prev = &before_raw; 282 299 283 NOLOOSE(300 NOLOOSE( 284 301 asm( "" : : : "memory" ); 285 302 list_pos_links.prev = 0p; … … 288 305 ) 289 306 return node; 307 } 308 // FIXME: Change from pointer to reference for node, when tuple type can handle references. 309 forall( List ... | { void remove( List ); } ) 310 void remove( tE * node, List args ) { 311 remove( *node ); 312 remove( args ); 313 } 314 void remove( tE * node ) { 315 remove( *node ); 290 316 } 291 317 … … 309 335 } 310 336 311 bool isFirst( tE & node ) {312 return recede( node );313 }314 315 bool isLast( tE & node ) {316 return advance( node );337 bool isFirst( tE & node ) { 338 return recede( node ); 339 } 340 341 bool isLast( tE & node ) { 342 return advance( node ); 317 343 } 318 344 … … 331 357 return node; 332 358 } 359 // FIXME: Change from pointer to reference for node, when tuple type can handle references. 360 forall( List ... | { void insert_first( dlist( tE, tLinks ) & list, List ); } ) 361 void insert_first( dlist( tE, tLinks ) & list, tE * node, List args ) { 362 insert_first( list, *node ); 363 insert_first( list, args ); 364 } 365 void insert_first( dlist( tE, tLinks ) & list, tE * node ) { 366 insert_first( list, *node ); 367 } 333 368 334 369 tE & insert_last( dlist( tE, tLinks ) & list, tE & node ) { … … 336 371 return node; 337 372 } 373 // FIXME: Change from pointer to reference for node, when tuple type can handle references. 374 forall( List ... | { void insert_last( dlist( tE, tLinks ) & list, List ); } ) 375 void insert_last( dlist( tE, tLinks ) & list, tE * node, List args ) { 376 insert_last( list, *node ); 377 insert_last( list, args ); 378 } 379 void insert_last( dlist( tE, tLinks ) & list, tE * node ) { 380 insert_last( list, *node ); 381 } 382 338 383 tE & insert( dlist( tE, tLinks ) & list, tE & node ) { // synonym for insert_last 339 384 insert_last( list, node ); 340 385 return node; 386 } 387 // FIXME: Change from pointer to reference for node, when tuple type can handle references. 388 forall( List ... | { void insert( dlist( tE, tLinks ) & list, List ); } ) 389 void insert( dlist( tE, tLinks ) & list, tE * node, List args ) { 390 insert( list, *node ); 391 insert( list, args ); 392 } 393 void insert( dlist( tE, tLinks ) & list, tE * node ) { 394 insert( list, *node ); 341 395 } 342 396 -
libcfa/src/collections/list2.hfa
r402f249 r6cbc5a62 19 19 // Created On : Wed Apr 22 18:00:00 2020 20 20 // Last Modified By : Peter A. Buhr 21 // Last Modified On : T hu Feb 2 11:32:26 202322 // Update Count : 221 // Last Modified On : Tue Mar 24 22:20:56 2026 22 // Update Count : 8 23 23 // 24 24 … … 29 29 forall( Decorator &, T & ) 30 30 struct tytagref { 31 inline T &;31 inline T &; 32 32 }; 33 33 34 34 forall( tOuter &, tMid &, tInner & ) 35 35 trait embedded { 36 tytagref( tMid, tInner ) ?`inner( tOuter & );36 tytagref( tMid, tInner ) ?`inner( tOuter & ); 37 37 }; 38 38 39 39 // embedded is reflexive, with no info (void) as the type tag 40 forall (T &)40 forall( T & ) 41 41 static inline tytagref(void, T) ?`inner ( T & this ) { tytagref( void, T ) ret = {this}; return ret; } 42 42 … … 46 46 // 47 47 // struct foo { 48 // int a, b, c;49 // inline (bar);48 // int a, b, c; 49 // inline (bar); 50 50 // }; 51 51 // P9_EMBEDDED( foo, bar ) … … 53 53 54 54 // usual version, for structs that are top-level declarations 55 #define P9_EMBEDDED( derived, immedBase ) P9_EMBEDDED_DECL_( derived, immedBase, static ) P9_EMBEDDED_BDY_( immedBase )55 #define P9_EMBEDDED( derived, immedBase ) P9_EMBEDDED_DECL_( derived, immedBase, static ) P9_EMBEDDED_BDY_( immedBase ) 56 56 57 57 // special version, for structs that are declared in functions 58 #define P9_EMBEDDED_INFUNC( derived, immedBase ) P9_EMBEDDED_DECL_( derived, immedBase, ) P9_EMBEDDED_BDY_( immedBase )58 #define P9_EMBEDDED_INFUNC( derived, immedBase ) P9_EMBEDDED_DECL_( derived, immedBase, ) P9_EMBEDDED_BDY_( immedBase ) 59 59 60 60 // forward declarations of both the above; generally not needed 61 61 // may help you control where the P9_EMBEEDED cruft goes, in case "right after the stuct" isn't where you want it 62 #define P9_EMBEDDED_FWD( derived, immedBase )P9_EMBEDDED_DECL_( derived, immedBase, static ) ;63 #define P9_EMBEDDED_FWD_INFUNC( derived, immedBase ) auto P9_EMBEDDED_DECL_( derived, immedBase, ) ;62 #define P9_EMBEDDED_FWD( derived, immedBase ) P9_EMBEDDED_DECL_( derived, immedBase, static ) ; 63 #define P9_EMBEDDED_FWD_INFUNC( derived, immedBase ) auto P9_EMBEDDED_DECL_( derived, immedBase, ) ; 64 64 65 65 // private helpers 66 66 #define P9_EMBEDDED_DECL_( derived, immedBase, STORAGE ) \ 67 forall( Tbase &, TdiscardPath & | { tytagref( TdiscardPath, Tbase ) ?`inner( immedBase & ); } ) \68 STORAGE inline tytagref(immedBase, Tbase) ?`inner( derived & this )69 67 forall( Tbase &, TdiscardPath & | { tytagref( TdiscardPath, Tbase ) ?`inner( immedBase & ); } ) \ 68 STORAGE inline tytagref( immedBase, Tbase ) ?`inner( derived & this ) 69 70 70 #define P9_EMBEDDED_BDY_( immedBase ) { \ 71 immedBase & ib = this; \ 72 Tbase & b = ib`inner; \ 73 tytagref(immedBase, Tbase) result = { b }; \ 74 return result; \ 75 } 76 77 #define EMBEDDED_VIA( OUTER, MID, INNER ) \ 78 (struct { tytagref(MID, INNER) ( * ?`inner ) ( OUTER & ); }){ ?`inner } 79 80 #define DLINK_VIA( TE, TLINK ) \ 81 EMBEDDED_VIA( TE, TLINK, dlink(TE) ) 82 83 // The origin is the position encountered at the start of iteration, 84 // signifying, "need to advance to the first element," and at the end 85 // of iteration, signifying, "no more elements." Normal comsumption of 86 // an iterator runs advance as the first step, and uses the return 87 // of advance as a guard, before dereferencing the iterator. So 88 // normal consumption of an iterator does not dereference an iterator 89 // in origin position. The value of a pointer (underlying a refence) 90 // that is exposed publicly as an iteraor, and also a pointer stored 91 // internally in a link field, is tagged, to indicate "is the origin" 92 // (internally, is the list-head sentinel node), or untagged, to indicate 93 // "is a regular node." Intent is to help a user who dereferences an 94 // iterator in origin position (which would be an API-use error on their 95 // part), by failing fast. 71 immedBase & ib = this; \ 72 Tbase & b = ib`inner; \ 73 tytagref( immedBase, Tbase ) result = { b }; \ 74 return result; \ 75 } 76 77 #define EMBEDDED_VIA( OUTER, MID, INNER ) (struct { tytagref( MID, INNER ) ( * ?`inner ) ( OUTER & ); }){ ?`inner } 78 79 #define DLINK_VIA( TE, TLINK ) EMBEDDED_VIA( TE, TLINK, dlink( TE ) ) 80 81 82 // The origin is the position encountered at the start of iteration, signifying, "need to advance to the first element," 83 // and at the end of iteration, signifying, "no more elements." Normal comsumption of an iterator runs "advance" as the 84 // first step, and uses the return of "advance" as a guard, before dereferencing the iterator. So normal consumption of 85 // an iterator does not dereference an iterator in origin position. The value of a pointer (underlying a refence) that 86 // is exposed publicly as an iteraor, and also a pointer stored internally in a link field, is tagged, to indicate "is 87 // the origin" (internally, is the list-head sentinel node), or untagged, to indicate "is a regular node." Intent is to 88 // help a user who dereferences an iterator in origin position (which would be an API-use error on their part), by 89 // failing fast. 96 90 97 91 #ifdef __EXPERIMENTAL_DISABLE_OTAG__ // Perf experimention alt mode 98 92 99 // With origin tagging disabled, iteration never reports "no more elements."100 // In this mode, the list API is buggy.101 // This mode is used to quantify the cost of the normal tagging scheme.102 103 #define ORIGIN_TAG_ENABL(p) (p)104 #define ORIGIN_TAG_CLEAR(p) (p)105 #define ORIGIN_TAG_QUERY(p) 0106 #define ORIGIN_TAG_ASGN(p, v) (p)107 #define ORIGIN_TAG_EITHER(p, v) (p)108 #define ORIGIN_TAG_NEQ(v1, v2) 0109 110 #define TAGSONLY(...)111 #define NOTAGS(...) __VA_ARGS__93 // With origin tagging disabled, iteration never reports "no more elements." 94 // In this mode, the list API is buggy. 95 // This mode is used to quantify the cost of the normal tagging scheme. 96 97 #define ORIGIN_TAG_ENABL(p) (p) 98 #define ORIGIN_TAG_CLEAR(p) (p) 99 #define ORIGIN_TAG_QUERY(p) 0 100 #define ORIGIN_TAG_ASGN(p, v) (p) 101 #define ORIGIN_TAG_EITHER(p, v) (p) 102 #define ORIGIN_TAG_NEQ(v1, v2) 0 103 104 #define TAGSONLY(...) 105 #define NOTAGS(...) __VA_ARGS__ 112 106 113 107 #else // Normal 114 108 115 #if defined( __x86_64 )116 // Preferred case: tag in the most-significant bit. Dereference117 // has been shown to segfault consistently. Maintenance should118 // list more architectures as "ok" here, to let them use the119 // preferred case, when valid.120 #define ORIGIN_TAG_BITNO ( 8 * sizeof( size_t ) - 1 )121 #else122 // Fallback case: tag in the least-significant bit. Dereference123 // will often give an alignment error, but may not, e.g. if124 // accessing a char-typed member. 32-bit x86 uses the most-125 // significant bit for real room on the heap.126 #define ORIGIN_TAG_BITNO 0127 #endif128 129 #define ORIGIN_TAG_MASK (((size_t)1) << ORIGIN_TAG_BITNO)130 131 #define ORIGIN_TAG_ENABL(p) ((p) | ORIGIN_TAG_MASK)132 #define ORIGIN_TAG_CLEAR(p) ((p) & ~ORIGIN_TAG_MASK)133 #define ORIGIN_TAG_QUERY(p) ((p) & ORIGIN_TAG_MASK)134 135 #define ORIGIN_TAG_ASGN(p, v) ( \136 verify( ! ORIGIN_TAG_QUERY(p) && "p had no tagbit" ), \137 ORIGIN_TAG_EITHER((p), (v)) \138 )139 140 #define ORIGIN_TAG_EITHER(p, v) ( \141 verify( ! ORIGIN_TAG_CLEAR(v) && "v is a pure tagbit" ), \142 ( (p) | (v) ) \143 )144 145 #define ORIGIN_TAG_NEQ(v1, v2) ( \146 verify( ! ORIGIN_TAG_CLEAR(v1) && "v1 is a pure tagbit" ), \147 verify( ! ORIGIN_TAG_CLEAR(v2) && "v2 is a pure tagbit" ), \148 ( (v1) ^ (v2) ) \149 )150 151 #define TAGSONLY(...) __VA_ARGS__152 #define NOTAGS(...)109 #if defined( __x86_64 ) 110 // Preferred case: tag in the most-significant bit. Dereference 111 // has been shown to segfault consistently. Maintenance should 112 // list more architectures as "ok" here, to let them use the 113 // preferred case, when valid. 114 #define ORIGIN_TAG_BITNO ( 8 * sizeof( size_t ) - 1 ) 115 #else 116 // Fallback case: tag in the least-significant bit. Dereference 117 // will often give an alignment error, but may not, e.g. if 118 // accessing a char-typed member. 32-bit x86 uses the most- 119 // significant bit for real room on the heap. 120 #define ORIGIN_TAG_BITNO 0 121 #endif 122 123 #define ORIGIN_TAG_MASK (((size_t)1) << ORIGIN_TAG_BITNO) 124 125 #define ORIGIN_TAG_ENABL(p) ((p) | ORIGIN_TAG_MASK) 126 #define ORIGIN_TAG_CLEAR(p) ((p) & ~ORIGIN_TAG_MASK) 127 #define ORIGIN_TAG_QUERY(p) ((p) & ORIGIN_TAG_MASK) 128 129 #define ORIGIN_TAG_ASGN(p, v) ( \ 130 verify( ! ORIGIN_TAG_QUERY(p) && "p had no tagbit" ), \ 131 ORIGIN_TAG_EITHER((p), (v)) \ 132 ) 133 134 #define ORIGIN_TAG_EITHER(p, v) ( \ 135 verify( ! ORIGIN_TAG_CLEAR(v) && "v is a pure tagbit" ), \ 136 ( (p) | (v) ) \ 137 ) 138 139 #define ORIGIN_TAG_NEQ(v1, v2) ( \ 140 verify( ! ORIGIN_TAG_CLEAR(v1) && "v1 is a pure tagbit" ), \ 141 verify( ! ORIGIN_TAG_CLEAR(v2) && "v2 is a pure tagbit" ), \ 142 ( (v1) ^ (v2) ) \ 143 ) 144 145 #define TAGSONLY(...) __VA_ARGS__ 146 #define NOTAGS(...) 153 147 154 148 #endif 155 149 156 150 157 158 159 160 161 151 #ifdef __EXPERIMENTAL_LOOSE_SINGLES__ // Perf experimention alt mode 162 152 163 // In loose-singles mode, the ability to answer an "is listed" query is disabled, as is "to insert an element,164 // it must not be listed already" checking. The user must know separately whether an element is listed.165 // Other than inserting it, any list-api action on an unlisted element is undefined. Notably, list iteration166 // starting from an unlisted element is not defined to respond "no more elements," and may instead continue167 // iterating from a formerly occupied list position. This mode matches LQ usage.168 169 #define NOLOOSE(...)170 #define LOOSEONLY(...) __VA_ARGS__153 // In loose-singles mode, the ability to answer an "is listed" query is disabled, as is "to insert an element, 154 // it must not be listed already" checking. The user must know separately whether an element is listed. 155 // Other than inserting it, any list-api action on an unlisted element is undefined. Notably, list iteration 156 // starting from an unlisted element is not defined to respond "no more elements," and may instead continue 157 // iterating from a formerly occupied list position. This mode matches LQ usage. 158 159 #define NOLOOSE(...) 160 #define LOOSEONLY(...) __VA_ARGS__ 171 161 172 162 #else // Normal 173 163 174 #define NOLOOSE(...) __VA_ARGS__175 #define LOOSEONLY(...)164 #define NOLOOSE(...) __VA_ARGS__ 165 #define LOOSEONLY(...) 176 166 177 167 #endif 178 168 179 169 180 181 182 183 184 185 186 170 // struct workaround0_t {}; 187 171 188 172 forall( tE & ) { 189 190 struct dlink; 191 192 // do not use; presence of the field declaration unblocks ability to define dlink (#304) 193 struct __dlink_selfref_workaround_t { 194 dlink(tE) *ref_notSelfRef; 195 }; 196 197 struct dlink { 198 dlink(tE) *next; // TODO: rename with $ 199 dlink(tE) *prev; 200 }; 201 202 static inline void ?{}( dlink(tE) & this ) { 203 NOLOOSE( 204 dlink(tE) * toSelf = & this; 205 size_t toSelfNum = (size_t) toSelf; 206 size_t toSelfNumTagged = ORIGIN_TAG_ENABL( toSelfNum ); 207 dlink(tE) * toSelfPtrTagged = (dlink(tE) *) toSelfNumTagged; 208 toSelf = toSelfPtrTagged; 209 (this.next){ toSelf }; 210 (this.prev){ toSelf }; 211 ) 212 } 213 214 // You can "copy" a dlink. But the result won't be linked. 215 // Lets you copy what you inline the dlink into. 216 static inline void ?{}( dlink(tE) & this, dlink(tE) ) { 217 this{}; 218 } 219 220 forall( tLinks & = dlink(tE) | embedded(tE, tLinks, dlink(tE)) ) { 221 struct dlist { 222 inline dlink(tE); 223 }; 224 225 static inline tE * $get_list_origin_addr( dlist(tE, tLinks) & lst ) { 226 dlink(tE) & link_from_null = ( * (tE *) 0p )`inner; 227 ptrdiff_t link_offset = (ptrdiff_t) & link_from_null; 228 size_t origin_addr = ((size_t) & lst) - link_offset; 229 size_t preResult = ORIGIN_TAG_ENABL( origin_addr ); 230 return (tE *)preResult; 231 } 232 233 static inline void ?{}( dlist(tE, tLinks) & this ) { 234 NOLOOSE( 235 ( (dlink(tE) &) this ){}; 236 ) 237 LOOSEONLY( 173 struct dlink; 174 175 // do not use; presence of the field declaration unblocks ability to define dlink (#304) 176 struct __dlink_selfref_workaround_t { 177 dlink(tE) *ref_notSelfRef; 178 }; 179 180 struct dlink { 181 dlink(tE) *next; // TODO: rename with $ 182 dlink(tE) *prev; 183 }; 184 185 static inline void ?{}( dlink(tE) & this ) { 186 NOLOOSE( 187 dlink(tE) * toSelf = & this; 188 size_t toSelfNum = (size_t) toSelf; 189 size_t toSelfNumTagged = ORIGIN_TAG_ENABL( toSelfNum ); 190 dlink(tE) * toSelfPtrTagged = (dlink(tE) *) toSelfNumTagged; 191 toSelf = toSelfPtrTagged; 192 (this.next){ toSelf }; 193 (this.prev){ toSelf }; 194 ) 195 } 196 197 // You can "copy" a dlink. But the result won't be linked. 198 // Lets you copy what you inline the dlink into. 199 static inline void ?{}( dlink(tE) & this, dlink(tE) ) { 200 this{}; 201 } 202 203 forall( tLinks & = dlink(tE) | embedded(tE, tLinks, dlink(tE)) ) { 204 struct dlist { 205 inline dlink(tE); 206 }; 207 208 static inline tE * $get_list_origin_addr( dlist(tE, tLinks) & lst ) { 209 dlink(tE) & link_from_null = ( * (tE *) 0p )`inner; 210 ptrdiff_t link_offset = (ptrdiff_t) & link_from_null; 211 size_t origin_addr = ((size_t) & lst) - link_offset; 212 size_t preResult = ORIGIN_TAG_ENABL( origin_addr ); 213 return (tE *)preResult; 214 } 215 216 static inline void ?{}( dlist(tE, tLinks) & this ) { 217 NOLOOSE( 218 ( (dlink(tE) &) this ){}; 219 ) 220 LOOSEONLY( 238 221 dlink(tE) * listOrigin = (dlink(tE) *) $get_list_origin_addr( this ); 239 dlink( tE ) & thisl = this;222 dlink( tE ) & thisl = this; 240 223 (thisl.prev) = listOrigin; 241 (thisl.next) = listOrigin;242 )243 }244 }224 (thisl.next) = listOrigin; 225 ) 226 } 227 } 245 228 } 229 246 230 247 231 forall( tE & ) { 248 232 #ifdef __EXPERIMENTAL_DISABLE_OTAG__ // Perf experimention alt mode 249 static inline size_t origin_tag_query_arith$( tE & raw ) {250 return 0;251 }252 static inline tE & nullif$( tE & val, size_t arith_ctrl ) {253 verify( arith_ctrl == 0 ); (void) arith_ctrl;254 return val;255 }233 static inline size_t origin_tag_query_arith$( tE & raw ) { 234 return 0; 235 } 236 static inline tE & nullif$( tE & val, size_t arith_ctrl ) { 237 verify( arith_ctrl == 0 ); (void) arith_ctrl; 238 return val; 239 } 256 240 #else // Normal 257 // like ORIGIN_TAG_QUERY, but return is arithmetic number 0 or 1 (rather than 0 or non-0)258 static inline size_t origin_tag_query_arith$( tE & raw ) {259 size_t ret = (((size_t) & raw) >> ORIGIN_TAG_BITNO) & 1;260 verify( ORIGIN_TAG_QUERY( (size_t) & raw ) ? ret == 1 : ret == 0 );261 return ret;262 }263 // Requires arith_ctrl being 0 or 1.264 // When 0, passes val through; when 1, returns null reference.265 // Importantly, implemented without jumps or tests.266 static inline tE & nullif$( tE & val, size_t arith_ctrl ) {267 verify( ! ORIGIN_TAG_QUERY( (size_t) & val ) );268 verify( arith_ctrl == 0 || arith_ctrl == 1 );269 size_t mask_ctrl = ~ - arith_ctrl;270 verify( arith_ctrl == 0 && mask_ctrl == -1 || arith_ctrl == 1 && mask_ctrl ==0 );271 tE & ret = * (tE*) ( ((size_t) & val) & mask_ctrl);272 verify( arith_ctrl == 0 && &ret == &val || arith_ctrl == 1 && &ret == 0p );273 return ret;274 }241 // like ORIGIN_TAG_QUERY, but return is arithmetic number 0 or 1 (rather than 0 or non-0) 242 static inline size_t origin_tag_query_arith$( tE & raw ) { 243 size_t ret = (((size_t) & raw) >> ORIGIN_TAG_BITNO) & 1; 244 verify( ORIGIN_TAG_QUERY( (size_t) & raw ) ? ret == 1 : ret == 0 ); 245 return ret; 246 } 247 // Requires arith_ctrl being 0 or 1. 248 // When 0, passes val through; when 1, returns null reference. 249 // Importantly, implemented without jumps or tests. 250 static inline tE & nullif$( tE & val, size_t arith_ctrl ) { 251 verify( ! ORIGIN_TAG_QUERY( (size_t) & val ) ); 252 verify( arith_ctrl == 0 || arith_ctrl == 1 ); 253 size_t mask_ctrl = ~ - arith_ctrl; 254 verify( arith_ctrl == 0 && mask_ctrl == -1 || arith_ctrl == 1 && mask_ctrl ==0 ); 255 tE & ret = * (tE*) ( ((size_t) & val) & mask_ctrl); 256 verify( arith_ctrl == 0 && &ret == &val || arith_ctrl == 1 && &ret == 0p ); 257 return ret; 258 } 275 259 #endif 276 260 } … … 305 289 306 290 forall( tE &, tLinks & | embedded( tE, tLinks, dlink(tE) ) ) { 307 308 static inline void insert_after(tE & list_pos, tE &to_insert) { 309 size_t list_pos_tag = ORIGIN_TAG_QUERY((size_t) & list_pos); // a request to insert after the origin is fine 310 tE & list_pos_real = * (tE *) ORIGIN_TAG_CLEAR((size_t) & list_pos); 291 static inline void insert_before(tE & list_pos, tE &to_insert) { 292 size_t list_pos_tag = ORIGIN_TAG_QUERY((size_t) & list_pos); // a request to insert before the origin is fine 293 tE & list_pos_real = * (tE *) ORIGIN_TAG_CLEAR((size_t) & list_pos); 311 294 verify (&list_pos_real != 0p); 312 295 313 296 verify (&to_insert != 0p); 314 NOLOOSE(297 NOLOOSE( 315 298 verify(! ORIGIN_TAG_QUERY((size_t) & to_insert)); 316 )317 dlink(tE) & linkToInsert = to_insert`inner;318 NOLOOSE(319 TAGSONLY(299 ) 300 dlink(tE) & linkToInsert = to_insert`inner; 301 NOLOOSE( 302 TAGSONLY( 320 303 verify(ORIGIN_TAG_QUERY((size_t)linkToInsert.prev)); 321 304 verify(ORIGIN_TAG_QUERY((size_t)linkToInsert.next)); 322 )305 ) 323 306 verify(ORIGIN_TAG_CLEAR((size_t)linkToInsert.prev) == (size_t)&linkToInsert); 324 307 verify(ORIGIN_TAG_CLEAR((size_t)linkToInsert.next) == (size_t)&linkToInsert); 325 ) 326 dlink(tE) & list_pos_links = list_pos_real`inner; 327 MAYBE_INSERT_READ_EARLY( 328 dlink(tE) & afterLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.next ); 329 ) 330 MAYBE_CMEM_BARRIER; 331 size_t list_pos_links_num = (size_t)(& list_pos_links); 332 size_t to_insert_prev_num = ORIGIN_TAG_ASGN(list_pos_links_num, list_pos_tag); 333 dlink(tE) * to_insert_prev = (dlink(tE)*)to_insert_prev_num; 308 ) 309 dlink(tE) & list_pos_links = list_pos_real`inner; 310 MAYBE_INSERT_READ_EARLY( 311 dlink(tE) & beforeLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.prev ); 312 ) 313 MAYBE_CMEM_BARRIER; 314 size_t list_pos_links_num = (size_t)(& list_pos_links); 315 size_t to_insert_next_num = ORIGIN_TAG_ASGN(list_pos_links_num, list_pos_tag); 316 dlink(tE) * to_insert_next = (dlink(tE)*)to_insert_next_num; 317 linkToInsert.next = to_insert_next; 318 linkToInsert.prev = list_pos_links.prev; 319 MAYBE_INSERT_READ_LATE( 320 dlink(tE) & beforeLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.prev ); 321 ) 322 size_t beforeLinks_next_tag = ORIGIN_TAG_QUERY((size_t)beforeLinks.next); 323 size_t linkToInsert_num = (size_t)(& linkToInsert); 324 size_t beforeLinks_next_num = ORIGIN_TAG_ASGN(linkToInsert_num, ORIGIN_TAG_NEQ(list_pos_tag, beforeLinks_next_tag)); 325 beforeLinks.next = (dlink(tE)*)(beforeLinks_next_num); 326 list_pos_links.prev = &linkToInsert; 327 MAYBE_CMEM_BARRIER; 328 } 329 // FIXME: Change from pointer to reference for node, when tuple type can handle references. 330 forall( List ... | { void insert_before( tE & before, List ); } ) 331 void insert_before( tE & before, tE * node, List args ) { 332 insert_before( before, *node ); 333 insert_before( before, args ); 334 } 335 void insert_before( tE & before, tE * node ) { 336 insert_before( before, *node ); 337 } 338 339 static inline void insert_after(tE & list_pos, tE &to_insert) { 340 size_t list_pos_tag = ORIGIN_TAG_QUERY((size_t) & list_pos); // a request to insert after the origin is fine 341 tE & list_pos_real = * (tE *) ORIGIN_TAG_CLEAR((size_t) & list_pos); 342 verify (&list_pos_real != 0p); 343 344 verify (&to_insert != 0p); 345 NOLOOSE( 346 verify(! ORIGIN_TAG_QUERY((size_t) & to_insert)); 347 ) 348 dlink(tE) & linkToInsert = to_insert`inner; 349 NOLOOSE( 350 TAGSONLY( 351 verify(ORIGIN_TAG_QUERY((size_t)linkToInsert.prev)); 352 verify(ORIGIN_TAG_QUERY((size_t)linkToInsert.next)); 353 ) 354 verify(ORIGIN_TAG_CLEAR((size_t)linkToInsert.prev) == (size_t)&linkToInsert); 355 verify(ORIGIN_TAG_CLEAR((size_t)linkToInsert.next) == (size_t)&linkToInsert); 356 ) 357 dlink(tE) & list_pos_links = list_pos_real`inner; 358 MAYBE_INSERT_READ_EARLY( 359 dlink(tE) & afterLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.next ); 360 ) 361 MAYBE_CMEM_BARRIER; 362 size_t list_pos_links_num = (size_t)(& list_pos_links); 363 size_t to_insert_prev_num = ORIGIN_TAG_ASGN(list_pos_links_num, list_pos_tag); 364 dlink(tE) * to_insert_prev = (dlink(tE)*)to_insert_prev_num; 334 365 linkToInsert.prev = to_insert_prev; 335 366 linkToInsert.next = list_pos_links.next; 336 MAYBE_INSERT_READ_LATE(337 dlink(tE) & afterLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.next );338 )339 size_t afterLinks_prev_tag = ORIGIN_TAG_QUERY((size_t)afterLinks.prev);340 size_t linkToInsert_num = (size_t)(& linkToInsert);341 size_t afterLinks_prev_num = ORIGIN_TAG_ASGN(linkToInsert_num, ORIGIN_TAG_NEQ(list_pos_tag, afterLinks_prev_tag));342 afterLinks.prev = (dlink(tE)*)(afterLinks_prev_num);367 MAYBE_INSERT_READ_LATE( 368 dlink(tE) & afterLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.next ); 369 ) 370 size_t afterLinks_prev_tag = ORIGIN_TAG_QUERY((size_t)afterLinks.prev); 371 size_t linkToInsert_num = (size_t)(& linkToInsert); 372 size_t afterLinks_prev_num = ORIGIN_TAG_ASGN(linkToInsert_num, ORIGIN_TAG_NEQ(list_pos_tag, afterLinks_prev_tag)); 373 afterLinks.prev = (dlink(tE)*)(afterLinks_prev_num); 343 374 list_pos_links.next = &linkToInsert; 344 MAYBE_CMEM_BARRIER; 345 } 346 347 static inline void insert_before(tE & list_pos, tE &to_insert) { 348 size_t list_pos_tag = ORIGIN_TAG_QUERY((size_t) & list_pos); // a request to insert before the origin is fine 349 tE & list_pos_real = * (tE *) ORIGIN_TAG_CLEAR((size_t) & list_pos); 350 verify (&list_pos_real != 0p); 351 352 verify (&to_insert != 0p); 353 NOLOOSE( 354 verify(! ORIGIN_TAG_QUERY((size_t) & to_insert)); 355 ) 356 dlink(tE) & linkToInsert = to_insert`inner; 357 NOLOOSE( 358 TAGSONLY( 375 MAYBE_CMEM_BARRIER; 376 } 377 // FIXME: Change from pointer to reference for node, when tuple type can handle references. 378 forall( List ... | { void insert_after( tE & after, List ); } ) 379 void insert_after( tE & after, tE * node, List args ) { 380 insert_after( after, *node ); 381 insert_after( after, args ); 382 } 383 void insert_after( tE & after, tE * node ) { 384 insert_after( after, *node ); 385 } 386 387 static inline tE & remove(tE & list_pos) { 388 verify( ! ORIGIN_TAG_QUERY((size_t) & list_pos) ); 389 verify (&list_pos != 0p); 390 391 dlink(tE) & list_pos_links = list_pos`inner; 392 dlink(tE) & before_raw = * list_pos_links.prev; 393 dlink(tE) & before_links = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) & before_raw ); 394 size_t before_links_next_tag = ORIGIN_TAG_QUERY( (size_t) (before_links.next) ); 395 396 dlink(tE) & after_raw = * list_pos_links.next; 397 dlink(tE) & after_links = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) & after_raw ); 398 size_t after_links_prev_tag = ORIGIN_TAG_QUERY( (size_t) (after_links.prev) ); 399 400 size_t before_links_next_rslt = ORIGIN_TAG_EITHER( ((size_t) & after_raw), before_links_next_tag ); 401 size_t after_links_prev_rslt = ORIGIN_TAG_EITHER( ((size_t) & before_raw), after_links_prev_tag ); 402 before_links.next = (dlink(tE) *) before_links_next_rslt; 403 after_links.prev = (dlink(tE) *) after_links_prev_rslt; 404 405 NOLOOSE( 406 MAYBE_CMEM_BARRIER; 407 size_t list_pos_links_num = (size_t) &list_pos_links; 408 size_t list_pos_links_tagged_num = ORIGIN_TAG_ENABL( list_pos_links_num ); 409 list_pos_links.next = list_pos_links.prev = (dlink(tE)*) list_pos_links_tagged_num; 410 MAYBE_CMEM_BARRIER; 411 ) 412 return list_pos; 413 } 414 // FIXME: Change from pointer to reference for node, when tuple type can handle references. 415 forall( List ... | { void remove( List ); } ) 416 void remove( tE * node, List args ) { 417 remove( *node ); 418 remove( args ); 419 } 420 void remove( tE * node ) { 421 remove( *node ); 422 } 423 424 static inline tE & downcast$( tytagref( tLinks, dlink(tE) ) ref ) { 425 dlink(tE) & lnk = ref; 426 dlink(tE) & link_from_null = ( * (tE *) 0p )`inner; 427 ptrdiff_t link_offset = (ptrdiff_t) & link_from_null; 428 size_t elm_addr = ((size_t) & lnk) - link_offset; 429 return * (tE*) elm_addr; 430 } 431 432 static inline tE & first( dlist(tE, tLinks) & lst ) { 433 verify (&lst != 0p); 434 dlink(tE) * firstLnk = lst.next; 435 if (ORIGIN_TAG_QUERY((size_t)firstLnk)) return * 0p; 436 tytagref( tLinks, dlink(tE) ) firstLnkTagged = {*firstLnk}; 437 return downcast$( firstLnkTagged ); 438 } 439 static inline tE & last ( dlist(tE, tLinks) & lst ) { 440 verify (&lst != 0p); 441 dlink(tE) * lastLnk = lst.prev; 442 if (ORIGIN_TAG_QUERY((size_t)lastLnk)) return * 0p; 443 tytagref( tLinks, dlink(tE) ) lastLnkTagged = {*lastLnk}; 444 return downcast$( lastLnkTagged ); 445 } 446 447 static inline bool isEmpty( dlist(tE, tLinks) & lst ) { 448 verify (&lst != 0p); 449 if ( & first(lst) == 0p || & last(lst) == 0p ) { 450 verify( & last(lst) == 0p && & last(lst) == 0p ); 451 return true; 452 } 453 return false; 454 } 455 456 static inline bool isListed( tE & e ) { 457 NOLOOSE( 458 verify (&e != 0p); 459 verify(! ORIGIN_TAG_QUERY( (size_t) & e )); 460 dlink(tE) & e_links = e`inner; 461 dlink(tE) * lprev = (dlink(tE)*) ORIGIN_TAG_CLEAR((size_t) e_links.prev); 462 dlink(tE) * lnext = (dlink(tE)*) ORIGIN_TAG_CLEAR((size_t) e_links.next); 463 return ( lprev != &e_links ) || ( lnext != &e_links ); 464 ) 465 LOOSEONLY( 466 verify(false && "isListed is undefined"); 467 return true; 468 ) 469 } 470 471 static inline tE & iter( dlist(tE, tLinks) & lst ) { 472 tE * origin = $get_list_origin_addr( lst ); 473 return *origin; 474 } 475 476 477 // todo: resolve the pun: 478 // tag as in proxy (tytagref) 479 // tag as in bit manipulation on a funny pointer 480 481 static inline bool advance( tE && refx ) { 482 tE && ref_inner = refx; 483 tE & oldReferent = * (tE*) ORIGIN_TAG_CLEAR( (size_t) & ref_inner ); 484 verify (& oldReferent != 0p); 485 dlink(tE) * tgt = oldReferent`inner.next; 486 size_t tgt_tags = ORIGIN_TAG_QUERY( (size_t)tgt); 487 dlink(tE) * nextl = (dlink(tE) *)ORIGIN_TAG_CLEAR((size_t)tgt); 488 tytagref( tLinks, dlink(tE) ) nextLnkTagged = { * nextl }; 489 tE & nexte = downcast$( nextLnkTagged ); 490 size_t next_te_num = (size_t) & nexte; 491 size_t new_ref_inner_num = ORIGIN_TAG_ASGN(next_te_num, tgt_tags); 492 tE * new_ref_inner = (tE *) new_ref_inner_num; 493 &ref_inner = new_ref_inner; 494 return ! tgt_tags; 495 } 496 497 static inline bool recede( tE && refx ) { 498 tE && ref_inner = refx; 499 tE & oldReferent = * (tE*) ORIGIN_TAG_CLEAR( (size_t) & ref_inner ); 500 verify (& oldReferent != 0p); 501 dlink(tE) * tgt = oldReferent`inner.prev; 502 size_t tgt_tags = ORIGIN_TAG_QUERY( (size_t)tgt); 503 dlink(tE) * prevl = (dlink(tE) *)ORIGIN_TAG_CLEAR((size_t)tgt); 504 tytagref( tLinks, dlink(tE) ) prevLnkTagged = { * prevl }; 505 tE & preve = downcast$( prevLnkTagged ); 506 size_t prev_te_num = (size_t) & preve; 507 size_t new_ref_inner_num = ORIGIN_TAG_ASGN(prev_te_num, tgt_tags); 508 tE * new_ref_inner = (tE *) new_ref_inner_num; 509 &ref_inner = new_ref_inner; 510 return ! tgt_tags; 511 } 512 513 bool isFirst( tE & node ) { 514 // Probable bug copied from master 515 // should be `! recede(node)` 516 // correct: "is first iff cannot recede" 517 // used backward in test suite too, probably victim of a grep rename 518 return recede( node ); 519 } 520 521 bool isLast( tE & node ) { 522 // ditto, vice versa 523 return advance( node ); 524 } 525 526 static inline tE & next( tE & e ) { 527 if( advance(e) ) return e; 528 return * 0p; 529 } 530 531 static inline tE & prev( tE & e ) { 532 if( recede(e) ) return e; 533 return * 0p; 534 } 535 536 // Next 4 headed operations: 537 // Manual inline of the equivalent headless operation, manually simplified. 538 // Applies knowledge of tag pattern around head (unknown to optimizer) to reduce runtime tag operations. 539 540 static inline void insert_first( dlist(tE, tLinks) &lst, tE & e ) { 541 dlink(tE) & linkToInsert = e`inner; 542 NOLOOSE( 543 TAGSONLY( 359 544 verify(ORIGIN_TAG_QUERY((size_t)linkToInsert.prev)); 360 545 verify(ORIGIN_TAG_QUERY((size_t)linkToInsert.next)); 361 )546 ) 362 547 verify(ORIGIN_TAG_CLEAR((size_t)linkToInsert.prev) == (size_t)&linkToInsert); 363 548 verify(ORIGIN_TAG_CLEAR((size_t)linkToInsert.next) == (size_t)&linkToInsert); 364 ) 365 dlink(tE) & list_pos_links = list_pos_real`inner; 366 MAYBE_INSERT_READ_EARLY( 367 dlink(tE) & beforeLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.prev ); 368 ) 369 MAYBE_CMEM_BARRIER; 370 size_t list_pos_links_num = (size_t)(& list_pos_links); 371 size_t to_insert_next_num = ORIGIN_TAG_ASGN(list_pos_links_num, list_pos_tag); 372 dlink(tE) * to_insert_next = (dlink(tE)*)to_insert_next_num; 549 ) 550 dlink(tE) & list_pos_links = lst; 551 MAYBE_INSERT_READ_EARLY( 552 dlink(tE) & afterLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.next ); 553 ) 554 MAYBE_CMEM_BARRIER; 555 size_t list_pos_links_num = (size_t)(& list_pos_links); 556 size_t to_insert_prev_num = ORIGIN_TAG_ENABL(list_pos_links_num); 557 dlink(tE) * to_insert_prev = (dlink(tE)*)to_insert_prev_num; 558 linkToInsert.prev = to_insert_prev; 559 linkToInsert.next = list_pos_links.next; 560 MAYBE_INSERT_READ_LATE( 561 dlink(tE) & afterLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.next ); 562 ) 563 size_t linkToInsert_num = (size_t)(& linkToInsert); 564 size_t afterLinks_prev_num = linkToInsert_num; 565 afterLinks.prev = (dlink(tE)*)(afterLinks_prev_num); 566 list_pos_links.next = &linkToInsert; 567 MAYBE_CMEM_BARRIER; 568 } 569 // FIXME: Change from pointer to reference for node, when tuple type can handle references. 570 forall( List ... | { void insert_first( dlist( tE, tLinks ) & list, List ); } ) 571 void insert_first( dlist( tE, tLinks ) & list, tE * node, List args ) { 572 insert_first( list, *node ); 573 insert_first( list, args ); 574 } 575 void insert_first( dlist( tE, tLinks ) & list, tE * node ) { 576 insert_first( list, *node ); 577 } 578 579 static inline void insert_last( dlist(tE, tLinks) &lst, tE & e ) { 580 dlink(tE) & linkToInsert = e`inner; 581 NOLOOSE( 582 TAGSONLY( 583 verify(ORIGIN_TAG_QUERY((size_t)linkToInsert.next)); 584 verify(ORIGIN_TAG_QUERY((size_t)linkToInsert.prev)); 585 ) 586 verify(ORIGIN_TAG_CLEAR((size_t)linkToInsert.next) == (size_t)&linkToInsert); 587 verify(ORIGIN_TAG_CLEAR((size_t)linkToInsert.prev) == (size_t)&linkToInsert); 588 ) 589 dlink(tE) & list_pos_links = lst; 590 MAYBE_INSERT_READ_EARLY( 591 dlink(tE) & beforeLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.prev ); 592 ) 593 MAYBE_CMEM_BARRIER; 594 size_t list_pos_links_num = (size_t)(& list_pos_links); 595 size_t to_insert_next_num = ORIGIN_TAG_ENABL(list_pos_links_num); 596 dlink(tE) * to_insert_next = (dlink(tE)*)to_insert_next_num; 373 597 linkToInsert.next = to_insert_next; 374 598 linkToInsert.prev = list_pos_links.prev; 375 MAYBE_INSERT_READ_LATE( 376 dlink(tE) & beforeLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.prev ); 377 ) 378 size_t beforeLinks_next_tag = ORIGIN_TAG_QUERY((size_t)beforeLinks.next); 379 size_t linkToInsert_num = (size_t)(& linkToInsert); 380 size_t beforeLinks_next_num = ORIGIN_TAG_ASGN(linkToInsert_num, ORIGIN_TAG_NEQ(list_pos_tag, beforeLinks_next_tag)); 381 beforeLinks.next = (dlink(tE)*)(beforeLinks_next_num); 599 MAYBE_INSERT_READ_LATE( 600 dlink(tE) & beforeLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.prev ); 601 ) 602 size_t linkToInsert_num = (size_t)(& linkToInsert); 603 size_t beforeLinks_next_num = linkToInsert_num; 604 beforeLinks.next = (dlink(tE)*)(beforeLinks_next_num); 382 605 list_pos_links.prev = &linkToInsert; 383 MAYBE_CMEM_BARRIER; 384 } 385 386 static inline tE & remove(tE & list_pos) { 387 verify( ! ORIGIN_TAG_QUERY((size_t) & list_pos) ); 388 verify (&list_pos != 0p); 389 390 dlink(tE) & list_pos_links = list_pos`inner; 391 dlink(tE) & before_raw = * list_pos_links.prev; 392 dlink(tE) & before_links = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) & before_raw ); 393 size_t before_links_next_tag = ORIGIN_TAG_QUERY( (size_t) (before_links.next) ); 394 395 dlink(tE) & after_raw = * list_pos_links.next; 396 dlink(tE) & after_links = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) & after_raw ); 397 size_t after_links_prev_tag = ORIGIN_TAG_QUERY( (size_t) (after_links.prev) ); 398 399 size_t before_links_next_rslt = ORIGIN_TAG_EITHER( ((size_t) & after_raw), before_links_next_tag ); 400 size_t after_links_prev_rslt = ORIGIN_TAG_EITHER( ((size_t) & before_raw), after_links_prev_tag ); 401 before_links.next = (dlink(tE) *) before_links_next_rslt; 402 after_links.prev = (dlink(tE) *) after_links_prev_rslt; 403 404 NOLOOSE( 405 MAYBE_CMEM_BARRIER; 406 size_t list_pos_links_num = (size_t) &list_pos_links; 407 size_t list_pos_links_tagged_num = ORIGIN_TAG_ENABL( list_pos_links_num ); 408 list_pos_links.next = list_pos_links.prev = (dlink(tE)*) list_pos_links_tagged_num; 409 MAYBE_CMEM_BARRIER; 410 ) 411 return list_pos; 412 } 413 414 static inline tE & downcast$( tytagref( tLinks, dlink(tE) ) ref ) { 415 dlink(tE) & lnk = ref; 416 dlink(tE) & link_from_null = ( * (tE *) 0p )`inner; 417 ptrdiff_t link_offset = (ptrdiff_t) & link_from_null; 418 size_t elm_addr = ((size_t) & lnk) - link_offset; 419 return * (tE*) elm_addr; 420 } 421 422 static inline tE & first( dlist(tE, tLinks) & lst ) { 606 MAYBE_CMEM_BARRIER; 607 } 608 // FIXME: Change from pointer to reference for node, when tuple type can handle references. 609 forall( List ... | { void insert_last( dlist( tE, tLinks ) & list, List ); } ) 610 void insert_last( dlist( tE, tLinks ) & list, tE * node, List args ) { 611 insert_last( list, *node ); 612 insert_last( list, args ); 613 } 614 void insert_last( dlist( tE, tLinks ) & list, tE * node ) { 615 insert_last( list, *node ); 616 } 617 618 tE & insert( dlist( tE, tLinks ) & list, tE & node ) { // synonym for insert_last 619 insert_last( list, node ); 620 return node; 621 } 622 // FIXME: Change from pointer to reference for node, when tuple type can handle references. 623 forall( List ... | { void insert( dlist( tE, tLinks ) & list, List ); } ) 624 void insert( dlist( tE, tLinks ) & list, tE * node, List args ) { 625 insert( list, *node ); 626 insert( list, args ); 627 } 628 void insert( dlist( tE, tLinks ) & list, tE * node ) { 629 insert( list, *node ); 630 } 631 632 static inline tE & remove_first( dlist(tE, tLinks) &lst ) { 423 633 verify (&lst != 0p); 424 dlink(tE) * firstLnk = lst.next; 425 if (ORIGIN_TAG_QUERY((size_t)firstLnk)) return * 0p; 426 tytagref( tLinks, dlink(tE) ) firstLnkTagged = {*firstLnk}; 427 return downcast$( firstLnkTagged ); 428 } 429 static inline tE & last ( dlist(tE, tLinks) & lst ) { 634 dlink(tE) & list_links = lst; 635 // call is valid on empty list; when so, list_links.next and after_links.prev have otags set 636 637 dlink(tE) & fst_raw = * list_links.next; 638 dlink(tE) & fst_links = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) & fst_raw ); 639 size_t fst_tagval = origin_tag_query_arith$( fst_raw ); 640 641 dlink(tE) & after_raw = * fst_links.next; 642 dlink(tE) & after_links = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) & after_raw ); 643 644 size_t before_links_next_rslt = ((size_t) & after_raw); 645 size_t after_links_prev_rslt = ORIGIN_TAG_ENABL( (size_t) & list_links ); 646 list_links.next = (dlink(tE) *) before_links_next_rslt; 647 after_links.prev = (dlink(tE) *) after_links_prev_rslt; 648 649 MAYBE_CMEM_BARRIER; 650 size_t list_pos_links_num = (size_t) &fst_links; 651 size_t list_pos_links_tagged_num = ORIGIN_TAG_ENABL( list_pos_links_num ); 652 fst_links.next = fst_links.prev = (dlink(tE)*) list_pos_links_tagged_num; 653 MAYBE_CMEM_BARRIER; 654 655 tytagref( tLinks, dlink(tE) ) retExt = { fst_links }; 656 return nullif$( downcast$( retExt ), fst_tagval ); 657 } 658 659 static inline tE & remove_last( dlist(tE, tLinks) &lst ) { 430 660 verify (&lst != 0p); 431 dlink(tE) * lastLnk = lst.prev; 432 if (ORIGIN_TAG_QUERY((size_t)lastLnk)) return * 0p; 433 tytagref( tLinks, dlink(tE) ) lastLnkTagged = {*lastLnk}; 434 return downcast$( lastLnkTagged ); 435 } 436 437 static inline bool isEmpty( dlist(tE, tLinks) & lst ) { 438 verify (&lst != 0p); 439 if ( & first(lst) == 0p || & last(lst) == 0p ) { 440 verify( & last(lst) == 0p && & last(lst) == 0p ); 441 return true; 442 } 443 return false; 444 } 445 446 static inline bool isListed( tE & e ) { 447 NOLOOSE( 448 verify (&e != 0p); 449 verify(! ORIGIN_TAG_QUERY( (size_t) & e )); 450 dlink(tE) & e_links = e`inner; 451 dlink(tE) * lprev = (dlink(tE)*) ORIGIN_TAG_CLEAR((size_t) e_links.prev); 452 dlink(tE) * lnext = (dlink(tE)*) ORIGIN_TAG_CLEAR((size_t) e_links.next); 453 return ( lprev != &e_links ) || ( lnext != &e_links ); 454 ) 455 LOOSEONLY( 456 verify(false && "isListed is undefined"); 457 return true; 458 ) 459 } 460 461 static inline tE & iter( dlist(tE, tLinks) & lst ) { 462 tE * origin = $get_list_origin_addr( lst ); 463 return *origin; 464 } 465 466 467 // todo: resolve the pun: 468 // tag as in proxy (tytagref) 469 // tag as in bit manipulation on a funny pointer 470 471 static inline bool advance( tE && refx ) { 472 tE && ref_inner = refx; 473 tE & oldReferent = * (tE*) ORIGIN_TAG_CLEAR( (size_t) & ref_inner ); 474 verify (& oldReferent != 0p); 475 dlink(tE) * tgt = oldReferent`inner.next; 476 size_t tgt_tags = ORIGIN_TAG_QUERY( (size_t)tgt); 477 dlink(tE) * nextl = (dlink(tE) *)ORIGIN_TAG_CLEAR((size_t)tgt); 478 tytagref( tLinks, dlink(tE) ) nextLnkTagged = { * nextl }; 479 tE & nexte = downcast$( nextLnkTagged ); 480 size_t next_te_num = (size_t) & nexte; 481 size_t new_ref_inner_num = ORIGIN_TAG_ASGN(next_te_num, tgt_tags); 482 tE * new_ref_inner = (tE *) new_ref_inner_num; 483 &ref_inner = new_ref_inner; 484 return ! tgt_tags; 485 } 486 487 static inline bool recede( tE && refx ) { 488 tE && ref_inner = refx; 489 tE & oldReferent = * (tE*) ORIGIN_TAG_CLEAR( (size_t) & ref_inner ); 490 verify (& oldReferent != 0p); 491 dlink(tE) * tgt = oldReferent`inner.prev; 492 size_t tgt_tags = ORIGIN_TAG_QUERY( (size_t)tgt); 493 dlink(tE) * prevl = (dlink(tE) *)ORIGIN_TAG_CLEAR((size_t)tgt); 494 tytagref( tLinks, dlink(tE) ) prevLnkTagged = { * prevl }; 495 tE & preve = downcast$( prevLnkTagged ); 496 size_t prev_te_num = (size_t) & preve; 497 size_t new_ref_inner_num = ORIGIN_TAG_ASGN(prev_te_num, tgt_tags); 498 tE * new_ref_inner = (tE *) new_ref_inner_num; 499 &ref_inner = new_ref_inner; 500 return ! tgt_tags; 501 } 502 503 bool isFirst( tE & node ) { 504 // Probable bug copied from master 505 // should be `! recede(node)` 506 // correct: "is first iff cannot recede" 507 // used backward in test suite too, probably victim of a grep rename 508 return recede( node ); 509 } 510 511 bool isLast( tE & node ) { 512 // ditto, vice versa 513 return advance( node ); 514 } 515 516 static inline tE & next( tE & e ) { 517 if( advance(e) ) return e; 518 return * 0p; 519 } 520 521 static inline tE & prev( tE & e ) { 522 if( recede(e) ) return e; 523 return * 0p; 524 } 525 526 // Next 4 headed operations: 527 // Manual inline of the equivalent headless operation, manually simplified. 528 // Applies knowledge of tag pattern around head (unknown to optimizer) to reduce runtime tag operations. 529 530 static inline void insert_first( dlist(tE, tLinks) &lst, tE & e ) { 531 dlink(tE) & linkToInsert = e`inner; 532 NOLOOSE( 533 TAGSONLY( 534 verify(ORIGIN_TAG_QUERY((size_t)linkToInsert.prev)); 535 verify(ORIGIN_TAG_QUERY((size_t)linkToInsert.next)); 536 ) 537 verify(ORIGIN_TAG_CLEAR((size_t)linkToInsert.prev) == (size_t)&linkToInsert); 538 verify(ORIGIN_TAG_CLEAR((size_t)linkToInsert.next) == (size_t)&linkToInsert); 539 ) 540 dlink(tE) & list_pos_links = lst; 541 MAYBE_INSERT_READ_EARLY( 542 dlink(tE) & afterLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.next ); 543 ) 544 MAYBE_CMEM_BARRIER; 545 size_t list_pos_links_num = (size_t)(& list_pos_links); 546 size_t to_insert_prev_num = ORIGIN_TAG_ENABL(list_pos_links_num); 547 dlink(tE) * to_insert_prev = (dlink(tE)*)to_insert_prev_num; 548 linkToInsert.prev = to_insert_prev; 549 linkToInsert.next = list_pos_links.next; 550 MAYBE_INSERT_READ_LATE( 551 dlink(tE) & afterLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.next ); 552 ) 553 size_t linkToInsert_num = (size_t)(& linkToInsert); 554 size_t afterLinks_prev_num = linkToInsert_num; 555 afterLinks.prev = (dlink(tE)*)(afterLinks_prev_num); 556 list_pos_links.next = &linkToInsert; 557 MAYBE_CMEM_BARRIER; 558 } 559 560 static inline void insert_last( dlist(tE, tLinks) &lst, tE & e ) { 561 dlink(tE) & linkToInsert = e`inner; 562 NOLOOSE( 563 TAGSONLY( 564 verify(ORIGIN_TAG_QUERY((size_t)linkToInsert.next)); 565 verify(ORIGIN_TAG_QUERY((size_t)linkToInsert.prev)); 566 ) 567 verify(ORIGIN_TAG_CLEAR((size_t)linkToInsert.next) == (size_t)&linkToInsert); 568 verify(ORIGIN_TAG_CLEAR((size_t)linkToInsert.prev) == (size_t)&linkToInsert); 569 ) 570 dlink(tE) & list_pos_links = lst; 571 MAYBE_INSERT_READ_EARLY( 572 dlink(tE) & beforeLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.prev ); 573 ) 574 MAYBE_CMEM_BARRIER; 575 size_t list_pos_links_num = (size_t)(& list_pos_links); 576 size_t to_insert_next_num = ORIGIN_TAG_ENABL(list_pos_links_num); 577 dlink(tE) * to_insert_next = (dlink(tE)*)to_insert_next_num; 578 linkToInsert.next = to_insert_next; 579 linkToInsert.prev = list_pos_links.prev; 580 MAYBE_INSERT_READ_LATE( 581 dlink(tE) & beforeLinks = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) list_pos_links.prev ); 582 ) 583 size_t linkToInsert_num = (size_t)(& linkToInsert); 584 size_t beforeLinks_next_num = linkToInsert_num; 585 beforeLinks.next = (dlink(tE)*)(beforeLinks_next_num); 586 list_pos_links.prev = &linkToInsert; 587 MAYBE_CMEM_BARRIER; 588 } 589 590 static inline tE & remove_first( dlist(tE, tLinks) &lst ) { 591 verify (&lst != 0p); 592 dlink(tE) & list_links = lst; 593 // call is valid on empty list; when so, list_links.next and after_links.prev have otags set 594 595 dlink(tE) & fst_raw = * list_links.next; 596 dlink(tE) & fst_links = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) & fst_raw ); 597 size_t fst_tagval = origin_tag_query_arith$( fst_raw ); 598 599 dlink(tE) & after_raw = * fst_links.next; 600 dlink(tE) & after_links = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) & after_raw ); 601 602 size_t before_links_next_rslt = ((size_t) & after_raw); 603 size_t after_links_prev_rslt = ORIGIN_TAG_ENABL( (size_t) & list_links ); 604 list_links.next = (dlink(tE) *) before_links_next_rslt; 605 after_links.prev = (dlink(tE) *) after_links_prev_rslt; 606 607 MAYBE_CMEM_BARRIER; 608 size_t list_pos_links_num = (size_t) &fst_links; 609 size_t list_pos_links_tagged_num = ORIGIN_TAG_ENABL( list_pos_links_num ); 610 fst_links.next = fst_links.prev = (dlink(tE)*) list_pos_links_tagged_num; 611 MAYBE_CMEM_BARRIER; 612 613 tytagref( tLinks, dlink(tE) ) retExt = { fst_links }; 614 return nullif$( downcast$( retExt ), fst_tagval ); 615 } 616 617 static inline tE & remove_last( dlist(tE, tLinks) &lst ) { 618 verify (&lst != 0p); 619 dlink(tE) & list_links = lst; 620 // call is valid on empty list; when so, list_links.prev and before_links.next have otags set 621 622 dlink(tE) & last_raw = * list_links.prev; 623 dlink(tE) & last_links = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) & last_raw ); 624 size_t last_tagval = origin_tag_query_arith$( last_raw ); 625 626 dlink(tE) & before_raw = * last_links.prev; 627 dlink(tE) & before_links = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) & before_raw ); 628 629 size_t after_links_prev_rslt = ((size_t) & before_raw); 630 size_t before_links_next_rslt = ORIGIN_TAG_ENABL( (size_t) & list_links ); 631 list_links.prev = (dlink(tE) *) after_links_prev_rslt; 632 before_links.next = (dlink(tE) *) before_links_next_rslt; 633 634 MAYBE_CMEM_BARRIER; 635 size_t list_pos_links_num = (size_t) &last_links; 636 size_t list_pos_links_tagged_num = ORIGIN_TAG_ENABL( list_pos_links_num ); 661 dlink(tE) & list_links = lst; 662 // call is valid on empty list; when so, list_links.prev and before_links.next have otags set 663 664 dlink(tE) & last_raw = * list_links.prev; 665 dlink(tE) & last_links = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) & last_raw ); 666 size_t last_tagval = origin_tag_query_arith$( last_raw ); 667 668 dlink(tE) & before_raw = * last_links.prev; 669 dlink(tE) & before_links = * (dlink(tE) *) ORIGIN_TAG_CLEAR( (size_t) & before_raw ); 670 671 size_t after_links_prev_rslt = ((size_t) & before_raw); 672 size_t before_links_next_rslt = ORIGIN_TAG_ENABL( (size_t) & list_links ); 673 list_links.prev = (dlink(tE) *) after_links_prev_rslt; 674 before_links.next = (dlink(tE) *) before_links_next_rslt; 675 676 MAYBE_CMEM_BARRIER; 677 size_t list_pos_links_num = (size_t) &last_links; 678 size_t list_pos_links_tagged_num = ORIGIN_TAG_ENABL( list_pos_links_num ); 637 679 last_links.prev = last_links.next = (dlink(tE)*) list_pos_links_tagged_num; 638 MAYBE_CMEM_BARRIER;639 640 tytagref( tLinks, dlink(tE) ) lpLnkTagged = { last_links };641 return nullif$( downcast$( lpLnkTagged ), last_tagval );642 }643 644 static inline tE & try_pop_first( dlist(tE, tLinks) &lst ) {645 tE & first_inlist = first(lst);646 tE & first_item = first_inlist;647 if (&first_item) remove(first_inlist); // TODO: should it use pop_front?648 return first_item;649 }650 651 static inline tE & try_pop_last( dlist(tE, tLinks) &lst ) {652 tE & last_inlist = last(lst);653 tE & last_item = last_inlist;654 if (&last_item) remove(last_inlist); // TODO: should it use pop_back?655 return last_item;656 }680 MAYBE_CMEM_BARRIER; 681 682 tytagref( tLinks, dlink(tE) ) lpLnkTagged = { last_links }; 683 return nullif$( downcast$( lpLnkTagged ), last_tagval ); 684 } 685 686 static inline tE & try_pop_first( dlist(tE, tLinks) &lst ) { 687 tE & first_inlist = first(lst); 688 tE & first_item = first_inlist; 689 if (&first_item) remove(first_inlist); // TODO: should it use pop_front? 690 return first_item; 691 } 692 693 static inline tE & try_pop_last( dlist(tE, tLinks) &lst ) { 694 tE & last_inlist = last(lst); 695 tE & last_item = last_inlist; 696 if (&last_item) remove(last_inlist); // TODO: should it use pop_back? 697 return last_item; 698 } 657 699 658 700 659 701 #if !defined(NDEBUG) && (defined(__CFA_DEBUG__) || defined(__CFA_VERIFY__)) 660 702 static bool $validate_fwd( dlist(tE, tLinks) & this ) { 661 tE & lagElem = *0p;662 663 while ( tE & it = iter(this); advance(it) ) {664 if (& lagElem == 0p && &it != & first(this) ) return false;665 & lagElem = & it;666 }667 668 if (& lagElem != & last(this)) return false;669 670 // TODO: verify that it is back at iter(this);671 return true;703 tE & lagElem = *0p; 704 705 while ( tE & it = iter(this); advance(it) ) { 706 if (& lagElem == 0p && &it != & first(this) ) return false; 707 & lagElem = & it; 708 } 709 710 if (& lagElem != & last(this)) return false; 711 712 // TODO: verify that it is back at iter(this); 713 return true; 672 714 } 673 715 static bool $validate_rev( dlist(tE, tLinks) & this ) { 674 tE & lagElem = *0p;675 676 while ( tE & it = iter(this); recede(it) ) {677 if (& lagElem == 0p && &it != & last(this) ) return false;678 & lagElem = & it;679 }680 681 if (& lagElem != & first(this)) return false;682 683 // TODO: verify that it is back at iter(this);684 return true;716 tE & lagElem = *0p; 717 718 while ( tE & it = iter(this); recede(it) ) { 719 if (& lagElem == 0p && &it != & last(this) ) return false; 720 & lagElem = & it; 721 } 722 723 if (& lagElem != & first(this)) return false; 724 725 // TODO: verify that it is back at iter(this); 726 return true; 685 727 } 686 728 static inline bool validate( dlist(tE, tLinks) & this ) { 687 bool reportsHavingFirst = ((& first(this)) == 0p);688 bool reportsHavingLast = ((& last(this)) == 0p);689 if ( reportsHavingFirst != reportsHavingLast ) return false;729 bool reportsHavingFirst = ((& first(this)) == 0p); 730 bool reportsHavingLast = ((& last(this)) == 0p); 731 if ( reportsHavingFirst != reportsHavingLast ) return false; 690 732 691 733 return $validate_fwd(this) && $validate_rev(this);
Note:
See TracChangeset
for help on using the changeset viewer.