Changeset 1740
- Timestamp:
- 07/09/10 03:59:53 (14 years ago)
- Files:
-
- trunk/phobos/std/container.d (modified) (18 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/phobos/std/container.d
r1734 r1740 10 10 11 11 License: Distributed under the Boost Software License, Version 1.0. 12 12 (See accompanying file LICENSE_1_0.txt or copy at $(WEB 13 13 boost.org/LICENSE_1_0.txt)). 14 14 15 15 Authors: $(WEB erdani.com, Andrei Alexandrescu) 16 16 17 17 */ 18 18 module std.container; 19 19 20 import core. stdc.stdlib, core.stdc.string, std.algorithm, std.contracts,21 std.conv, std. functional, std.range, std.traits, std.typecons,22 core.memory;20 import core.memory, core.stdc.stdlib, core.stdc.string, std.algorithm, 21 std.conv, std.exception, std.functional, std.range, std.traits, 22 std.typecons, std.typetuple; 23 23 version(unittest) import std.stdio; 24 24 25 25 /** 26 26 $(D TotalContainer) is an unimplemented container that illustrates a 27 27 host of primitives that a container may define. It is to some extent 28 28 the bottom of the conceptual container hierarchy. A given container 29 29 most often will choose to only implement a subset of these primitives, 30 30 and define its own additional ones. Adhering to the standard primitive 31 31 names below allows generic code to work independently of containers. 32 32 … … 39 39 A container may choose to define additional specific operations. The 40 40 only requirement is that those operations bear different names than 41 41 the ones below, lest user code gets confused. 42 42 43 43 Complexity of operations should be interpreted as "at least as good 44 44 as". If an operation is required to have $(BIGOH n) complexity, it 45 45 could have anything lower than that, e.g. $(BIGOH log(n)). Unless 46 46 specified otherwise, $(D n) inside a $(BIGOH) expression stands for 47 47 the number of elements in the container. 48 48 */ 49 struct TotalContainer( Whatever)49 struct TotalContainer(T) 50 50 { 51 51 /** 52 52 If the container has a notion of key-value mapping, $(D KeyType) 53 53 defines the type of the key of the container. 54 54 */ 55 alias SomeTypeKeyType;55 alias T KeyType; 56 56 57 57 /** 58 58 If the container has a notion of multikey-value mapping, $(D 59 59 KeyTypes[k]), where $(D k) is a zero-based unsigned number, defines 60 60 the type of the $(D k)th key of the container. 61 61 62 62 A container may define both $(D KeyType) and $(D KeyTypes), e.g. in 63 63 the case it has the notion of primary/preferred key. 64 64 */ 65 alias TypeTuple!( Key1, Key2) KeyTypes;65 alias TypeTuple!(T) KeyTypes; 66 66 67 67 /** 68 68 If the container has a notion of key-value mapping, $(D ValueType) 69 69 defines the type of the value of the container. Typically, a map-style 70 70 container mapping values of type $(D K) to values of type $(D V) 71 defines $(D KeyType) to be $(D K), $(D ValueType) to be $(D V), and 72 $(D ElementType) to be $(D Tuple!(K, V)). 73 */ 74 alias SomeType ValueType; 71 defines $(D KeyType) to be $(D K) and $(D ValueType) to be $(D V). 72 */ 73 alias T ValueType; 75 74 76 75 /** 77 76 Defines the container's primary range, which embodies one of the 78 archetypalranges defined in $(XREFMODULE range).77 ranges defined in $(XREFMODULE range). 79 78 80 79 Generally a container may define several types of ranges. 81 80 */ 82 alias SomeType Range; 81 struct Range 82 { 83 /// Range primitives. 84 @property bool empty() 85 { 86 assert(0); 87 } 88 /// Ditto 89 @property T front() 90 { 91 assert(0); 92 } 93 /// Ditto 94 T moveFront() 95 { 96 assert(0); 97 } 98 /// Ditto 99 void popFront() 100 { 101 assert(0); 102 } 103 /// Ditto 104 @property T back() 105 { 106 assert(0); 107 } 108 /// Ditto 109 T moveBack() 110 { 111 assert(0); 112 } 113 /// Ditto 114 void popBack() 115 { 116 assert(0); 117 } 118 /// Ditto 119 T opIndex(size_t i) 120 { 121 assert(0); 122 } 123 /// Ditto 124 void opIndexAssign(T value, uint i) 125 { 126 assert(0); 127 } 128 /// Ditto 129 void opIndexOpAssign(string op)(T value, uint i) 130 { 131 assert(0); 132 } 133 /// Ditto 134 T moveAt(size_t i) 135 { 136 assert(0); 137 } 138 /// Ditto 139 @property size_t length() 140 { 141 assert(0); 142 } 143 } 83 144 84 145 /** 85 146 Property returning $(D true) if and only if the container has no 86 147 elements. 87 148 88 149 Complexity: $(BIGOH 1) 89 150 */ 90 @property bool empty(); 151 @property bool empty() 152 { 153 assert(0); 154 } 91 155 92 156 /** 93 157 Returns a duplicate of the container. The elements themselves are not 94 158 transitively duplicated. 95 159 96 160 Complexity: $(BIGOH n). 97 161 */ 98 @property TotalContainer dup(); 162 @property TotalContainer dup() 163 { 164 assert(0); 165 } 99 166 100 167 /** 101 168 Returns the number of elements in the container. 102 169 103 170 Complexity: $(BIGOH log(n)). 104 */ 105 @property size_t length(); 171 */ 172 @property size_t length() 173 { 174 assert(0); 175 } 106 176 107 177 /** 108 178 Returns the maximum number of elements the container can store without 109 179 (a) allocating memory, (b) invalidating iterators upon insertion. 110 180 111 181 Complexity: $(BIGOH log(n)). 112 182 */ 113 @property size_t capacity(); 183 @property size_t capacity() 184 { 185 assert(0); 186 } 114 187 115 188 /** 116 189 Ensures sufficient capacity to accommodate $(D n) elements. 117 190 118 191 Postcondition: $(D capacity >= n) 119 192 120 193 Complexity: $(BIGOH log(e - capacity)) if $(D e > capacity), otherwise 121 194 $(BIGOH 1). 122 195 */ 123 void reserve(size_t e); 196 void reserve(size_t e) 197 { 198 assert(0); 199 } 124 200 125 201 /** 126 202 Returns a range that iterates over all elements of the container, in a 127 203 container-defined order. The container should choose the most 128 204 convenient and fast method of iteration for $(D opSlice()). 129 205 130 206 Complexity: $(BIGOH log(n)) 131 207 */ 132 Range opSlice(); 208 Range opSlice() 209 { 210 assert(0); 211 } 212 213 /** 214 Returns a range that iterates the container between two 215 specified positions. 216 217 Complexity: $(BIGOH log(n)) 218 */ 219 Range opSlice(size_t a, size_t b) 220 { 221 assert(0); 222 } 133 223 134 224 /** 135 225 Forward to $(D opSlice().front) and $(D opSlice().back), respectively. 136 226 137 227 Complexity: $(BIGOH log(n)) 138 228 */ 139 @property ElementType front(); 140 /// ditto 141 @property ElementType back(); 229 @property T front() 230 { 231 assert(0); 232 } 233 /// Ditto 234 T moveFront() 235 { 236 assert(0); 237 } 238 /// Ditto 239 @property T back() 240 { 241 assert(0); 242 } 243 /// Ditto 244 T moveBack() 245 { 246 assert(0); 247 } 142 248 143 249 /** 144 250 Indexing operators yield or modify the value at a specified index. 145 251 */ 146 ValueType opIndex(KeyType); 147 /// ditto 148 void opIndexAssign(KeyType); 149 /// ditto 150 void opIndexOpAssign(string op)(KeyType); 252 /** 253 Indexing operators yield or modify the value at a specified index. 254 */ 255 ValueType opIndex(KeyType) 256 { 257 assert(0); 258 } 259 /// ditto 260 void opIndexAssign(KeyType) 261 { 262 assert(0); 263 } 264 /// ditto 265 void opIndexOpAssign(string op)(KeyType) 266 { 267 assert(0); 268 } 269 T moveAt(size_t i) 270 { 271 assert(0); 272 } 151 273 152 274 /** 153 275 $(D k in container) returns true if the given key is in the container. 154 276 */ 155 bool opBinary(string op)(KeyType k) if (op == "in"); 277 bool opBinary(string op)(KeyType k) if (op == "in") 278 { 279 assert(0); 280 } 156 281 157 282 /** 158 283 Returns a range of all elements containing $(D k) (could be empty or a 159 284 singleton range). 160 285 */ 161 Range equalRange(KeyType k); 286 Range equalRange(KeyType k) 287 { 288 assert(0); 289 } 162 290 163 291 /** 164 292 Returns a range of all elements with keys less than $(D k) (could be 165 293 empty or a singleton range). Only defined by containers that store 166 294 data sorted at all times. 167 295 */ 168 Range lowerBound(KeyType k); 296 Range lowerBound(KeyType k) 297 { 298 assert(0); 299 } 169 300 170 301 /** 171 302 Returns a range of all elements with keys larger than $(D k) (could be 172 303 empty or a singleton range). Only defined by containers that store 173 304 data sorted at all times. 174 305 */ 175 Range upperBound(KeyType k); 306 Range upperBound(KeyType k) 307 { 308 assert(0); 309 } 176 310 177 311 /** 178 312 Returns a new container that's the concatenation of $(D this) and its 179 313 argument. $(D opBinaryRight) is only defined if $(D Stuff) does not 180 314 define $(D opBinary). 181 315 182 316 Complexity: $(BIGOH n + m), where m is the number of elements in $(D 183 317 stuff) 184 318 */ 185 TotalContainer opBinary(string op)(Stuff rhs) if (op == "~"); 186 187 /// ditto 188 TotalContainer opBinaryRight(string op)(Stuff lhs) if (op == "~"); 319 TotalContainer opBinary(string op)(Stuff rhs) if (op == "~") 320 { 321 assert(0); 322 } 323 324 /// ditto 325 TotalContainer opBinaryRight(string op)(Stuff lhs) if (op == "~") 326 { 327 assert(0); 328 } 189 329 190 330 /** 191 331 Forwards to $(D insertAfter(this[], stuff)). 192 332 */ 193 void opOpAssign(string op)(Stuff stuff) if (op == "~"); 333 void opOpAssign(string op)(Stuff stuff) if (op == "~") 334 { 335 assert(0); 336 } 194 337 195 338 /** 196 339 Removes all contents from the container. The container decides how $(D 197 340 capacity) is affected. 198 341 199 342 Postcondition: $(D empty) 200 343 201 344 Complexity: $(BIGOH n) 202 345 */ 203 void clear(); 346 void clear() 347 { 348 assert(0); 349 } 204 350 205 351 /** 206 352 Sets the number of elements in the container to $(D newSize). If $(D 207 353 newSize) is greater than $(D length), the added elements are added to 208 354 unspecified positions in the container and initialized with $(D 209 ElementType.init).355 .init). 210 356 211 357 Complexity: $(BIGOH abs(n - newLength)) 212 358 213 Postcondition: $(D length == newLength) 214 */ 215 @property void length(size_t newLength); 359 Postcondition: $(D _length == newLength) 360 */ 361 @property void length(size_t newLength) 362 { 363 assert(0); 364 } 216 365 217 366 /** 218 367 Inserts $(D stuff) in an unspecified position in the 219 368 container. Implementations should choose whichever insertion means is 220 369 the most advantageous for the container, but document the exact 221 behavior. $(D stuff) can be a value convertible to $(D ElementType) or222 a range of objects convertible to $(D ElementType).370 behavior. $(D stuff) can be a value convertible to the element type of 371 the container, or a range of values convertible to it. 223 372 224 373 The $(D stable) version guarantees that ranges iterating over the 225 374 container are never invalidated. Client code that counts on 226 375 non-invalidating insertion should use $(D stableInsert). Such code would 227 376 not compile against containers that don't support it. 228 377 229 378 Returns: The number of elements added. 230 379 231 Complexity: $(BIGOH m * log(n)), where m is the number of elements in 232 $(D stuff) 233 */ 234 size_t insert(Stuff stuff); 380 Complexity: $(BIGOH m * log(n)), where $(D m) is the number of 381 elements in $(D stuff) 382 */ 383 size_t insert(Stuff)(Stuff stuff) 384 { 385 assert(0); 386 } 235 387 ///ditto 236 size_t stableInsert(Stuff stuff); 388 size_t stableInsert(Stuff)(Stuff stuff) 389 { 390 assert(0); 391 } 392 393 /** 394 Same as $(D insert(stuff)) and $(D stableInsert(stuff)) respectively, 395 but relax the complexity constraint to linear. 396 */ 397 size_t linearInsert(Stuff)(Stuff stuff) 398 { 399 assert(0); 400 } 401 ///ditto 402 size_t stableLinearInsert(Stuff)(Stuff stuff) 403 { 404 assert(0); 405 } 237 406 238 407 /** 239 408 Picks one value in an unspecified position in the container, removes 240 409 it from the container, and returns it. Implementations should pick the 241 410 value that's the most advantageous for the container, but document the 242 411 exact behavior. The stable version behaves the same, but guarantees that 243 412 ranges iterating over the container are never invalidated. 244 413 245 414 Precondition: $(D !empty) 246 415 247 416 Returns: The element removed. 248 417 249 418 Complexity: $(BIGOH log(n)). 250 419 */ 251 ElementType removeAny(); 252 /// ditto 253 ElementType stableRemoveAny(); 420 T removeAny() 421 { 422 assert(0); 423 } 424 /// ditto 425 T stableRemoveAny() 426 { 427 assert(0); 428 } 254 429 255 430 /** 256 431 Inserts $(D value) to the front or back of the container. $(D stuff) 257 can be a value convertible to $(D ElementType) or a range of objects258 convertible to $(D ElementType). The stable version behaves the same, 259 butguarantees that ranges iterating over the container are never432 can be a value convertible to the container's element type or a range 433 of values convertible to it. The stable version behaves the same, but 434 guarantees that ranges iterating over the container are never 260 435 invalidated. 261 436 262 437 Returns: The number of elements inserted 263 438 264 439 Complexity: $(BIGOH log(n)). 265 440 */ 266 size_t insertFront(Stuff stuff); 267 /// ditto 268 size_t stableInsertFront(Stuff stuff); 269 /// ditto 270 size_t insertBack(Stuff stuff); 271 /// ditto 272 size_t stableInsertBack(T value); 441 size_t insertFront(Stuff)(Stuff stuff) 442 { 443 assert(0); 444 } 445 /// ditto 446 size_t stableInsertFront(Stuff)(Stuff stuff) 447 { 448 assert(0); 449 } 450 /// ditto 451 size_t insertBack(Stuff)(Stuff stuff) 452 { 453 assert(0); 454 } 455 /// ditto 456 size_t stableInsertBack(T value) 457 { 458 assert(0); 459 } 273 460 274 461 /** 275 462 Removes the value at the front or back of the container. The stable 276 463 version behaves the same, but guarantees that ranges iterating over 277 464 the container are never invalidated. The optional parameter $(D 278 465 howMany) instructs removal of that many elements. If $(D howMany > n), 279 466 all elements are removed and no exception is thrown. 280 467 281 468 Precondition: $(D !empty) 282 469 283 470 Complexity: $(BIGOH log(n)). 284 471 */ 285 void removeFront(); 286 /// ditto 287 void stableRemoveFront(); 288 /// ditto 289 void removeBack(); 290 /// ditto 291 void stableRemoveBack(); 472 void removeFront() 473 { 474 assert(0); 475 } 476 /// ditto 477 void stableRemoveFront() 478 { 479 assert(0); 480 } 481 /// ditto 482 void removeBack() 483 { 484 assert(0); 485 } 486 /// ditto 487 void stableRemoveBack() 488 { 489 assert(0); 490 } 292 491 293 492 /** 294 493 Removes $(D howMany) values at the front or back of the 295 494 container. Unlike the unparameterized versions above, these functions 296 495 do not throw if they could not remove $(D howMany) elements. Instead, 297 496 if $(D howMany > n), all elements are removed. The returned value is 298 497 the effective number of elements removed. The stable version behaves 299 498 the same, but guarantees that ranges iterating over the container are 300 499 never invalidated. 301 500 302 501 Returns: The number of elements removed 303 502 304 503 Complexity: $(BIGOH howMany * log(n)). 305 504 */ 306 size_t removeFront(size_t howMany); 307 /// ditto 308 size_t stableRemoveFront(size_t howMany); 309 /// ditto 310 size_t removeBack(size_t howMany); 311 /// ditto 312 size_t stableRemoveBack(size_t howMany); 505 size_t removeFront(size_t howMany) 506 { 507 assert(0); 508 } 509 /// ditto 510 size_t stableRemoveFront(size_t howMany) 511 { 512 assert(0); 513 } 514 /// ditto 515 size_t removeBack(size_t howMany) 516 { 517 assert(0); 518 } 519 /// ditto 520 size_t stableRemoveBack(size_t howMany) 521 { 522 assert(0); 523 } 313 524 314 525 /** 315 526 Removes all values corresponding to key $(D k). 316 527 317 528 Complexity: $(BIGOH m * log(n)), where $(D m) is the number of 318 529 elements with the same key. 319 530 320 531 Returns: The number of elements removed. 321 532 */ 322 size_t removeKey(KeyType k); 533 size_t removeKey(KeyType k) 534 { 535 assert(0); 536 } 323 537 324 538 /** 325 539 Inserts $(D stuff) before, after, or instead range $(D r), which must 326 540 be a valid range previously extracted from this container. $(D stuff) 327 can be a value convertible to $(D ElementType) or a range of objects328 convertible to $(D ElementType). The stable version behaves the same, 329 butguarantees that ranges iterating over the container are never541 can be a value convertible to the container's element type or a range 542 of objects convertible to it. The stable version behaves the same, but 543 guarantees that ranges iterating over the container are never 330 544 invalidated. 331 545 332 546 Returns: The number of values inserted. 333 547 334 548 Complexity: $(BIGOH n + m), where $(D m) is the length of $(D stuff) 335 549 */ 336 size_t insertBefore(Range r, Stuff stuff); 337 /// ditto 338 size_t stableInsertBefore(Range r, Stuff stuff); 339 /// ditto 340 size_t insertAfter(Range r, Stuff stuff); 341 /// ditto 342 size_t stableInsertAfter(Range r, Stuff stuff); 343 /// ditto 344 size_t replace(Range r, Stuff stuff); 345 /// ditto 346 size_t stableReplace(Range r, Stuff stuff); 550 size_t insertBefore(Stuff)(Range r, Stuff stuff) 551 { 552 assert(0); 553 } 554 /// ditto 555 size_t stableInsertBefore(Stuff)(Range r, Stuff stuff) 556 { 557 assert(0); 558 } 559 /// ditto 560 size_t insertAfter(Stuff)(Range r, Stuff stuff) 561 { 562 assert(0); 563 } 564 /// ditto 565 size_t stableInsertAfter(Stuff)(Range r, Stuff stuff) 566 { 567 assert(0); 568 } 569 /// ditto 570 size_t replace(Stuff)(Range r, Stuff stuff) 571 { 572 assert(0); 573 } 574 /// ditto 575 size_t stableReplace(Stuff)(Range r, Stuff stuff) 576 { 577 assert(0); 578 } 347 579 348 580 /** 349 581 Removes all elements belonging to $(D r), which must be a range 350 582 obtained originally from this container. The stable version behaves the 351 583 same, but guarantees that ranges iterating over the container are 352 584 never invalidated. 353 585 354 586 Returns: A range spanning the remaining elements in the container that 355 587 initially were right after $(D r). 356 588 357 589 Complexity: $(BIGOH m * log(n)), where $(D m) is the number of 358 590 elements in $(D r) 359 591 */ 360 Range remove(Range r); 361 /// ditto 362 Range stableRemove(Range r); 592 Range remove(Range r) 593 { 594 assert(0); 595 } 596 /// ditto 597 Range stableRemove(Range r) 598 { 599 assert(0); 600 } 363 601 364 602 /** 365 603 Same as $(D remove) above, but has complexity relaxed to linear. 366 604 367 605 Returns: A range spanning the remaining elements in the container that 368 606 initially were right after $(D r). 369 607 370 608 Complexity: $(BIGOH n) 371 609 */ 372 Range linearRemove(Range r); 373 /// ditto 374 Range stableLinearRemove(Range r); 610 Range linearRemove(Range r) 611 { 612 assert(0); 613 } 614 /// ditto 615 Range stableLinearRemove(Range r) 616 { 617 assert(0); 618 } 619 } 620 621 unittest { 622 TotalContainer!int test; 375 623 } 376 624 377 625 /** 378 626 Returns an initialized container. This function is mainly for 379 627 eliminating construction differences between $(D class) containers and 380 628 $(D struct) containers. 381 629 */ 382 630 Container make(Container, T...)(T arguments) if (is(Container == struct)) 383 631 { 384 632 static if (T.length == 0) … … 601 849 602 850 Complexity: $(BIGOH 1) 603 851 */ 604 852 void clear() 605 853 { 606 854 _root = null; 607 855 } 608 856 609 857 /** 610 858 Inserts $(D stuff) to the front of the container. $(D stuff) can be a 611 value convertible to $(D ElementType) or a range of objects 612 convertible to $(D ElementType). The stable version behaves the same, 613 but guarantees that ranges iterating over the container are never 614 invalidated. 859 value convertible to $(D T) or a range of objects convertible to $(D 860 T). The stable version behaves the same, but guarantees that ranges 861 iterating over the container are never invalidated. 615 862 616 863 Returns: The number of elements inserted 617 864 618 865 Complexity: $(BIGOH log(n)) 619 866 */ 620 867 size_t insertFront(Stuff)(Stuff stuff) 621 868 if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) 622 869 { 623 870 size_t result; 624 871 Node * n, newRoot; … … 720 967 alias removeFront stableRemoveFront; 721 968 722 969 /** 723 970 Inserts $(D stuff) after range $(D r), which must be a range 724 971 previously extracted from this container. Given that all ranges for a 725 972 list end at the end of the list, this function essentially appends to 726 973 the list and uses $(D r) as a potentially fast way to reach the last 727 974 node in the list. (Ideally $(D r) is positioned near or at the last 728 975 element of the list.) 729 976 730 $(D stuff) can be a value convertible to $(D ElementType) or a range731 of objects convertible to $(D ElementType). The stable version behaves 732 the same, but guarantees that ranges iterating over the container are 733 neverinvalidated.977 $(D stuff) can be a value convertible to $(D T) or a range of objects 978 convertible to $(D T). The stable version behaves the same, but 979 guarantees that ranges iterating over the container are never 980 invalidated. 734 981 735 982 Returns: The number of values inserted. 736 983 737 984 Complexity: $(BIGOH k + m), where $(D k) is the number of elements in 738 985 $(D r) and $(D m) is the length of $(D stuff). 739 986 */ 740 987 741 988 size_t insertAfter(Stuff)(Range r, Stuff stuff) 742 989 { 743 990 if (!_root) … … 970 1217 971 1218 auto lst3 = lst ~ [ 7 ]; 972 1219 assert(walkLength(lst3[]) == 5); 973 1220 } 974 1221 975 1222 unittest 976 1223 { 977 1224 auto s = make!(SList!int)(1, 2, 3); 978 1225 } 979 1226 980 version (none) 981 { 982 /** 983 _Array type with straightforward implementation building on $(D T[]). 984 */ 985 struct Array(T) 986 { 987 private struct Data 1227 /** 1228 Array type with deterministic control of memory. The memory allocated 1229 for the array is reclaimed as soon as possible; there is no reliance 1230 on the garbage collector. $(D Array) uses $(D malloc) and $(D free) 1231 for managing its own memory. 1232 */ 1233 struct Array(T) if (!is(T : const(bool))) 1234 { 1235 // This structure is not copyable. 1236 private struct Payload 988 1237 { 989 1238 size_t _capacity; 990 1239 T[] _payload; 991 this(size_t c, T[] p) { _capacity = c; _payload = p; } 992 } 993 private Data * _data; 1240 1241 // Convenience constructor 1242 this(T[] p) { _capacity = p.length; _payload = p; } 1243 1244 // Destructor releases array memory 1245 ~this() 1246 { 1247 foreach (ref e; _payload) .clear(e); 1248 static if (hasIndirections!T) 1249 GC.removeRange(_payload.ptr); 1250 free(_payload.ptr); 1251 } 1252 1253 this(this) 1254 { 1255 assert(0); 1256 } 1257 1258 void opAssign(Array!(T).Payload rhs) 1259 { 1260 assert(false); 1261 } 1262 1263 // Duplicate data 1264 // @property Payload dup() 1265 // { 1266 // Payload result; 1267 // result._payload = _payload.dup; 1268 // // Conservatively assume initial capacity == length 1269 // result._capacity = result._payload.length; 1270 // return result; 1271 // } 1272 1273 // length 1274 @property size_t length() const 1275 { 1276 return _payload.length; 1277 } 1278 1279 // length 1280 @property void length(size_t newLength) 1281 { 1282 if (length >= newLength) 1283 { 1284 // shorten 1285 static if (is(T == struct) && hasElaborateDestructor!T) 1286 { 1287 foreach (ref e; _payload.ptr[newLength .. _payload.length]) 1288 { 1289 clear(e); 1290 } 1291 } 1292 _payload = _payload.ptr[0 .. newLength]; 1293 return; 1294 } 1295 // enlarge 1296 auto startEmplace = length; 1297 _payload = (cast(T*) realloc(_payload.ptr, 1298 T.sizeof * newLength))[0 .. newLength]; 1299 initializeAll(_payload.ptr[startEmplace .. length]); 1300 } 1301 1302 // capacity 1303 @property size_t capacity() const 1304 { 1305 return _capacity; 1306 } 1307 1308 // reserve 1309 void reserve(size_t elements) 1310 { 1311 if (elements <= capacity) return; 1312 immutable sz = elements * T.sizeof; 1313 static if (hasIndirections!T) // should use hasPointers instead 1314 { 1315 /* Because of the transactional nature of this 1316 * relative to the garbage collector, ensure no 1317 * threading bugs by using malloc/copy/free rather 1318 * than realloc. 1319 */ 1320 immutable oldLength = length; 1321 auto newPayload = 1322 enforce((cast(T*) malloc(sz))[0 .. oldLength]); 1323 // copy old data over to new array 1324 newPayload[] = _payload[]; 1325 // Zero out unused capacity to prevent gc from seeing 1326 // false pointers 1327 memset(newPayload.ptr + oldLength, 1328 0, 1329 (elements - oldLength) * T.sizeof); 1330 GC.addRange(newPayload.ptr, sz); 1331 GC.removeRange(_data._payload.ptr); 1332 free(_data._payload.ptr); 1333 _data._payload = newPayload; 1334 } 1335 else 1336 { 1337 /* These can't have pointers, so no need to zero 1338 * unused region 1339 */ 1340 auto newPayload = 1341 enforce(cast(T*) realloc(_payload.ptr, sz))[0 .. length]; 1342 _payload = newPayload; 1343 } 1344 _capacity = elements; 1345 } 1346 1347 // Insert one item 1348 size_t insertBack(Stuff)(Stuff stuff) 1349 if (isImplicitlyConvertible!(Stuff, T)) 1350 { 1351 if (_capacity == length) 1352 { 1353 reserve(1 + capacity * 3 / 2); 1354 } 1355 assert(capacity > length && _payload.ptr); 1356 emplace!T((cast(void*) (_payload.ptr + _payload.length)) 1357 [0 .. T.sizeof], 1358 stuff); 1359 _payload = _payload.ptr[0 .. _payload.length + 1]; 1360 return 1; 1361 } 1362 1363 /// Insert a range of items 1364 size_t insertBack(Stuff)(Stuff stuff) 1365 if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) 1366 { 1367 static if (hasLength!Stuff) 1368 { 1369 immutable oldLength = length; 1370 reserve(oldLength + stuff.length); 1371 } 1372 size_t result; 1373 foreach (item; stuff) 1374 { 1375 insertBack(item); 1376 ++result; 1377 } 1378 static if (hasLength!Stuff) 1379 { 1380 assert(length == oldLength + stuff.length); 1381 } 1382 return result; 1383 } 1384 } 1385 private alias RefCounted!(Payload, RefCountedAutoInitialize.no) Data; 1386 private Data _data; 994 1387 995 1388 this(U)(U[] values...) if (isImplicitlyConvertible!(U, T)) 996 1389 { 997 _data = new Data(values.length, new T[values.length]); 1390 auto p = malloc(T.sizeof * values.length); 1391 if (hasIndirections!T && p) 1392 { 1393 GC.addRange(p, T.sizeof * values.length); 1394 } 998 1395 foreach (i, e; values) 999 1396 { 1000 _data._payload[i] = e; 1001 } 1397 emplace!T(p[i * T.sizeof .. (i + 1) * T.sizeof], e); 1398 assert((cast(T*) p)[i] == e); 1399 } 1400 _data.RefCounted.initialize((cast(T*) p)[0 .. values.length]); 1002 1401 } 1003 1402 1004 1403 /** 1005 1404 Comparison for equality. 1006 1405 */ 1007 1406 bool opEquals(ref const Array rhs) const 1008 1407 { 1009 1408 if (empty) return rhs.empty; 1010 1409 if (rhs.empty) return false; 1011 1410 return _data._payload == rhs._data._payload; 1012 1411 } 1013 1412 1014 1413 /** 1015 1414 Defines the container's primary range, which is a random-access range. 1016 */ 1017 alias T[] Range; 1415 */ 1416 struct Range 1417 { 1418 private Array _outer; 1419 private size_t _a, _b; 1420 1421 this(Array data, size_t a, size_t b) 1422 { 1423 _outer = data; 1424 _a = a; 1425 _b = b; 1426 } 1427 1428 @property bool empty() const 1429 { 1430 assert(_outer.length >= _b); 1431 return _a >= _b; 1432 } 1433 1434 @property Range save() 1435 { 1436 return this; 1437 } 1438 1439 @property T front() 1440 { 1441 enforce(!empty); 1442 return _outer[_a]; 1443 } 1444 1445 @property void front(T value) 1446 { 1447 enforce(!empty); 1448 _outer[_a] = move(value); 1449 } 1450 1451 void popFront() 1452 { 1453 enforce(!empty); 1454 ++_a; 1455 } 1456 1457 T moveFront() 1458 { 1459 enforce(!empty); 1460 return move(_outer._data._payload[_a]); 1461 } 1462 1463 T moveBack() 1464 { 1465 enforce(!empty); 1466 return move(_outer._data._payload[_b - 1]); 1467 } 1468 1469 T moveAt(size_t i) 1470 { 1471 i += _a; 1472 enforce(i < _b && !empty); 1473 return move(_outer._data._payload[_a + i]); 1474 } 1475 1476 T opIndex(size_t i) 1477 { 1478 i += _a; 1479 enforce(i < _b && _b <= _outer.length); 1480 return _outer[i]; 1481 } 1482 1483 void opIndexAssign(T value, size_t i) 1484 { 1485 i += _a; 1486 enforce(i < _b && _b <= _outer.length); 1487 _outer[i] = value; 1488 } 1489 1490 void opIndexOpAssign(string op)(T value, size_t i) 1491 { 1492 enforce(_outer && _a + i < _b && _b <= _outer._payload.length); 1493 mixin("_outer._payload.ptr[_a + i] "~op~"= value;"); 1494 } 1495 } 1018 1496 1019 1497 /** 1020 1498 Property returning $(D true) if and only if the container has no 1021 1499 elements. 1022 1500 1023 1501 Complexity: $(BIGOH 1) 1024 1502 */ 1025 1503 @property bool empty() const 1026 1504 { 1027 return !_data || _data._payload.empty;1505 return !_data.RefCounted.isInitialized || _data._payload.empty; 1028 1506 } 1029 1507 1030 1508 /** 1031 1509 Duplicates the container. The elements themselves are not transitively 1032 1510 duplicated. 1033 1511 1034 1512 Complexity: $(BIGOH n). 1035 1513 */ 1036 1514 @property Array dup() 1037 1515 { 1038 if (!_data) return this; 1039 Array result; 1040 result._data = new Data(_data._capacity, _data._payload.dup); 1041 return result; 1516 if (!_data.RefCounted.isInitialized) return this; 1517 return Array(_data._payload); 1042 1518 } 1043 1519 1044 1520 /** 1045 1521 Returns the number of elements in the container. 1046 1522 1047 1523 Complexity: $(BIGOH 1). 1048 1524 */ 1049 1525 @property size_t length() const 1050 1526 { 1051 return _data ? _data._payload.length : 0;1527 return _data.RefCounted.isInitialized ? _data._payload.length : 0; 1052 1528 } 1053 1529 1054 1530 /** 1055 1531 Returns the maximum number of elements the container can store without 1056 1532 (a) allocating memory, (b) invalidating iterators upon insertion. 1057 1533 1058 1534 Complexity: $(BIGOH 1) 1059 1535 */ 1060 1536 @property size_t capacity() 1061 1537 { 1062 return _data ? _data._capacity : 0;1538 return _data.RefCounted.isInitialized ? _data._capacity : 0; 1063 1539 } 1064 1540 1065 1541 /** 1066 1542 Ensures sufficient capacity to accommodate $(D e) elements. 1067 1543 1068 1544 Postcondition: $(D capacity >= e) 1069 1545 1070 1546 Complexity: $(BIGOH 1) 1071 */ 1072 void reserve(size_t e) 1073 { 1074 if (!_data) 1075 { 1076 auto newPayload = (cast(T*) core.memory.GC.malloc( 1077 e * T.sizeof))[0 .. 0]; 1078 _data = new Data(e, newPayload); 1547 */ 1548 void reserve(size_t elements) 1549 { 1550 if (!_data.RefCounted.isInitialized) 1551 { 1552 if (!elements) return; 1553 immutable sz = elements * T.sizeof; 1554 auto p = enforce(malloc(sz)); 1555 static if (hasIndirections!T) 1556 { 1557 GC.addRange(p, sz); 1558 } 1559 _data.RefCounted.initialize(cast(T[]) p[0 .. 0]); 1560 _data._capacity = elements; 1079 1561 } 1080 1562 else 1081 1563 { 1082 if (e <= _data._capacity) return; 1083 auto newPayload = (cast(T*) core.memory.GC.realloc( 1084 _data._payload.ptr, 1085 e * T.sizeof))[0 .. _data._payload.length]; 1086 _data._payload = newPayload; 1087 _data._capacity = e; 1564 _data.reserve(elements); 1088 1565 } 1089 1566 } 1090 1567 1091 1568 /** 1092 1569 Returns a range that iterates over elements of the container, in 1093 1570 forward order. 1094 1571 1095 1572 Complexity: $(BIGOH 1) 1096 1573 */ 1097 1574 Range opSlice() 1098 1575 { 1099 return _data ? _data._payload : null; 1576 // Workaround for bug 4356 1577 Array copy; 1578 copy._data = this._data; 1579 return Range(copy, 0, length); 1100 1580 } 1101 1581 1102 1582 /** 1103 1583 Returns a range that iterates over elements of the container from 1104 1584 index $(D a) up to (excluding) index $(D b). 1105 1585 1106 1586 Precondition: $(D a <= b && b <= length) 1107 1587 1108 1588 Complexity: $(BIGOH 1) 1109 1589 */ 1110 1590 Range opSlice(size_t a, size_t b) 1111 1591 { 1112 1592 enforce(a <= b && b <= length); 1113 return _data ? _data._payload[a .. b] : (enforce(b == 0), (T[]).init); 1593 // Workaround for bug 4356 1594 Array copy; 1595 copy._data = this._data; 1596 return Range(copy, a, b); 1114 1597 } 1115 1598 1116 1599 /** 1117 1600 @@@BUG@@@ This doesn't work yet 1118 1601 */ 1119 1602 size_t opDollar() const 1120 1603 { 1121 1604 return length; 1122 1605 } 1123 1606 … … 1157 1640 1158 1641 /** 1159 1642 Indexing operators yield or modify the value at a specified index. 1160 1643 1161 1644 Precondition: $(D i < length) 1162 1645 1163 1646 Complexity: $(BIGOH 1) 1164 1647 */ 1165 1648 T opIndex(size_t i) 1166 1649 { 1167 enforce(_data );1650 enforce(_data.RefCounted.isInitialized); 1168 1651 return _data._payload[i]; 1169 1652 } 1170 1653 1171 1654 /// ditto 1172 1655 void opIndexAssign(T value, size_t i) 1173 1656 { 1174 enforce(_data );1657 enforce(_data.RefCounted.isInitialized); 1175 1658 _data._payload[i] = value; 1176 1659 } 1177 1660 1178 1661 /// ditto 1179 1662 void opIndexOpAssign(string op)(T value, size_t i) 1180 1663 { 1181 1664 mixin("_data._payload[i] "~op~"= value;"); 1182 1665 } 1183 1666 1184 1667 /** 1185 1668 Returns a new container that's the concatenation of $(D this) and its 1186 1669 argument. $(D opBinaryRight) is only defined if $(D Stuff) does not 1187 1670 define $(D opBinary). 1188 1671 1189 1672 Complexity: $(BIGOH n + m), where m is the number of elements in $(D 1190 1673 stuff) 1191 1674 */ 1192 1675 Array opBinary(string op, Stuff)(Stuff stuff) if (op == "~") 1193 1676 { 1194 1677 // TODO: optimize 1195 auto result = Array(this[]); 1196 result ~= stuff; 1678 Array result; 1679 // @@@BUG@@ result ~= this[] doesn't work 1680 auto r = this[]; 1681 result ~= r; 1682 assert(result.length == length); 1683 result ~= stuff[]; 1197 1684 return result; 1198 1685 } 1199 1686 1200 1687 /** 1201 1688 Forwards to $(D insertBack(stuff)). 1202 1689 */ 1203 1690 void opOpAssign(string op, Stuff)(Stuff stuff) if (op == "~") 1204 1691 { 1205 1692 static if (is(typeof(stuff[]))) 1206 1693 { … … 1215 1702 /** 1216 1703 Removes all contents from the container. The container decides how $(D 1217 1704 capacity) is affected. 1218 1705 1219 1706 Postcondition: $(D empty) 1220 1707 1221 1708 Complexity: $(BIGOH n) 1222 1709 */ 1223 1710 void clear() 1224 1711 { 1225 _data = null;1712 .clear(_data); 1226 1713 } 1227 1714 1228 1715 /** 1229 1716 Sets the number of elements in the container to $(D newSize). If $(D 1230 1717 newSize) is greater than $(D length), the added elements are added to 1231 1718 unspecified positions in the container and initialized with $(D 1232 ElementType.init).1719 T.init). 1233 1720 1234 1721 Complexity: $(BIGOH abs(n - newLength)) 1235 1722 1236 1723 Postcondition: $(D length == newLength) 1237 1724 */ 1238 1725 @property void length(size_t newLength) 1239 1726 { 1240 if (!_data) 1241 { 1242 _data = new Data(newLength, new T[newLength]); 1243 } 1244 else 1245 { 1246 _data._payload.length = newLength; 1247 if (newLength > capacity) 1248 { 1249 _data._capacity = newLength; 1250 } 1251 } 1727 _data.RefCounted.ensureInitialized(); 1728 _data.length = newLength; 1252 1729 } 1253 1730 1254 1731 /** 1255 1732 Picks one value in an unspecified position in the container, removes 1256 1733 it from the container, and returns it. Implementations should pick the 1257 1734 value that's the most advantageous for the container, but document the 1258 1735 exact behavior. The stable version behaves the same, but guarantees 1259 1736 that ranges iterating over the container are never invalidated. 1260 1737 1261 1738 Precondition: $(D !empty) … … 1268 1745 { 1269 1746 auto result = back; 1270 1747 removeBack(); 1271 1748 return result; 1272 1749 } 1273 1750 /// ditto 1274 1751 alias removeAny stableRemoveAny; 1275 1752 1276 1753 /** 1277 1754 Inserts $(D value) to the front or back of the container. $(D stuff) 1278 can be a value convertible to $(D ElementType) or a range of objects 1279 convertible to $(D ElementType). The stable version behaves the same, 1280 but guarantees that ranges iterating over the container are never 1281 invalidated. 1755 can be a value convertible to $(D T) or a range of objects convertible 1756 to $(D T). The stable version behaves the same, but guarantees that 1757 ranges iterating over the container are never invalidated. 1282 1758 1283 1759 Returns: The number of elements inserted 1284 1760 1285 1761 Complexity: $(BIGOH m * log(n)), where $(D m) is the number of 1286 1762 elements in $(D stuff) 1287 1763 */ 1288 1764 size_t insertBack(Stuff)(Stuff stuff) 1289 if (isImplicitlyConvertible!(Stuff, T)) 1290 { 1291 if (capacity == length) 1292 { 1293 reserve(1 + capacity * 3 / 2); 1294 } 1295 _data._payload = _data._payload.ptr[0 .. _data._payload.length + 1]; 1296 _data._payload[$ - 1] = stuff; 1297 return 1; 1298 } 1299 1300 /// ditto 1301 size_t insertBack(Stuff)(Stuff stuff) 1302 if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) 1303 { 1304 size_t result; 1305 foreach (item; stuff) 1306 { 1307 insertBack(item); 1308 ++result; 1309 } 1310 return result; 1765 if (isImplicitlyConvertible!(Stuff, T) || 1766 isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) 1767 { 1768 _data.RefCounted.ensureInitialized(); 1769 return _data.insertBack(stuff); 1311 1770 } 1312 1771 /// ditto 1313 1772 alias insertBack insert; 1314 1773 1315 1774 /** 1316 1775 Removes the value at the back of the container. The stable version 1317 1776 behaves the same, but guarantees that ranges iterating over the 1318 1777 container are never invalidated. 1319 1778 1320 1779 Precondition: $(D !empty) 1321 1780 1322 1781 Complexity: $(BIGOH log(n)). 1323 1782 */ 1324 1783 void removeBack() 1325 1784 { 1326 1785 enforce(!empty); 1786 static if (is(T == struct)) 1787 { 1788 // Destroy this guy 1789 clear(_data._payload[$ - 1]); 1790 } 1327 1791 _data._payload = _data._payload[0 .. $ - 1]; 1328 1792 } 1329 1793 /// ditto 1330 1794 alias removeBack stableRemoveBack; 1331 1795 1332 1796 /** 1333 1797 Removes $(D howMany) values at the front or back of the 1334 1798 container. Unlike the unparameterized versions above, these functions 1335 1799 do not throw if they could not remove $(D howMany) elements. Instead, 1336 1800 if $(D howMany > n), all elements are removed. The returned value is … … 1338 1802 the same, but guarantees that ranges iterating over the container are 1339 1803 never invalidated. 1340 1804 1341 1805 Returns: The number of elements removed 1342 1806 1343 1807 Complexity: $(BIGOH howMany). 1344 1808 */ 1345 1809 size_t removeBack(size_t howMany) 1346 1810 { 1347 1811 if (howMany > length) howMany = length; 1812 static if (is(T == struct)) 1813 { 1814 // Destroy this guy 1815 foreach (ref e; _data._payload[$ - howMany .. $]) 1816 { 1817 clear(e); 1818 } 1819 } 1348 1820 _data._payload = _data._payload[0 .. $ - howMany]; 1349 1821 return howMany; 1350 1822 } 1351 1823 /// ditto 1352 1824 alias removeBack stableRemoveBack; 1353 1825 1354 1826 /** 1355 1827 Inserts $(D stuff) before, after, or instead range $(D r), which must 1356 1828 be a valid range previously extracted from this container. $(D stuff) 1357 can be a value convertible to $(D ElementType) or a range of objects 1358 convertible to $(D ElementType). The stable version behaves the same, 1359 but guarantees that ranges iterating over the container are never 1360 invalidated. 1829 can be a value convertible to $(D T) or a range of objects convertible 1830 to $(D T). The stable version behaves the same, but guarantees that 1831 ranges iterating over the container are never invalidated. 1361 1832 1362 1833 Returns: The number of values inserted. 1363 1834 1364 1835 Complexity: $(BIGOH n + m), where $(D m) is the length of $(D stuff) 1365 */ 1366 size_t insertBefore(Stuff)(Range r, Stuff stuff) 1367 { 1368 // TODO: optimize 1369 enforce(_data); 1370 immutable offset = r.ptr - _data._payload.ptr; 1371 enforce(offset <= length); 1372 auto result = insertBack(stuff); 1373 bringToFront(this[offset .. length - result], 1374 this[length - result .. length]); 1375 return result; 1376 } 1377 1378 /// ditto 1379 size_t insertAfter(Stuff)(Range r, Stuff stuff) 1380 { 1381 // TODO: optimize 1382 enforce(_data); 1383 immutable offset = r.ptr + r.length - _data._payload.ptr; 1384 enforce(offset <= length); 1385 auto result = insertBack(stuff); 1386 bringToFront(this[offset .. length - result], 1387 this[length - result .. length]); 1388 return result; 1389 } 1390 1391 /// ditto 1392 size_t replace(Stuff)(Range r, Stuff stuff) 1393 if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) 1394 { 1395 enforce(_data); 1396 immutable offset = r.ptr - _data._payload.ptr; 1397 enforce(offset <= length); 1398 size_t result; 1399 for (; !stuff.empty; stuff.popFront()) 1400 { 1401 if (r.empty) 1402 { 1403 // append the rest 1404 return result + insertBack(stuff); 1405 } 1406 r.front = stuff.front; 1407 r.popFront(); 1408 ++result; 1409 } 1410 // Remove remaining stuff in r 1411 remove(r); 1412 return result; 1413 } 1414 1415 /// ditto 1416 size_t replace(Stuff)(Range r, Stuff stuff) 1417 if (isImplicitlyConvertible!(Stuff, T)) 1418 { 1419 if (r.empty) 1420 { 1421 insertBefore(r, stuff); 1422 } 1423 else 1424 { 1425 r.front = stuff; 1426 r.popFront(); 1427 remove(r); 1428 } 1429 return 1; 1430 } 1431 1432 /** 1433 Removes all elements belonging to $(D r), which must be a range 1434 obtained originally from this container. The stable version behaves 1435 the same, but guarantees that ranges iterating over the container are 1436 never invalidated. 1437 1438 Returns: A range spanning the remaining elements in the container that 1439 initially were right after $(D r). 1440 1441 Complexity: $(BIGOH n - m), where $(D m) is the number of elements in 1442 $(D r) 1443 */ 1444 Range linearRemove(Range r) 1445 { 1446 enforce(_data); 1447 immutable offset1 = r.ptr - _data._payload.ptr; 1448 immutable offset2 = offset1 + r.length; 1449 enforce(offset1 <= offset2 && offset2 <= length); 1450 immutable tailLength = length - offset2; 1451 // Use copy here, not a[] = b[] because the ranges may overlap 1452 copy(this[offset2 .. length], this[offset1 .. offset1 + tailLength]); 1453 length = offset1 + tailLength; 1454 return this[length - tailLength .. length]; 1455 } 1456 1457 /// ditto 1458 alias remove stableLinearRemove; 1459 1460 } 1461 1462 unittest 1463 { 1464 Array!int a; 1465 assert(a.empty); 1466 } 1467 1468 unittest 1469 { 1470 auto a = Array!int(1, 2, 3); 1471 auto b = a.dup; 1472 assert(b == Array!int(1, 2, 3)); 1473 b.front = 42; 1474 assert(b == Array!int(42, 2, 3)); 1475 assert(a == Array!int(1, 2, 3)); 1476 } 1477 1478 unittest 1479 { 1480 auto a = Array!int(1, 2, 3); 1481 assert(a.length == 3); 1482 } 1483 1484 unittest 1485 { 1486 Array!int a; 1487 a.reserve(1000); 1488 assert(a.length == 0); 1489 assert(a.empty); 1490 assert(a.capacity >= 1000); 1491 auto p = a._data._payload.ptr; 1492 foreach (i; 0 .. 1000) 1493 { 1494 a.insertBack(i); 1495 } 1496 assert(p == a._data._payload.ptr); 1497 } 1498 1499 unittest 1500 { 1501 auto a = Array!int(1, 2, 3); 1502 a[1] *= 42; 1503 assert(a[1] == 84); 1504 } 1505 1506 unittest 1507 { 1508 auto a = Array!int(1, 2, 3); 1509 auto b = Array!int(11, 12, 13); 1510 assert(a ~ b == Array!int(1, 2, 3, 11, 12, 13)); 1511 assert(a ~ b[] == Array!int(1, 2, 3, 11, 12, 13)); 1512 } 1513 1514 unittest 1515 { 1516 auto a = Array!int(1, 2, 3); 1517 auto b = Array!int(11, 12, 13); 1518 a ~= b; 1519 assert(a == Array!int(1, 2, 3, 11, 12, 13)); 1520 } 1521 1522 unittest 1523 { 1524 auto a = Array!int(1, 2, 3, 4); 1525 assert(a.removeAny() == 4); 1526 assert(a == Array!int(1, 2, 3)); 1527 } 1528 1529 unittest 1530 { 1531 auto a = Array!int(1, 2, 3, 4, 5); 1532 auto r = a[2 .. a.length]; 1533 assert(a.insertBefore(r, 42) == 1); 1534 assert(a == Array!int(1, 2, 42, 3, 4, 5)); 1535 r = a[2 .. 2]; 1536 assert(a.insertBefore(r, [8, 9]) == 2); 1537 assert(a == Array!int(1, 2, 8, 9, 42, 3, 4, 5)); 1538 } 1539 1540 unittest 1541 { 1542 auto a = Array!int(0, 1, 2, 3, 4, 5, 6, 7, 8); 1543 a.linearRemove(a[4 .. 6]); 1544 assert(a == Array!int(0, 1, 2, 3, 6, 7, 8)); 1545 } 1546 } 1547 1548 /** 1549 Array type with deterministic control of memory. The memory allocated 1550 for the array is reclaimed as soon as possible; there is no reliance 1551 on the garbage collector. 1552 */ 1553 struct Array(T) 1554 { 1555 private struct Data 1556 { 1557 uint _refCount = 1; 1558 size_t _capacity; 1559 T[] _payload; 1560 this(T[] p) { _capacity = p.length; _payload = p; } 1561 } 1562 private Data * _data; 1563 1564 this(U)(U[] values...) if (isImplicitlyConvertible!(U, T)) 1565 { 1566 auto p = malloc(T.sizeof * values.length); 1567 if (T.sizeof >= size_t.sizeof && p) 1568 GC.addRange(p, T.sizeof * values.length); 1569 _data = emplace!Data( 1570 malloc(Data.sizeof)[0 .. Data.sizeof], 1571 (cast(T*) p)[0 .. values.length]); 1572 assert(_data._refCount == 1); 1573 foreach (i, e; values) 1574 { 1575 emplace!T((cast(void*) &_data._payload[i])[0 .. T.sizeof], e); 1576 assert(_data._payload[i] == e); 1577 } 1578 } 1579 1580 this(this) 1581 { 1582 if (_data) 1583 { 1584 ++_data._refCount; 1585 } 1586 } 1587 1588 ~this() 1589 { 1590 if (!_data) return; 1591 if (_data._refCount > 1) 1592 { 1593 --_data._refCount; 1594 return; 1595 } 1596 assert(_data._refCount == 1); 1597 --_data._refCount; 1598 foreach (ref e; _data._payload) .clear(e); 1599 if (T.sizeof >= size_t.sizeof) 1600 GC.removeRange(_data._payload.ptr); 1601 free(_data._payload.ptr); 1602 free(_data); 1603 _data = null; 1604 } 1605 1606 void opAssign(Array another) 1607 { 1608 swap(this, another); 1609 } 1610 1611 /** 1612 Comparison for equality. 1613 */ 1614 bool opEquals(ref const Array rhs) const 1615 { 1616 if (empty) return rhs.empty; 1617 if (rhs.empty) return false; 1618 return _data._payload == rhs._data._payload; 1619 } 1620 1621 /** 1622 Defines the container's primary range, which is a random-access range. 1623 */ 1624 struct Range 1625 { 1626 private Data * _data; 1627 private size_t _a, _b; 1628 1629 private this(Data * data, size_t a, size_t b) 1630 { 1631 _data = data; 1632 if (!_data) 1633 { 1634 assert(a == 0 && b == 0); 1635 return; 1636 } 1637 ++_data._refCount; 1638 _a = a; 1639 _b = b; 1640 } 1641 1642 this(this) 1643 { 1644 if (_data) 1645 { 1646 ++_data._refCount; 1647 } 1648 } 1649 1650 ~this() 1651 { 1652 if (!_data) return; 1653 if (_data._refCount > 1) 1654 { 1655 --_data._refCount; 1656 return; 1657 } 1658 assert(_data._refCount == 1); 1659 foreach (ref e; _data._payload) .clear(e); 1660 free(_data._payload.ptr); 1661 free(_data); 1662 _data = null; 1663 _a = _b = 0; 1664 } 1665 1666 void opAssign(Range another) 1667 { 1668 swap(this, another); 1669 } 1670 1671 @property bool empty() const 1672 { 1673 return !_data || _a == _b || _data._payload.length <= _a; 1674 } 1675 1676 @property Range save() 1677 { 1678 return this; 1679 } 1680 1681 @property T front() 1682 { 1683 enforce(_data && _a < _data._payload.length); 1684 return _data._payload[_a]; 1685 } 1686 1687 void popFront() 1688 { 1689 enforce(!empty); 1690 ++_a; 1691 } 1692 1693 void put(T e) 1694 { 1695 enforce(!empty); 1696 _data._payload[_a] = e; 1697 popFront(); 1698 } 1699 1700 T moveFront() 1701 { 1702 enforce(_data && _a < _data._payload.length); 1703 return move(_data._payload[_a]); 1704 } 1705 1706 T moveBack() 1707 { 1708 enforce(_data && _b <= _data._payload.length); 1709 return move(_data._payload[_b - 1]); 1710 } 1711 1712 T moveAt(size_t i) 1713 { 1714 enforce(_data && _a + i < _b && _b <= _data._payload.length); 1715 return move(_data._payload[_a + i]); 1716 } 1717 1718 T opIndex(size_t i) 1719 { 1720 enforce(_data && _a + i < _b && _b <= _data._payload.length); 1721 return _data._payload.ptr[_a + i]; 1722 } 1723 1724 void opIndexAssign(T value, size_t i) 1725 { 1726 enforce(_data && _a + i < _b && _b <= _data._payload.length); 1727 swap(_data._payload.ptr[_a + i], value); 1728 } 1729 1730 void opIndexOpAssign(string op)(T value, size_t i) 1731 { 1732 enforce(_data && _a + i < _b && _b <= _data._payload.length); 1733 mixin("_data._payload.ptr[_a + i] "~op~"= value;"); 1734 } 1735 } 1736 1737 /** 1738 Property returning $(D true) if and only if the container has no 1739 elements. 1740 1741 Complexity: $(BIGOH 1) 1742 */ 1743 @property bool empty() const 1744 { 1745 return !_data || _data._payload.empty; 1746 } 1747 1748 /** 1749 Duplicates the container. The elements themselves are not transitively 1750 duplicated. 1751 1752 Complexity: $(BIGOH n). 1753 */ 1754 @property Array dup() 1755 { 1756 if (!_data) return this; 1757 return Array(_data._payload); 1758 } 1759 1760 /** 1761 Returns the number of elements in the container. 1762 1763 Complexity: $(BIGOH 1). 1764 */ 1765 @property size_t length() const 1766 { 1767 return _data ? _data._payload.length : 0; 1768 } 1769 1770 /** 1771 Returns the maximum number of elements the container can store without 1772 (a) allocating memory, (b) invalidating iterators upon insertion. 1773 1774 Complexity: $(BIGOH 1) 1775 */ 1776 @property size_t capacity() 1777 { 1778 return _data ? _data._capacity : 0; 1779 } 1780 1781 /** 1782 Ensures sufficient capacity to accommodate $(D e) elements. 1783 1784 Postcondition: $(D capacity >= e) 1785 1786 Complexity: $(BIGOH 1) 1787 */ 1788 void reserve(size_t elements) 1789 { 1790 if (!_data) 1791 { 1792 auto p = malloc(elements * T.sizeof); 1793 if (T.sizeof >= size_t.sizeof && p) // should use hasPointers instead 1794 GC.addRange(p, T.sizeof * elements); 1795 _data = emplace!Data(malloc(Data.sizeof)[0 .. Data.sizeof], 1796 (cast(T*) p)[0 .. 0]); 1797 _data._capacity = elements; 1798 } 1799 else 1800 { 1801 if (elements <= _data._capacity) return; 1802 1803 auto sz = elements * T.sizeof; 1804 if (T.sizeof >= size_t.sizeof) // should use hasPointers instead 1805 { 1806 /* Because of the transactional nature of this relative to the 1807 * garbage collector, ensure no threading bugs by using malloc/copy/free 1808 * rather than realloc. 1809 */ 1810 auto newPayload = (cast(T*) malloc(sz))[0 .. _data._payload.length]; 1811 newPayload || assert(false); 1812 newPayload[] = _data._payload[]; // copy old data over to new array 1813 // Zero out unused capacity to prevent gc from seeing false pointers 1814 memset(newPayload.ptr + _data._payload.length, 1815 0, 1816 (elements - _data._payload.length) * T.sizeof); 1817 GC.addRange(newPayload.ptr, sz); 1818 GC.removeRange(_data._payload.ptr); 1819 free(_data._payload.ptr); 1820 _data._payload = newPayload; 1821 } 1822 else 1823 { 1824 /* These can't have pointers, so no need to zero unused region 1825 */ 1826 auto newPayload = (cast(T*) realloc(_data._payload.ptr, sz)) 1827 [0 .. _data._payload.length]; 1828 newPayload || assert(false); 1829 _data._payload = newPayload; 1830 } 1831 _data._capacity = elements; 1832 } 1833 } 1834 1835 /** 1836 Returns a range that iterates over elements of the container, in 1837 forward order. 1838 1839 Complexity: $(BIGOH 1) 1840 */ 1841 Range opSlice() 1842 { 1843 return Range(_data, 0, length); 1844 } 1845 1846 /** 1847 Returns a range that iterates over elements of the container from 1848 index $(D a) up to (excluding) index $(D b). 1849 1850 Precondition: $(D a <= b && b <= length) 1851 1852 Complexity: $(BIGOH 1) 1853 */ 1854 Range opSlice(size_t a, size_t b) 1855 { 1856 enforce(a <= b && b <= length); 1857 return Range(_data, a, b); 1858 } 1859 1860 /** 1861 @@@BUG@@@ This doesn't work yet 1862 */ 1863 size_t opDollar() const 1864 { 1865 return length; 1866 } 1867 1868 /** 1869 Forward to $(D opSlice().front) and $(D opSlice().back), respectively. 1870 1871 Precondition: $(D !empty) 1872 1873 Complexity: $(BIGOH 1) 1874 */ 1875 @property T front() 1876 { 1877 enforce(!empty); 1878 return *_data._payload.ptr; 1879 } 1880 1881 /// ditto 1882 @property void front(T value) 1883 { 1884 enforce(!empty); 1885 *_data._payload.ptr = value; 1886 } 1887 1888 /// ditto 1889 @property T back() 1890 { 1891 enforce(!empty); 1892 return _data._payload[$ - 1]; 1893 } 1894 1895 /// ditto 1896 @property void back(T value) 1897 { 1898 enforce(!empty); 1899 _data._payload[$ - 1] = value; 1900 } 1901 1902 /** 1903 Indexing operators yield or modify the value at a specified index. 1904 1905 Precondition: $(D i < length) 1906 1907 Complexity: $(BIGOH 1) 1908 */ 1909 T opIndex(size_t i) 1910 { 1911 enforce(_data); 1912 return _data._payload[i]; 1913 } 1914 1915 /// ditto 1916 void opIndexAssign(T value, size_t i) 1917 { 1918 enforce(_data); 1919 _data._payload[i] = value; 1920 } 1921 1922 /// ditto 1923 void opIndexOpAssign(string op)(T value, size_t i) 1924 { 1925 mixin("_data._payload[i] "~op~"= value;"); 1926 } 1927 1928 /** 1929 Returns a new container that's the concatenation of $(D this) and its 1930 argument. $(D opBinaryRight) is only defined if $(D Stuff) does not 1931 define $(D opBinary). 1932 1933 Complexity: $(BIGOH n + m), where m is the number of elements in $(D 1934 stuff) 1935 */ 1936 Array opBinary(string op, Stuff)(Stuff stuff) if (op == "~") 1937 { 1938 // TODO: optimize 1939 Array result; 1940 result ~= this[]; 1941 result ~= stuff; 1942 return result; 1943 } 1944 1945 /** 1946 Forwards to $(D insertBack(stuff)). 1947 */ 1948 void opOpAssign(string op, Stuff)(Stuff stuff) if (op == "~") 1949 { 1950 static if (is(typeof(stuff[]))) 1951 { 1952 insertBack(stuff[]); 1953 } 1954 else 1955 { 1956 insertBack(stuff); 1957 } 1958 } 1959 1960 /** 1961 Removes all contents from the container. The container decides how $(D 1962 capacity) is affected. 1963 1964 Postcondition: $(D empty) 1965 1966 Complexity: $(BIGOH n) 1967 */ 1968 void clear() 1969 { 1970 _data = null; 1971 } 1972 1973 /** 1974 Sets the number of elements in the container to $(D newSize). If $(D 1975 newSize) is greater than $(D length), the added elements are added to 1976 unspecified positions in the container and initialized with $(D 1977 ElementType.init). 1978 1979 Complexity: $(BIGOH abs(n - newLength)) 1980 1981 Postcondition: $(D length == newLength) 1982 */ 1983 @property void length(size_t newLength) 1984 { 1985 size_t startEmplace = void; 1986 if (!_data) 1987 { 1988 _data = emplace!Data(malloc(Data.sizeof)[0 .. Data.sizeof], 1989 (cast(T*) malloc(T.sizeof * newLength))[0 .. newLength]); 1990 startEmplace = 0; 1991 } 1992 else 1993 { 1994 if (length >= newLength) 1995 { 1996 // shorten 1997 _data._payload = _data._payload.ptr[0 .. newLength]; 1998 return; 1999 } 2000 else 2001 { 2002 // enlarge 2003 startEmplace = length; 2004 _data._payload = (cast(T*) realloc(_data._payload.ptr, 2005 T.sizeof * newLength))[0 .. newLength]; 2006 } 2007 } 2008 foreach (ref e; _data._payload[startEmplace .. $]) 2009 { 2010 static init = T.init; 2011 memcpy(&e, &init, T.sizeof); 2012 } 2013 } 2014 2015 /** 2016 Picks one value in an unspecified position in the container, removes 2017 it from the container, and returns it. Implementations should pick the 2018 value that's the most advantageous for the container, but document the 2019 exact behavior. The stable version behaves the same, but guarantees 2020 that ranges iterating over the container are never invalidated. 2021 2022 Precondition: $(D !empty) 2023 2024 Returns: The element removed. 2025 2026 Complexity: $(BIGOH log(n)). 2027 */ 2028 T removeAny() 2029 { 2030 auto result = back; 2031 removeBack(); 2032 return result; 2033 } 2034 /// ditto 2035 alias removeAny stableRemoveAny; 2036 2037 /** 2038 Inserts $(D value) to the front or back of the container. $(D stuff) 2039 can be a value convertible to $(D ElementType) or a range of objects 2040 convertible to $(D ElementType). The stable version behaves the same, 2041 but guarantees that ranges iterating over the container are never 2042 invalidated. 2043 2044 Returns: The number of elements inserted 2045 2046 Complexity: $(BIGOH m * log(n)), where $(D m) is the number of 2047 elements in $(D stuff) 2048 */ 2049 size_t insertBack(Stuff)(Stuff stuff) 2050 if (isImplicitlyConvertible!(Stuff, T)) 2051 { 2052 if (capacity == length) 2053 { 2054 reserve(1 + capacity * 3 / 2); 2055 assert(capacity > length); 2056 } 2057 assert(_data); 2058 emplace!T((cast(void*) (_data._payload.ptr + _data._payload.length)) 2059 [0 .. T.sizeof], 2060 stuff); 2061 _data._payload = _data._payload.ptr[0 .. _data._payload.length + 1]; 2062 return 1; 2063 } 2064 2065 /// ditto 2066 size_t insertBack(Stuff)(Stuff stuff) 2067 if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) 2068 { 2069 size_t result; 2070 foreach (item; stuff) 2071 { 2072 insertBack(item); 2073 ++result; 2074 } 2075 return result; 2076 } 2077 /// ditto 2078 alias insertBack insert; 2079 2080 /** 2081 Removes the value at the back of the container. The stable version 2082 behaves the same, but guarantees that ranges iterating over the 2083 container are never invalidated. 2084 2085 Precondition: $(D !empty) 2086 2087 Complexity: $(BIGOH log(n)). 2088 */ 2089 void removeBack() 2090 { 2091 enforce(!empty); 2092 _data._payload = _data._payload[0 .. $ - 1]; 2093 } 2094 /// ditto 2095 alias removeBack stableRemoveBack; 2096 2097 /** 2098 Removes $(D howMany) values at the front or back of the 2099 container. Unlike the unparameterized versions above, these functions 2100 do not throw if they could not remove $(D howMany) elements. Instead, 2101 if $(D howMany > n), all elements are removed. The returned value is 2102 the effective number of elements removed. The stable version behaves 2103 the same, but guarantees that ranges iterating over the container are 2104 never invalidated. 2105 2106 Returns: The number of elements removed 2107 2108 Complexity: $(BIGOH howMany). 2109 */ 2110 size_t removeBack(size_t howMany) 2111 { 2112 if (howMany > length) howMany = length; 2113 _data._payload = _data._payload[0 .. $ - howMany]; 2114 return howMany; 2115 } 2116 /// ditto 2117 alias removeBack stableRemoveBack; 2118 2119 /** 2120 Inserts $(D stuff) before, after, or instead range $(D r), which must 2121 be a valid range previously extracted from this container. $(D stuff) 2122 can be a value convertible to $(D ElementType) or a range of objects 2123 convertible to $(D ElementType). The stable version behaves the same, 2124 but guarantees that ranges iterating over the container are never 2125 invalidated. 2126 2127 Returns: The number of values inserted. 2128 2129 Complexity: $(BIGOH n + m), where $(D m) is the length of $(D stuff) 2130 */ 1836 */ 2131 1837 size_t insertBefore(Stuff)(Range r, Stuff stuff) 2132 1838 if (isImplicitlyConvertible!(Stuff, T)) 2133 1839 { 2134 enforce(r._ data == _data && r._a < length);1840 enforce(r._outer._data == _data && r._a < length); 2135 1841 reserve(length + 1); 2136 assert(_data );1842 assert(_data.RefCounted.isInitialized); 2137 1843 // Move elements over by one slot 2138 1844 memmove(_data._payload.ptr + r._a + 1, 2139 1845 _data._payload.ptr + r._a, 2140 1846 T.sizeof * (length - r._a)); 2141 1847 emplace!T((cast(void*) (_data._payload.ptr + r._a))[0 .. T.sizeof], 2142 1848 stuff); 2143 1849 _data._payload = _data._payload.ptr[0 .. _data._payload.length + 1]; 2144 1850 return 1; 2145 1851 } 2146 1852 2147 1853 /// ditto 2148 1854 size_t insertBefore(Stuff)(Range r, Stuff stuff) 2149 1855 if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, T)) 2150 1856 { 2151 enforce(r._ data == _data && r._a <length);1857 enforce(r._outer._data == _data && r._a <= length); 2152 1858 static if (isForwardRange!Stuff) 2153 1859 { 2154 1860 // Can find the length in advance 2155 1861 auto extra = walkLength(stuff); 2156 1862 if (!extra) return 0; 2157 1863 reserve(length + extra); 2158 assert(_data );1864 assert(_data.RefCounted.isInitialized); 2159 1865 // Move elements over by extra slots 2160 1866 memmove(_data._payload.ptr + r._a + extra, 2161 1867 _data._payload.ptr + r._a, 2162 1868 T.sizeof * (length - r._a)); 2163 1869 foreach (p; _data._payload.ptr + r._a .. 2164 1870 _data._payload.ptr + r._a + extra) 2165 1871 { 2166 1872 emplace!T((cast(void*) p)[0 .. T.sizeof], stuff.front); 2167 1873 stuff.popFront(); 2168 1874 } … … 2243 1949 never invalidated. 2244 1950 2245 1951 Returns: A range spanning the remaining elements in the container that 2246 1952 initially were right after $(D r). 2247 1953 2248 1954 Complexity: $(BIGOH n - m), where $(D m) is the number of elements in 2249 1955 $(D r) 2250 1956 */ 2251 1957 Range linearRemove(Range r) 2252 1958 { 2253 enforce(_data );1959 enforce(_data.RefCounted.isInitialized); 2254 1960 enforce(r._a <= r._b && r._b <= length); 2255 1961 immutable offset1 = r._a; 2256 1962 immutable offset2 = r._b; 2257 1963 immutable tailLength = length - offset2; 2258 1964 // Use copy here, not a[] = b[] because the ranges may overlap 2259 1965 copy(this[offset2 .. length], this[offset1 .. offset1 + tailLength]); 2260 1966 length = offset1 + tailLength; 2261 1967 return this[length - tailLength .. length]; 2262 1968 } 2263 1969 2264 1970 /// ditto 2265 1971 alias remove stableLinearRemove; 2266 1972 2267 1973 } 2268 1974 1975 // unittest 1976 // { 1977 // Array!int a; 1978 // assert(a.empty); 1979 // } 1980 2269 1981 unittest 2270 1982 { 2271 Array!int a; 2272 assert(a.empty); 2273 } 2274 2275 unittest 2276 { 2277 auto a = Array!int(1, 2, 3); 1983 Array!int a = Array!int(1, 2, 3); 1984 //a._data._refCountedDebug = true; 2278 1985 auto b = a.dup; 2279 1986 assert(b == Array!int(1, 2, 3)); 2280 1987 b.front = 42; 2281 1988 assert(b == Array!int(42, 2, 3)); 2282 1989 assert(a == Array!int(1, 2, 3)); 2283 1990 } 2284 1991 2285 1992 unittest 2286 1993 { 2287 1994 auto a = Array!int(1, 2, 3); … … 2307 2014 { 2308 2015 auto a = Array!int(1, 2, 3); 2309 2016 a[1] *= 42; 2310 2017 assert(a[1] == 84); 2311 2018 } 2312 2019 2313 2020 unittest 2314 2021 { 2315 2022 auto a = Array!int(1, 2, 3); 2316 2023 auto b = Array!int(11, 12, 13); 2317 assert(a ~ b == Array!int(1, 2, 3, 11, 12, 13)); 2318 assert(a ~ b[] == Array!int(1, 2, 3, 11, 12, 13)); 2024 auto c = a ~ b; 2025 //foreach (e; c) writeln(e); 2026 assert(c == Array!int(1, 2, 3, 11, 12, 13)); 2027 //assert(a ~ b[] == Array!int(1, 2, 3, 11, 12, 13)); 2319 2028 } 2320 2029 2321 2030 unittest 2322 2031 { 2323 2032 auto a = Array!int(1, 2, 3); 2324 2033 auto b = Array!int(11, 12, 13); 2325 2034 a ~= b; 2326 2035 assert(a == Array!int(1, 2, 3, 11, 12, 13)); 2327 2036 } 2328 2037 … … 2342 2051 r = a[2 .. 2]; 2343 2052 assert(a.insertBefore(r, [8, 9]) == 2); 2344 2053 assert(a == Array!int(1, 2, 8, 9, 42, 3, 4, 5)); 2345 2054 } 2346 2055 2347 2056 unittest 2348 2057 { 2349 2058 auto a = Array!int(0, 1, 2, 3, 4, 5, 6, 7, 8); 2350 2059 a.linearRemove(a[4 .. 6]); 2351 2060 auto b = Array!int(0, 1, 2, 3, 6, 7, 8); 2061 //writeln(a.length); 2062 //foreach (e; a) writeln(e); 2352 2063 assert(a == Array!int(0, 1, 2, 3, 6, 7, 8)); 2353 2064 } 2354 2065 2355 2066 // BinaryHeap 2356 2067 /** 2357 2068 Implements a $(WEB en.wikipedia.org/wiki/Binary_heap, binary heap) 2358 2069 container on top of a given random-access range type (usually $(D 2359 2070 T[])) or a random-access container type (usually $(D Array!T)). The 2360 2071 documentation of $(D BinaryHeap) will refer to the underlying range or 2361 2072 container as the $(I store) of the heap. … … 2400 2111 //private: 2401 2112 2402 2113 // The payload includes the support store and the effective length 2403 2114 private RefCounted!(Tuple!(Store, "_store", size_t, "_length"), 2404 2115 RefCountedAutoInitialize.no) _payload; 2405 2116 // Comparison predicate 2406 2117 private alias binaryFun!(less) comp; 2407 2118 // Convenience accessors 2408 2119 private @property ref Store _store() 2409 2120 { 2410 assert(_payload. refCountedIsInitialized);2121 assert(_payload.RefCounted.isInitialized); 2411 2122 return _payload._store; 2412 2123 } 2413 2124 private @property ref size_t _length() 2414 2125 { 2415 assert(_payload. refCountedIsInitialized);2126 assert(_payload.RefCounted.isInitialized); 2416 2127 return _payload._length; 2417 2128 } 2418 2129 2419 2130 // Asserts that the heap property is respected. 2420 2131 private void assertValid() 2421 2132 { 2422 2133 debug 2423 2134 { 2424 if (!_payload. refCountedIsInitialized) return;2135 if (!_payload.RefCounted.isInitialized) return; 2425 2136 if (_length < 2) return; 2426 2137 for (size_t n = _length - 1; n >= 1; --n) 2427 2138 { 2428 2139 auto parentIdx = (n - 1) / 2; 2429 2140 assert(!comp(_store[parentIdx], _store[n]), text(n)); 2430 2141 } 2431 2142 } 2432 2143 } 2433 2144 2434 2145 // Assuming the element at index i perturbs the heap property in … … 2484 2195 { 2485 2196 auto t1 = _store[].moveAt(i); 2486 2197 auto t2 = _store[].moveAt(j); 2487 2198 _store[i] = move(t2); 2488 2199 _store[j] = move(t1); 2489 2200 } 2490 2201 } 2491 2202 2492 2203 public: 2493 2204 2494 /**2495 Converts the store $(D s) into a heap. If $(D initialSize) is2496 specified, only the first $(D initialSize) elements in $(D s) are 2497 transformed into a heap, after which the heap can grow up to $(D 2498 r.length) (if $(D Store) is a range) or indefinitely (if $(D Store) is 2499 a container with $(D insertBack)). Performs $(BIGOH min(r.length, 2500 initialSize)) evaluations of $(D less).2501 */2205 /** 2206 Converts the store $(D s) into a heap. If $(D initialSize) is 2207 specified, only the first $(D initialSize) elements in $(D s) 2208 are transformed into a heap, after which the heap can grow up 2209 to $(D r.length) (if $(D Store) is a range) or indefinitely (if 2210 $(D Store) is a container with $(D insertBack)). Performs 2211 $(BIGOH min(r.length, initialSize)) evaluations of $(D less). 2212 */ 2502 2213 this(Store s, size_t initialSize = size_t.max) 2503 2214 { 2504 2215 acquire(s, initialSize); 2505 2216 } 2506 2217 2507 2218 /** 2508 2219 Takes ownership of a store. After this, manipulating $(D s) may make 2509 2220 the heap work incorrectly. 2510 2221 */ 2511 2222 void acquire(Store s, size_t initialSize = size_t.max) 2512 2223 { 2513 _payload. refCountedEnsureInitialized();2224 _payload.RefCounted.ensureInitialized(); 2514 2225 _store() = move(s); 2515 2226 _length() = min(_store.length, initialSize); 2516 2227 if (_length < 2) return; 2517 2228 for (auto i = (_length - 2) / 2; ; ) 2518 2229 { 2519 2230 this.percolateDown(_store, i, _length); 2520 2231 if (i-- == 0) break; 2521 2232 } 2522 2233 assertValid; 2523 2234 } 2524 2235 2525 2236 /** 2526 2237 Takes ownership of a store assuming it already was organized as a 2527 2238 heap. 2528 2239 */ 2529 2240 void assume(Store s, size_t initialSize = size_t.max) 2530 2241 { 2531 _payload. refCountedEnsureInitialized();2242 _payload.RefCounted.ensureInitialized(); 2532 2243 _store() = s; 2533 2244 _length() = min(_store.length, initialSize); 2534 2245 assertValid; 2535 2246 } 2536 2247 2537 2248 /** 2538 2249 Clears the heap. Returns the portion of the store from $(D 0) up to 2539 2250 $(D length), which satisfies the $(LUCKY heap property). 2540 2251 */ 2541 2252 auto release() 2542 2253 { 2543 if (!_payload. refCountedIsInitialized)2254 if (!_payload.RefCounted.isInitialized) 2544 2255 { 2545 2256 return typeof(_store[0 .. _length]).init; 2546 2257 } 2547 2258 assertValid(); 2548 2259 auto result = _store[0 .. _length]; 2549 2260 _payload = _payload.init; 2550 2261 return result; 2551 2262 } 2552 2263 2553 2264 /** … … 2558 2269 return !length; 2559 2270 } 2560 2271 2561 2272 /** 2562 2273 Returns a duplicate of the heap. The underlying store must also 2563 2274 support a $(D dup) method. 2564 2275 */ 2565 2276 @property BinaryHeap dup() 2566 2277 { 2567 2278 BinaryHeap result; 2568 if (!_payload. refCountedIsInitialized) return result;2279 if (!_payload.RefCounted.isInitialized) return result; 2569 2280 result.assume(_store.dup, length); 2570 2281 return result; 2571 2282 } 2572 2283 2573 2284 /** 2574 2285 Returns the _length of the heap. 2575 2286 */ 2576 2287 @property size_t length() 2577 2288 { 2578 return _payload. refCountedIsInitialized ? _length : 0;2289 return _payload.RefCounted.isInitialized ? _length : 0; 2579 2290 } 2580 2291 2581 2292 /** 2582 2293 Returns the _capacity of the heap, which is the length of the 2583 2294 underlying store (if the store is a range) or the _capacity of the 2584 2295 underlying store (if the store is a container). 2585 2296 */ 2586 2297 @property size_t capacity() 2587 2298 { 2588 if (!_payload. refCountedIsInitialized) return 0;2299 if (!_payload.RefCounted.isInitialized) return 0; 2589 2300 static if (is(typeof(_store.capacity) : size_t)) 2590 2301 { 2591 2302 return _store.capacity; 2592 2303 } 2593 2304 else 2594 2305 { 2595 2306 return _store.length; 2596 2307 } 2597 2308 } 2598 2309 … … 2615 2326 } 2616 2327 2617 2328 /** 2618 2329 Inserts $(D value) into the store. If the underlying store is a range 2619 2330 and $(D length == capacity), throws an exception. 2620 2331 */ 2621 2332 size_t insert(ElementType!Store value) 2622 2333 { 2623 2334 static if (is(_store.insertBack(value))) 2624 2335 { 2625 _payload. refCountedEnsureInitialized();2336 _payload.RefCounted.ensureInitialized(); 2626 2337 if (length == _store.length) 2627 2338 { 2628 2339 // reallocate 2629 2340 _store.insertBack(value); 2630 2341 } 2631 2342 else 2632 2343 { 2633 2344 // no reallocation 2634 2345 _store[_length] = value; 2635 2346 } … … 2700 2411 /** 2701 2412 If the heap has room to grow, inserts $(D value) into the store and 2702 2413 returns $(D true). Otherwise, if $(D less(value, front)), calls $(D 2703 2414 replaceFront(value)) and returns again $(D true). Otherwise, leaves 2704 2415 the heap unaffected and returns $(D false). This method is useful in 2705 2416 scenarios where the smallest $(D k) elements of a set of candidates 2706 2417 must be collected. 2707 2418 */ 2708 2419 bool conditionalInsert(ElementType!Store value) 2709 2420 { 2710 _payload. refCountedEnsureInitialized();2421 _payload.RefCounted.ensureInitialized(); 2711 2422 if (_length < _store.length) 2712 2423 { 2713 2424 insert(value); 2714 2425 return true; 2715 2426 } 2716 2427 // must replace the top 2717 2428 assert(!_store.empty); 2718 2429 if (!comp(value, _store.front)) return false; // value >= largest 2719 2430 _store.front = value; 2720 2431 percolateDown(_store, 0, _length); … … 2753 2464 int[] b = new int[a.length]; 2754 2465 BinaryHeap!(int[]) h = BinaryHeap!(int[])(b, 0); 2755 2466 foreach (e; a) 2756 2467 { 2757 2468 h.insert(e); 2758 2469 } 2759 2470 assert(b == [ 16, 14, 10, 8, 7, 3, 9, 1, 4, 2 ], text(b)); 2760 2471 } 2761 2472 } 2762 2473 2474 //////////////////////////////////////////////////////////////////////////////// 2475 // Array!bool 2476 //////////////////////////////////////////////////////////////////////////////// 2477 2478 /** 2479 _Array specialized for $(D bool). Packs together values efficiently by 2480 allocating one bit per element. 2481 */ 2482 struct Array(T) if (is(T == bool)) 2483 { 2484 static immutable uint bitsPerWord = size_t.sizeof * 8; 2485 private alias Tuple!(Array!(size_t).Payload, "_backend", ulong, "_length") 2486 Data; 2487 private RefCounted!(Data, RefCountedAutoInitialize.no) _store; 2488 2489 private ref size_t[] data() 2490 { 2491 assert(_store.RefCounted.isInitialized); 2492 return _store._backend._payload; 2493 } 2494 2495 private ref size_t dataCapacity() 2496 { 2497 return _store._backend._capacity; 2498 } 2499 2500 /** 2501 Defines the container's primary range. 2502 */ 2503 struct Range 2504 { 2505 private Array!bool _outer; 2506 private ulong _a, _b; 2507 /// Range primitives 2508 @property Range save() 2509 { 2510 version (bug4437) 2511 { 2512 return this; 2513 } 2514 else 2515 { 2516 auto copy = this; 2517 return copy; 2518 } 2519 } 2520 /// Ditto 2521 @property bool empty() 2522 { 2523 return _a >= _b || _outer.length < _b; 2524 } 2525 /// Ditto 2526 @property T front() 2527 { 2528 enforce(!empty); 2529 return _outer[_a]; 2530 } 2531 /// Ditto 2532 @property void front(bool value) 2533 { 2534 enforce(!empty); 2535 _outer[_a] = value; 2536 } 2537 /// Ditto 2538 T moveFront() 2539 { 2540 enforce(!empty); 2541 return _outer.moveAt(_a); 2542 } 2543 /// Ditto 2544 void popFront() 2545 { 2546 enforce(!empty); 2547 ++_a; 2548 } 2549 /// Ditto 2550 @property T back() 2551 { 2552 enforce(!empty); 2553 return _outer[_b - 1]; 2554 } 2555 /// Ditto 2556 T moveBack() 2557 { 2558 enforce(!empty); 2559 return _outer.moveAt(_b - 1); 2560 } 2561 /// Ditto 2562 void popBack() 2563 { 2564 enforce(!empty); 2565 --_b; 2566 } 2567 /// Ditto 2568 T opIndex(size_t i) 2569 { 2570 return _outer[_a + i]; 2571 } 2572 /// Ditto 2573 void opIndexAssign(T value, uint i) 2574 { 2575 _outer[_a + i] = value; 2576 } 2577 /// Ditto 2578 T moveAt(size_t i) 2579 { 2580 return _outer.moveAt(_a + i); 2581 } 2582 /// Ditto 2583 @property ulong length() const 2584 { 2585 assert(_a <= _b); 2586 return _b - _a; 2587 } 2588 } 2589 2590 /** 2591 Property returning $(D true) if and only if the container has 2592 no elements. 2593 2594 Complexity: $(BIGOH 1) 2595 */ 2596 @property bool empty() 2597 { 2598 return !length; 2599 } 2600 2601 unittest 2602 { 2603 Array!bool a; 2604 //a._store._refCountedDebug = true; 2605 assert(a.empty); 2606 a.insertBack(false); 2607 assert(!a.empty); 2608 } 2609 2610 /** 2611 Returns a duplicate of the container. The elements themselves 2612 are not transitively duplicated. 2613 2614 Complexity: $(BIGOH n). 2615 */ 2616 @property Array!bool dup() 2617 { 2618 Array!bool result; 2619 result.insertBack(this[]); 2620 return result; 2621 } 2622 2623 unittest 2624 { 2625 Array!bool a; 2626 assert(a.empty); 2627 auto b = a.dup; 2628 assert(b.empty); 2629 a.insertBack(true); 2630 assert(b.empty); 2631 } 2632 2633 /** 2634 Returns the number of elements in the container. 2635 2636 Complexity: $(BIGOH log(n)). 2637 */ 2638 @property ulong length() 2639 { 2640 return _store.RefCounted.isInitialized ? _store._length : 0; 2641 } 2642 2643 unittest 2644 { 2645 Array!bool a; 2646 assert(a.length == 0); 2647 a.insert(true); 2648 assert(a.length == 1, text(a.length)); 2649 } 2650 2651 /** 2652 Returns the maximum number of elements the container can store 2653 without (a) allocating memory, (b) invalidating iterators upon 2654 insertion. 2655 2656 Complexity: $(BIGOH log(n)). 2657 */ 2658 @property ulong capacity() 2659 { 2660 return _store.RefCounted.isInitialized 2661 ? cast(ulong) bitsPerWord * _store._backend.capacity 2662 : 0; 2663 } 2664 2665 unittest 2666 { 2667 Array!bool a; 2668 assert(a.capacity == 0); 2669 foreach (i; 0 .. 100) 2670 { 2671 a.insert(true); 2672 assert(a.capacity >= a.length, text(a.capacity)); 2673 } 2674 } 2675 2676 /** 2677 Ensures sufficient capacity to accommodate $(D n) elements. 2678 2679 Postcondition: $(D capacity >= n) 2680 2681 Complexity: $(BIGOH log(e - capacity)) if $(D e > capacity), 2682 otherwise $(BIGOH 1). 2683 */ 2684 void reserve(ulong e) 2685 { 2686 _store.RefCounted.ensureInitialized(); 2687 _store._backend.reserve(to!size_t((e + bitsPerWord - 1) / bitsPerWord)); 2688 } 2689 2690 unittest 2691 { 2692 Array!bool a; 2693 assert(a.capacity == 0); 2694 a.reserve(15657); 2695 assert(a.capacity >= 15657); 2696 } 2697 2698 /** 2699 Returns a range that iterates over all elements of the 2700 container, in a container-defined order. The container should 2701 choose the most convenient and fast method of iteration for $(D 2702 opSlice()). 2703 2704 Complexity: $(BIGOH log(n)) 2705 */ 2706 Range opSlice() 2707 { 2708 return Range(this, 0, length); 2709 } 2710 2711 unittest 2712 { 2713 Array!bool a; 2714 a.insertBack([true, false, true, true]); 2715 assert(a[].length == 4); 2716 } 2717 2718 /** 2719 Returns a range that iterates the container between two 2720 specified positions. 2721 2722 Complexity: $(BIGOH log(n)) 2723 */ 2724 Range opSlice(ulong a, ulong b) 2725 { 2726 enforce(a <= b && b <= length); 2727 return Range(this, a, b); 2728 } 2729 2730 unittest 2731 { 2732 Array!bool a; 2733 a.insertBack([true, false, true, true]); 2734 assert(a[0 .. 2].length == 2); 2735 } 2736 2737 /** 2738 Equivalent to $(D opSlice().front) and $(D opSlice().back), 2739 respectively. 2740 2741 Complexity: $(BIGOH log(n)) 2742 */ 2743 @property bool front() 2744 { 2745 enforce(!empty); 2746 return data.ptr[0] & 1; 2747 } 2748 2749 /// Ditto 2750 @property void front(bool value) 2751 { 2752 enforce(!empty); 2753 if (value) data.ptr[0] |= 1; 2754 else data.ptr[0] &= ~cast(size_t) 1; 2755 } 2756 2757 unittest 2758 { 2759 Array!bool a; 2760 a.insertBack([true, false, true, true]); 2761 assert(a.front); 2762 a.front = false; 2763 assert(!a.front); 2764 } 2765 2766 /// Ditto 2767 @property bool back() 2768 { 2769 enforce(!empty); 2770 return data.back & (1u << ((_store._length - 1) % bitsPerWord)); 2771 } 2772 2773 /// Ditto 2774 @property void back(bool value) 2775 { 2776 enforce(!empty); 2777 if (value) 2778 { 2779 data.back |= (1u << ((_store._length - 1) % bitsPerWord)); 2780 } 2781 else 2782 { 2783 data.back &= 2784 ~(cast(size_t)1 << ((_store._length - 1) % bitsPerWord)); 2785 } 2786 } 2787 2788 unittest 2789 { 2790 Array!bool a; 2791 a.insertBack([true, false, true, true]); 2792 assert(a.back); 2793 a.back = false; 2794 assert(!a.back); 2795 } 2796 2797 /** 2798 Indexing operators yield or modify the value at a specified index. 2799 */ 2800 bool opIndex(ulong i) 2801 { 2802 auto div = cast(size_t) (i / bitsPerWord); 2803 auto rem = i % bitsPerWord; 2804 enforce(div < data.length); 2805 return data.ptr[div] & (1u << rem); 2806 } 2807 /// ditto 2808 void opIndexAssign(bool value, ulong i) 2809 { 2810 auto div = cast(size_t) (i / bitsPerWord); 2811 auto rem = i % bitsPerWord; 2812 enforce(div < data.length); 2813 if (value) data.ptr[div] |= (1u << rem); 2814 else data.ptr[div] &= ~(cast(size_t)1 << rem); 2815 } 2816 /// ditto 2817 void opIndexOpAssign(string op)(bool value, ulong i) 2818 { 2819 auto div = cast(size_t) (i / bitsPerWord); 2820 auto rem = i % bitsPerWord; 2821 enforce(div < data.length); 2822 auto oldValue = cast(bool) (data.ptr[div] & (1u << rem)); 2823 // Do the deed 2824 auto newValue = mixin("oldValue "~op~" value"); 2825 // Write back the value 2826 if (newValue != oldValue) 2827 { 2828 if (newValue) data.ptr[div] |= (1u << rem); 2829 else data.ptr[div] &= ~(cast(size_t)1 << rem); 2830 } 2831 } 2832 /// Ditto 2833 T moveAt(ulong i) 2834 { 2835 return this[i]; 2836 } 2837 2838 unittest 2839 { 2840 Array!bool a; 2841 a.insertBack([true, false, true, true]); 2842 assert(a[0] && !a[1]); 2843 a[0] &= a[1]; 2844 assert(!a[0]); 2845 } 2846 2847 /** 2848 Returns a new container that's the concatenation of $(D this) 2849 and its argument. 2850 2851 Complexity: $(BIGOH n + m), where m is the number of elements 2852 in $(D stuff) 2853 */ 2854 Array!bool opBinary(string op, Stuff)(Stuff rhs) if (op == "~") 2855 { 2856 auto result = this; 2857 return result ~= rhs; 2858 } 2859 2860 unittest 2861 { 2862 Array!bool a; 2863 a.insertBack([true, false, true, true]); 2864 Array!bool b; 2865 b.insertBack([true, true, false, true]); 2866 assert(equal((a ~ b)[], 2867 [true, false, true, true, true, true, false, true])); 2868 } 2869 2870 // /// ditto 2871 // TotalContainer opBinaryRight(Stuff, string op)(Stuff lhs) if (op == "~") 2872 // { 2873 // assert(0); 2874 // } 2875 2876 /** 2877 Forwards to $(D insertAfter(this[], stuff)). 2878 */ 2879 // @@@BUG@@@ 2880 //ref Array!bool opOpAssign(string op, Stuff)(Stuff stuff) if (op == "~") 2881 Array!bool opOpAssign(string op, Stuff)(Stuff stuff) if (op == "~") 2882 { 2883 static if (is(typeof(stuff[]))) insertBack(stuff[]); 2884 else insertBack(stuff); 2885 return this; 2886 } 2887 2888 unittest 2889 { 2890 Array!bool a; 2891 a.insertBack([true, false, true, true]); 2892 Array!bool b; 2893 a.insertBack([false, true, false, true, true]); 2894 a ~= b; 2895 assert(equal( 2896 a[], 2897 [true, false, true, true, false, true, false, true, true])); 2898 } 2899 2900 /** 2901 Removes all contents from the container. The container decides 2902 how $(D capacity) is affected. 2903 2904 Postcondition: $(D empty) 2905 2906 Complexity: $(BIGOH n) 2907 */ 2908 void clear() 2909 { 2910 this = Array!bool(); 2911 } 2912 2913 unittest 2914 { 2915 Array!bool a; 2916 a.insertBack([true, false, true, true]); 2917 a.clear(); 2918 assert(a.capacity == 0); 2919 } 2920 2921 /** 2922 Sets the number of elements in the container to $(D 2923 newSize). If $(D newSize) is greater than $(D length), the 2924 added elements are added to the container and initialized with 2925 $(D ElementType.init). 2926 2927 Complexity: $(BIGOH abs(n - newLength)) 2928 2929 Postcondition: $(D _length == newLength) 2930 */ 2931 @property void length(ulong newLength) 2932 { 2933 _store.RefCounted.ensureInitialized(); 2934 auto newDataLength = 2935 to!size_t((newLength + bitsPerWord - 1) / bitsPerWord); 2936 _store._backend.length = newDataLength; 2937 _store._length = newLength; 2938 } 2939 2940 unittest 2941 { 2942 Array!bool a; 2943 a.length = 1057; 2944 assert(a.length == 1057); 2945 foreach (e; a) 2946 { 2947 assert(!e); 2948 } 2949 } 2950 2951 /** 2952 Inserts $(D stuff) in the container. $(D stuff) can be a value 2953 convertible to $(D ElementType) or a range of objects 2954 convertible to $(D ElementType). 2955 2956 The $(D stable) version guarantees that ranges iterating over 2957 the container are never invalidated. Client code that counts on 2958 non-invalidating insertion should use $(D stableInsert). 2959 2960 Returns: The number of elements added. 2961 2962 Complexity: $(BIGOH m * log(n)), where $(D m) is the number of 2963 elements in $(D stuff) 2964 */ 2965 alias insertBack insert; 2966 ///ditto 2967 alias insertBack stableInsert; 2968 2969 /** 2970 Same as $(D insert(stuff)) and $(D stableInsert(stuff)) 2971 respectively, but relax the complexity constraint to linear. 2972 */ 2973 alias insertBack linearInsert; 2974 ///ditto 2975 alias insertBack stableLinearInsert; 2976 2977 /** 2978 Picks one value in the container, removes it from the 2979 container, and returns it. The stable version behaves the same, 2980 but guarantees that ranges iterating over the container are 2981 never invalidated. 2982 2983 Precondition: $(D !empty) 2984 2985 Returns: The element removed. 2986 2987 Complexity: $(BIGOH log(n)) 2988 */ 2989 T removeAny() 2990 { 2991 auto result = back(); 2992 removeBack(); 2993 return result; 2994 } 2995 /// ditto 2996 alias removeAny stableRemoveAny; 2997 2998 unittest 2999 { 3000 Array!bool a; 3001 a.length = 1057; 3002 assert(!a.removeAny()); 3003 assert(a.length == 1056); 3004 foreach (e; a) 3005 { 3006 assert(!e); 3007 } 3008 } 3009 3010 /** 3011 Inserts $(D value) to the back of the container. $(D stuff) can 3012 be a value convertible to $(D ElementType) or a range of 3013 objects convertible to $(D ElementType). The stable version 3014 behaves the same, but guarantees that ranges iterating over the 3015 container are never invalidated. 3016 3017 Returns: The number of elements inserted 3018 3019 Complexity: $(BIGOH log(n)) 3020 */ 3021 ulong insertBack(Stuff)(Stuff stuff) if (is(Stuff : bool)) 3022 { 3023 _store.RefCounted.ensureInitialized(); 3024 auto rem = _store._length % bitsPerWord; 3025 if (rem) 3026 { 3027 // Fits within the current array 3028 if (stuff) 3029 { 3030 data[$ - 1] |= (1u << rem); 3031 } 3032 else 3033 { 3034 data[$ - 1] &= ~(1u << rem); 3035 } 3036 } 3037 else 3038 { 3039 // Need to add more data 3040 _store._backend.insertBack(stuff); 3041 } 3042 ++_store._length; 3043 return 1; 3044 } 3045 /// Ditto 3046 ulong insertBack(Stuff)(Stuff stuff) 3047 if (isInputRange!Stuff && is(ElementType!Stuff : bool)) 3048 { 3049 static if (!hasLength!Stuff) ulong result; 3050 for (; !stuff.empty; stuff.popFront()) 3051 { 3052 insertBack(stuff.front); 3053 static if (!hasLength!Stuff) ++result; 3054 } 3055 static if (!hasLength!Stuff) return result; 3056 else return stuff.length; 3057 } 3058 /// ditto 3059 alias insertBack stableInsertBack; 3060 3061 /** 3062 Removes the value at the front or back of the container. The 3063 stable version behaves the same, but guarantees that ranges 3064 iterating over the container are never invalidated. The 3065 optional parameter $(D howMany) instructs removal of that many 3066 elements. If $(D howMany > n), all elements are removed and no 3067 exception is thrown. 3068 3069 Precondition: $(D !empty) 3070 3071 Complexity: $(BIGOH log(n)). 3072 */ 3073 void removeBack() 3074 { 3075 enforce(_store._length); 3076 if (_store._length % bitsPerWord) 3077 { 3078 // Cool, just decrease the length 3079 --_store._length; 3080 } 3081 else 3082 { 3083 // Reduce the allocated space 3084 --_store._length; 3085 _store._backend.length = _store._backend.length - 1; 3086 } 3087 } 3088 /// ditto 3089 alias removeBack stableRemoveBack; 3090 3091 /** 3092 Removes $(D howMany) values at the front or back of the 3093 container. Unlike the unparameterized versions above, these 3094 functions do not throw if they could not remove $(D howMany) 3095 elements. Instead, if $(D howMany > n), all elements are 3096 removed. The returned value is the effective number of elements 3097 removed. The stable version behaves the same, but guarantees 3098 that ranges iterating over the container are never invalidated. 3099 3100 Returns: The number of elements removed 3101 3102 Complexity: $(BIGOH howMany * log(n)). 3103 */ 3104 /// ditto 3105 ulong removeBack(ulong howMany) 3106 { 3107 if (howMany >= length) 3108 { 3109 howMany = length; 3110 clear(); 3111 } 3112 else 3113 { 3114 length = length - howMany; 3115 } 3116 return howMany; 3117 } 3118 3119 unittest 3120 { 3121 Array!bool a; 3122 a.length = 1057; 3123 assert(a.removeBack(1000) == 1000); 3124 assert(a.length == 57); 3125 foreach (e; a) 3126 { 3127 assert(!e); 3128 } 3129 } 3130 3131 /** 3132 Inserts $(D stuff) before, after, or instead range $(D r), 3133 which must be a valid range previously extracted from this 3134 container. $(D stuff) can be a value convertible to $(D 3135 ElementType) or a range of objects convertible to $(D 3136 ElementType). The stable version behaves the same, but 3137 guarantees that ranges iterating over the container are never 3138 invalidated. 3139 3140 Returns: The number of values inserted. 3141 3142 Complexity: $(BIGOH n + m), where $(D m) is the length of $(D stuff) 3143 */ 3144 ulong insertBefore(Stuff)(Range r, Stuff stuff) 3145 { 3146 // TODO: make this faster, it moves one bit at a time 3147 immutable inserted = stableInsertBack(stuff); 3148 immutable tailLength = length - inserted; 3149 bringToFront( 3150 this[r._a .. tailLength], 3151 this[tailLength .. length]); 3152 return inserted; 3153 } 3154 /// ditto 3155 alias insertBefore stableInsertBefore; 3156 3157 unittest 3158 { 3159 Array!bool a; 3160 version (bugxxxx) 3161 { 3162 a._store.refCountedDebug = true; 3163 } 3164 a.insertBefore(a[], true); 3165 assert(a.length == 1, text(a.length)); 3166 a.insertBefore(a[], false); 3167 assert(a.length == 2, text(a.length)); 3168 } 3169 3170 /// ditto 3171 ulong insertAfter(Stuff)(Range r, Stuff stuff) 3172 { 3173 // TODO: make this faster, it moves one bit at a time 3174 immutable inserted = stableInsertBack(stuff); 3175 immutable tailLength = length - inserted; 3176 bringToFront( 3177 this[r._b .. tailLength], 3178 this[tailLength .. length]); 3179 return inserted; 3180 } 3181 /// ditto 3182 alias insertAfter stableInsertAfter; 3183 3184 unittest 3185 { 3186 Array!bool a; 3187 a.length = 10; 3188 a.insertAfter(a[0 .. 5], true); 3189 assert(a.length == 11, text(a.length)); 3190 assert(a[5]); 3191 } 3192 /// ditto 3193 size_t replace(Stuff)(Range r, Stuff stuff) if (is(Stuff : bool)) 3194 { 3195 if (!r.empty) 3196 { 3197 // There is room 3198 r.front = stuff; 3199 r.popFront(); 3200 linearRemove(r); 3201 } 3202 else 3203 { 3204 // No room, must insert 3205 insertBefore(r, stuff); 3206 } 3207 return 1; 3208 } 3209 /// ditto 3210 alias replace stableReplace; 3211 3212 unittest 3213 { 3214 Array!bool a; 3215 a.length = 10; 3216 a.replace(a[3 .. 5], true); 3217 assert(a.length == 9, text(a.length)); 3218 assert(a[3]); 3219 } 3220 3221 /** 3222 Removes all elements belonging to $(D r), which must be a range 3223 obtained originally from this container. The stable version 3224 behaves the same, but guarantees that ranges iterating over the 3225 container are never invalidated. 3226 3227 Returns: A range spanning the remaining elements in the container that 3228 initially were right after $(D r). 3229 3230 Complexity: $(BIGOH n) 3231 */ 3232 Range linearRemove(Range r) 3233 { 3234 copy(this[r._b .. length], this[r._a .. length]); 3235 length = length - r.length; 3236 return this[r._a .. length]; 3237 } 3238 /// ditto 3239 alias linearRemove stableLinearRemove; 3240 } 3241 3242 unittest 3243 { 3244 Array!bool a; 3245 assert(a.empty); 3246 }
