sain.collections.vec
A contiguous growable alternative to builtin list with extra functionalities.
Example
names = Vec[str]()
names.push('foo')
names.push('bar')
print(names) # ['foo', 'bar']
assert names.len() == 2
1# BSD 3-Clause License 2# 3# Copyright (c) 2022-Present, nxtlo 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 9# * Redistributions of source code must retain the above copyright notice, this 10# list of conditions and the following disclaimer. 11# 12# * Redistributions in binary form must reproduce the above copyright notice, 13# this list of conditions and the following disclaimer in the documentation 14# and/or other materials provided with the distribution. 15# 16# * Neither the name of the copyright holder nor the names of its 17# contributors may be used to endorse or promote products derived from 18# this software without specific prior written permission. 19# 20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30"""A contiguous growable alternative to builtin `list` with extra functionalities. 31 32Example 33------- 34```py 35names = Vec[str]() 36 37names.push('foo') 38names.push('bar') 39 40print(names) # ['foo', 'bar'] 41assert names.len() == 2 42``` 43""" 44 45from __future__ import annotations 46 47__all__ = ("Vec",) 48 49import sys as _sys 50import typing 51from collections import abc as collections 52 53from sain import iter as _iter 54from sain import option as _option 55from sain import result as _result 56from sain.collections.slice import Slice 57from sain.collections.slice import SliceMut 58from sain.collections.slice import SpecContains 59from sain.macros import rustc_diagnostic_item 60 61if typing.TYPE_CHECKING: 62 from _typeshed import SupportsRichComparison 63 64 from sain import Result 65 66T = typing.TypeVar("T") 67 68 69@rustc_diagnostic_item("Vec") 70@typing.final 71class Vec(typing.Generic[T], collections.MutableSequence[T], SpecContains[T]): 72 """A contiguous growable alternative to builtin `list` with extra functionalities. 73 74 The layout of `Vec<T>` is exactly the same as `list<T>`. 75 Which means `list<T>`'s methods are inherited into `Vec<T>`. 76 77 Example 78 ------- 79 ```py 80 names = Vec() 81 names.push('foo') 82 names.push('bar') 83 84 print(names) # ['foo', 'bar'] 85 assert names.len() == 2 86 ``` 87 88 Constructing 89 ------------ 90 * `Vec()`: Create an empty vec, this will not allocate the initial buffer. 91 * `Vec(other_list)`: Create a vec which points to `other_list` 92 * `Vec([1, 2, 3])`: Create a vec with `[1, 2, 3]` pre-allocated. 93 * `Vec(iterable)`: Create a vec from an `iterable`, This is `O(n)` where `n` is the number of elements, 94 since it copies `iterable`'s elements into a new list. 95 * `Vec.with_capacity(5)`: Create a vec that can hold up to 5 elements 96 97 Iterating over `Vec` 98 ------------------- 99 There're two ways to iterate over a `Vec`. The first is to normally use `for` loop. 100 101 ```py 102 for i in names: 103 print(i) 104 105 # foo 106 # bar 107 ``` 108 109 The second is to use `Vec.iter`, which yields all items in this `Vec` from start to end. 110 Then the iterator gets exhausted as usual, See `sain.Iterator`. 111 112 ```py 113 iterator = names.iter() 114 for name in iterator.map(str.upper): 115 print(name) 116 117 # FOO 118 # BAR 119 120 # No more items, The actual vec is left unchanged. 121 assert iterator.next().is_none() 122 ``` 123 124 ## Comparison operators 125 A `Vec` may be compared with another `Vec` or a `list`, any other type will return `False` 126 127 ```py 128 vec = Vec([1, 2, 3]) 129 assert vec == [1, 2, 3] # True 130 assert vec != (1, 2, 3) 131 ``` 132 133 Zero-Copy 134 --------- 135 A vec that gets initialized from a `list` will *point* to it and doesn't copy it. 136 So any element that gets appended to the list will also get pushed into the vec 137 that's pointing to it and vice-versa. 138 139 ```py 140 cells: list[str] = [] 141 vec = Vec(cells) # This DOES NOT copy the `cells`. 142 143 cells.append("foo") 144 vec[0] == "foo" # True 145 ``` 146 147 The opposite of the above is to initialize the vec from either 148 an iterable or args, or copy the list. 149 150 ```py 151 from sain.collections import vec, Vec 152 153 # Copy the list into a vec. 154 vec = Vec(cells[:]) 155 cells.append("bar") 156 157 vec[1] # IndexError: "bar" doesn't exist in vec. 158 ``` 159 """ 160 161 __slots__ = ("_ptr", "_capacity") 162 163 @typing.overload 164 def __init__(self) -> None: ... 165 166 @typing.overload 167 def __init__(self, iterable: collections.Iterable[T]) -> None: ... 168 169 def __init__(self, iterable: collections.Iterable[T] | None = None) -> None: 170 """Create an empty `Vec<T>`. 171 172 The vector will not allocate until elements are pushed onto it. 173 174 Example 175 ------ 176 ```py 177 vec: Vec[float] = Vec() 178 ``` 179 """ 180 # We won't allocate to build the list here. 181 # Instead, On first push or fist indexed set 182 # we allocate if it was None. 183 if isinstance(iterable, list): 184 # Calling `list()` on another list will copy it, So instead we just point to it. 185 self._ptr = iterable 186 elif isinstance(iterable, Vec): 187 self._ptr = iterable._ptr 188 # any other iterable that ain't a list needs to get copied into a new list. 189 else: 190 self._ptr: list[T] | None = list(iterable) if iterable else None 191 192 self._capacity: int | None = None 193 194 @classmethod 195 def with_capacity(cls, capacity: int) -> Vec[T]: 196 """Create a new `Vec` with at least the specified capacity. 197 This vec will be able to hold `capacity` elements without pushing further. 198 199 Check out `Vec.push_within_capacity` as well. 200 201 Example 202 ------- 203 ```py 204 vec = Vec.with_capacity(3) 205 assert vec.len() == 0 and vec.capacity() >= 3 206 207 vec.push(1) 208 vec.push(2) 209 vec.push(3) 210 print(vec.len()) # 3 211 212 # This won't push. 213 vec.push(4) 214 ``` 215 """ 216 v = cls() 217 v._capacity = capacity 218 return v 219 220 def as_ref(self) -> Slice[T]: 221 """Return an immutable view over this vector elements. 222 223 No copying occurs. 224 225 Example 226 ------- 227 ```py 228 def send_bytes(v: Slice[int]) -> None: 229 # access `vec` in a read-only mode. 230 socket.write_all(v) 231 232 buf = Vec([1, 2, 3]) 233 send_bytes(buf.as_ref()) 234 ``` 235 """ 236 return Slice(self) 237 238 def as_mut(self) -> SliceMut[T]: 239 """Return a mutable view over this vector elements. 240 241 No copying occurs. 242 243 Example 244 ------- 245 ```py 246 def read_bytes(buf: SliceMut[int]) -> None: 247 socket.read_to_end(buf.as_mut()) 248 249 buf: Vec[int] = Vec() 250 read_bytes(buf.as_mut()) # or just `buf` 251 assert vec.len() >= 1 252 ``` 253 """ 254 return SliceMut(self) 255 256 def len(self) -> int: 257 """Return the number of elements in this vector. 258 259 Example 260 ------- 261 ```py 262 vec = Vec((1,2,3)) 263 264 assert vec.len() == 3 265 ``` 266 """ 267 return self.__len__() 268 269 def capacity(self) -> int: 270 """Return the capacity of this vector if set, 0 if not . 271 272 The number `0` here has two different Meanings: 273 - The first means the `Vec` doesn't have a specific capacity set. 274 - The second means the `Vec` literally initialized with `0` capacity. 275 276 Example 277 ------- 278 ```py 279 vec_with_cap = Vec.with_capacity(3) 280 assert vec_with_cap.capacity().unwrap() == 3 281 282 vec = Vec([1, 2, 3]) 283 assert vec.capacity() == 0 284 ``` 285 """ 286 return 0 if self._capacity is None else self._capacity 287 288 def iter(self) -> _iter.TrustedIter[T]: 289 """Returns an iterator over this vector elements. 290 291 Example 292 ------- 293 ```py 294 vec = Vec([1 ,2, 3]) 295 for element in vec.iter().map(str): 296 print(element) 297 ``` 298 """ 299 return _iter.TrustedIter(self._ptr or ()) 300 301 def is_empty(self) -> bool: 302 """Returns true if the vector contains no elements. 303 304 Inlined into: 305 ```py 306 not self.vec 307 ``` 308 """ 309 return not self._ptr 310 311 def leak(self) -> list[T]: 312 """Consumes and leaks the Vec, returning a mutable reference to the contents. 313 314 After calling this, this vec will no longer reference the underlying buffer, 315 therefore, it becomes unusable. 316 317 if `self` is uninitialized, an empty list is returned. 318 319 This function is only useful when you want to detach from a `Vec<T>` and get a `list[T]` without 320 any copies. 321 322 Example 323 ------- 324 ```py 325 x = Vec([1, 2, 3]) 326 owned = x.leak() 327 # x is now unusable. 328 owned[0] += 1 329 assert owned == [2, 2, 3] 330 ``` 331 """ 332 if self._ptr is not None: 333 # don't point to `_ptr` anymore. 334 tmp = self._ptr 335 del self._ptr 336 return tmp 337 338 return [] 339 340 def split_off(self, at: int) -> Vec[T]: 341 """Split the vector off at the specified position, returning a new 342 vec at the range of `[at : len]`, leaving `self` at `[at : vec_len]`. 343 344 if this vec is empty, `self` is returned unchanged. 345 346 Example 347 ------- 348 ```py 349 origin = Vec((1, 2, 3, 4)) 350 split = vec.split_off(2) 351 352 print(origin, split) # [1, 2], [3, 4] 353 ``` 354 355 Raises 356 ------ 357 `IndexError` 358 This method will raise if `at` > `len(self)` 359 """ 360 len_ = self.len() 361 if at > len_: 362 raise IndexError( 363 f"Index `at` ({at}) should be <= than len of vector ({len_}) " 364 ) from None 365 366 # Either the list is empty or uninit. 367 if not self._ptr: 368 return self 369 370 split = self[at:len_] # split the items into a new vec. 371 del self._ptr[at:len_] # remove the items from the original list. 372 return split 373 374 def split_first(self) -> _option.Option[tuple[T, collections.Sequence[T]]]: 375 """Split the first and rest elements of the vector, If empty, `None` is returned. 376 377 Example 378 ------- 379 ```py 380 vec = Vec([1, 2, 3]) 381 split = vec.split_first() 382 assert split == Some((1, [2, 3])) 383 384 vec: Vec[int] = Vec() 385 split = vec.split_first() 386 assert split.is_none() 387 ``` 388 """ 389 if not self._ptr: 390 return _option.NOTHING 391 392 # optimized to only one element in the vector. 393 if self.len() == 1: 394 return _option.Some((self[0], ())) 395 396 first, *rest = self._ptr 397 return _option.Some((first, rest)) 398 399 def split_last(self) -> _option.Option[tuple[T, collections.Sequence[T]]]: 400 """Split the last and rest elements of the vector, If empty, `None` is returned. 401 402 Example 403 ------- 404 ```py 405 vec = Vec([1, 2, 3]) 406 last, rest = vec.split_last().unwrap() 407 assert (last, rest) == [3, [1, 2]] 408 ``` 409 """ 410 if not self._ptr: 411 return _option.NOTHING 412 413 # optimized to only one element in the vector. 414 if self.len() == 1: 415 return _option.Some((self[0], ())) 416 417 last, *rest = self._ptr[-1], *self._ptr[:-1] 418 return _option.Some((last, rest)) 419 420 def split_at(self, mid: int) -> tuple[Vec[T], Vec[T]]: 421 """Divide `self` into two at an index. 422 423 The first will contain all elements from `[0:mid]` excluding `mid` it self. 424 and the second will contain the remaining elements. 425 426 if `mid` > `self.len()`, Then all elements will be moved to the left, 427 returning an empty vec in right. 428 429 Example 430 ------- 431 ```py 432 buffer = Vec((1, 2, 3, 4)) 433 left, right = buffer.split_at(0) 434 assert left == [] and right == [1, 2, 3, 4] 435 436 left, right = buffer.split_at(2) 437 assert left == [1, 2] and right == [2, 3] 438 ``` 439 440 The is roughly the implementation 441 ```py 442 vec[0:mid], vec[mid:] 443 ``` 444 """ 445 return self[0:mid], self[mid:] 446 447 def swap(self, a: int, b: int): 448 """Swap two elements in the vec. 449 450 if `a` equals to `b` then it's guaranteed that elements won't change value. 451 452 Example 453 ------- 454 ```py 455 buf = Vec([1, 2, 3, 4]) 456 buf.swap(0, 3) 457 assert buf == [4, 2, 3, 1] 458 ``` 459 460 Raises 461 ------ 462 IndexError 463 If the positions of `a` or `b` are out of index. 464 """ 465 if self[a] == self[b]: 466 return 467 468 self[a], self[b] = self[b], self[a] 469 470 def swap_unchecked(self, a: int, b: int): 471 """Swap two elements in the vec. without checking if `a` == `b`. 472 473 If you care about `a` and `b` equality, see `Vec.swap`. 474 475 Example 476 ------- 477 ```py 478 buf = Vec([1, 2, 3, 1]) 479 buf.swap_unchecked(0, 3) 480 assert buf == [1, 2, 3, 1] 481 ``` 482 483 Raises 484 ------ 485 IndexError 486 If the positions of `a` or `b` are out of index. 487 """ 488 self[a], self[b] = self[b], self[a] 489 490 def first(self) -> _option.Option[T]: 491 """Get the first element in this vec, returning `None` if there's none. 492 493 Example 494 ------- 495 ```py 496 vec = Vec((1,2,3)) 497 first = vec.first() 498 assert ~first == 1 499 ``` 500 """ 501 return self.get(0) 502 503 def last(self) -> _option.Option[T]: 504 """Get the last element in this vec, returning `None` if there's none. 505 506 Example 507 ------- 508 ```py 509 vec = Vec([1, 2, 3, 4]) 510 first = vec.last() 511 assert ~first == 4 512 ``` 513 """ 514 return self.get(-1) 515 516 def truncate(self, size: int) -> None: 517 """Shortens the vec, keeping the first `size` elements and dropping the rest. 518 519 Example 520 ------- 521 ```py 522 vec = Vec([1,2,3]) 523 vec.truncate(1) 524 assert vec == [1] 525 ``` 526 """ 527 if not self._ptr: 528 return 529 530 del self._ptr[size:] 531 532 def retain(self, f: collections.Callable[[T], bool]) -> None: 533 """Retains only the elements specified by the predicate. 534 535 This operation occurs in-place without copying the original list. 536 537 Example 538 ------- 539 ```py 540 vec = Vec([1, 2, 3]) 541 vec.retain(lambda elem: elem > 1) 542 543 assert vec == [2, 3] 544 ``` 545 546 The impl for this method is very simple 547 ```py 548 for idx, e in enumerate(vec): 549 if not f(e): 550 del vec[idx] 551 ``` 552 """ 553 if not self._ptr: 554 return 555 556 idx = 0 557 while idx < len(self._ptr): 558 if not f(self._ptr[idx]): 559 del self._ptr[idx] 560 else: 561 idx += 1 562 563 def swap_remove(self, item: T) -> T: 564 """Remove the first appearance of `item` from this vector and return it. 565 566 Raises 567 ------ 568 * `ValueError`: if `item` is not in this vector. 569 * `MemoryError`: if this vector hasn't allocated, Aka nothing has been pushed to it. 570 571 Example 572 ------- 573 ```py 574 vec = Vec(('a', 'b', 'c')) 575 element = vec.remove('a') 576 assert vec == ['b', 'c'] and element == 'a' 577 ``` 578 """ 579 if self._ptr is None: 580 raise MemoryError("Vec is unallocated.") from None 581 582 return self._ptr.pop(self.index(item)) 583 584 def fill(self, value: T) -> None: 585 """Fill `self` with the given `value`. 586 587 Nothing happens if the vec is empty or unallocated. 588 589 Example 590 ```py 591 a = Vec([0, 1, 2, 3]) 592 a.fill(0) 593 assert a == [0, 0, 0, 0] 594 ``` 595 """ 596 if not self._ptr: 597 return 598 599 for n, _ in enumerate(self): 600 self[n] = value 601 602 def push(self, item: T) -> None: 603 """Push an element at the end of the vector. 604 605 Example 606 ------- 607 ```py 608 vec = Vec() 609 vec.push(1) 610 611 assert vec == [1] 612 ``` 613 """ 614 if self._capacity is not None: 615 self.push_within_capacity(item) 616 return 617 618 if self._ptr is None: 619 self._ptr = [] 620 621 self._ptr.append(item) 622 623 def push_within_capacity(self, x: T) -> Result[None, T]: 624 """Appends an element if there is sufficient spare capacity, otherwise an error is returned with the element. 625 626 Example 627 ------- 628 ```py 629 vec: Vec[int] = Vec.with_capacity(3) 630 for i in range(3): 631 match vec.push_within_capacity(i): 632 case Ok(_): 633 print("All good.") 634 case Err(elem): 635 print("Reached max cap :< can't push", elem) 636 ``` 637 638 Or you can also just call `Vec.push` and it will push if there's is sufficient capacity. 639 ```py 640 vec: Vec[int] = Vec.with_capacity(3) 641 642 vec.extend((1, 2, 3)) 643 vec.push(4) 644 645 assert vec.len() == 3 646 ``` 647 """ 648 if self._ptr is None: 649 self._ptr = [] 650 651 if self.len() == self._capacity: 652 return _result.Err(x) 653 654 self._ptr.append(x) 655 return _result.Ok(None) 656 657 def reserve(self, additional: int) -> None: 658 """Reserves capacity for at least additional more elements to be inserted in the given Vec<T>. 659 660 Example 661 ------- 662 ```py 663 vec = Vec.with_capacity(3) 664 is_vip = random.choice((True, False)) 665 666 for i in range(4): 667 match vec.push_within_capacity(i): 668 case Ok(_): 669 print("All good") 670 case Err(person): 671 # If the person is a VIP, then reserve for one more. 672 if is_vip: 673 vec.reserve(1) 674 continue 675 676 # is_vip was false. 677 print("Can't reserve for non-VIP members...", person) 678 break 679 ``` 680 """ 681 if self._capacity is not None: 682 self._capacity += additional 683 684 def shrink_to_fit(self) -> None: 685 """Shrink the capacity of this `Vec` to match its length. 686 687 If `self` is initialized with no capacity, This is a `NOP`. 688 689 Example 690 ------- 691 ```py 692 s = Vec([1, 2, 3, 4]) 693 694 s.reserve(100) 695 s.shrink_to_fit() 696 assert s.capacity() == 4 697 ``` 698 """ 699 if self._capacity is None: 700 return 701 702 # The capacity is never less than the length. 703 self._capacity = min(self.__len__(), self._capacity) 704 705 def shrink_to(self, min_capacity: int) -> None: 706 """Shrink the capacity of this `Vec` to a minimum specified capacity. 707 708 If `self` is initialized with no capacity or the current capacity is less than the lower limit, 709 This is a `NOP`. 710 711 Example 712 ------- 713 ```py 714 vec = Vec.with_capacity(10) 715 vec.extend([1, 2, 3]) 716 assert vec.capacity() >= 10 717 vec.shrink_to(4) 718 assert vec.capacity() >= 4 719 vec.shrink_to(0) 720 ``` 721 """ 722 if self._capacity is None or self._capacity <= min_capacity: 723 return 724 725 # Ensure the capacity is not reduced below the current length of the vector. 726 self._capacity = max(self.__len__(), min_capacity) 727 728 ########################## 729 # * Builtin Operations * 730 ########################## 731 732 def append(self, value: T) -> None: 733 """An alias to `Vec.push`.""" 734 self.push(value) 735 736 def get(self, index: int) -> _option.Option[T]: 737 """Get the item at the given index, or `Some[None]` if its out of bounds. 738 739 Example 740 ------- 741 ```py 742 vec = Vec((1, 2, 3)) 743 vec.get(0) == Some(1) 744 vec.get(3) == Some(None) 745 ``` 746 """ 747 try: 748 return _option.Some(self[index]) 749 except IndexError: 750 return _option.NOTHING 751 752 def insert(self, index: int, value: T) -> None: 753 """Insert an element at the position `index`. 754 755 Example 756 -------- 757 ```py 758 vec = Vec((2, 3)) 759 vec.insert(0, 1) 760 assert vec == [1, 2, 3] 761 ``` 762 """ 763 self.__setitem__(index, value) 764 765 def pop(self, index: int = -1) -> _option.Option[T]: 766 """Removes the last element from a vector and returns it, or `None` if it is empty. 767 768 Example 769 ------- 770 ```py 771 vec = Vec((1, 2, 3)) 772 assert vec.pop() == Some(3) 773 assert vec == [1, 2] 774 ``` 775 """ 776 if not self._ptr: 777 return _option.NOTHING 778 779 return _option.Some(self._ptr.pop(index)) 780 781 def pop_if(self, pred: collections.Callable[[T], bool]) -> _option.Option[T]: 782 """Removes the last element from a vector and returns it if `f` returns `True`, 783 or `None` if it is empty. 784 785 Example 786 ------- 787 ```py 788 vec = Vec((1, 2, 3)) 789 assert vec.pop_if(lambda num: num * 2 == 6) == Some(3) 790 assert vec == [1, 2] 791 ``` 792 """ 793 if not self._ptr: 794 return _option.NOTHING 795 796 if pred(self[-1]): 797 return self.pop() 798 799 return _option.NOTHING 800 801 def dedup(self) -> None: 802 """Removes consecutive repeated elements in the vector according to their `__eq__` 803 implementation. 804 805 Example 806 ------- 807 ```py 808 vec = Vec([1, 2, 2, 3, 2]) 809 vec.dedup() 810 assert vec == [1, 2, 3, 2] 811 """ 812 self.dedup_by(lambda a, b: a == b) 813 814 def dedup_by(self, same_bucket: collections.Callable[[T, T], bool]) -> None: 815 """Removes all but the first of consecutive elements in the vector satisfying a given equality. 816 817 Example 818 ------- 819 ```py 820 vec = Vec(["foo", "bar", "Bar", "baz", "bar"]) 821 vec.dedup_by(lambda a, b: a.lower() == b.lower()) 822 assert vec == ["foo", "bar", "baz", "bar"] 823 ``` 824 825 Only remove consecutive duplicates. 826 ```py 827 vec = Vec([1, 2, 2, 3, 4, 1]) 828 vec.dedup_by(lambda a, b: a == b) 829 # The final 1 is not adjacent to the first 1, so it is not removed. 830 assert vec == [1, 2, 3, 4, 1] 831 ``` 832 """ 833 834 if not self._ptr or (len_ := len(self._ptr)) <= 1: 835 return 836 837 idx = 1 838 while idx < len_: 839 if same_bucket(self._ptr[idx], self._ptr[idx - 1]): 840 del self._ptr[idx] 841 len_ -= 1 842 else: 843 idx += 1 844 845 def remove(self, item: T) -> None: 846 """Remove the first appearance of `item` from this vector. 847 848 Example 849 ------- 850 ```py 851 vec = Vec(('a', 'b', 'c')) 852 vec.remove('a') 853 assert vec == ['b', 'c'] 854 ``` 855 """ 856 if not self._ptr: 857 return 858 859 self._ptr.remove(item) 860 861 def extend(self, iterable: collections.Iterable[T]) -> None: 862 """Extend this vector from another iterable. 863 864 Example 865 ------- 866 ```py 867 vec = Vec((1, 2, 3)) 868 vec.extend((4, 5, 6)) 869 870 assert vec == [1, 2, 3, 4, 5, 6] 871 ``` 872 """ 873 if self._ptr is None: 874 self._ptr = [] 875 876 self._ptr.extend(iterable) 877 878 def copy(self) -> Vec[T]: 879 """Copy all elements of `self` into a new vector. 880 881 Example 882 ------- 883 ```py 884 original = Vec((1,2,3)) 885 copy = original.copy() 886 copy.push(4) 887 888 print(original) # [1, 2, 3] 889 ``` 890 """ 891 return Vec(self._ptr[:]) if self._ptr else Vec() 892 893 def clear(self) -> None: 894 """Clear all elements of this vector. 895 896 Example 897 ------- 898 ```py 899 vec = Vec((1,2,3)) 900 vec.clear() 901 assert vec.len() == 0 902 ``` 903 """ 904 if not self._ptr: 905 return 906 907 self._ptr.clear() 908 909 def sort( 910 self, 911 *, 912 key: collections.Callable[[T], SupportsRichComparison] | None = None, 913 reverse: bool = False, 914 ) -> None: 915 """This method sorts the list in place, using only < comparisons between items. 916 917 Example 918 ------- 919 ```py 920 vec = Vec((2, 1, 3)) 921 vec.sort() 922 assert vec == [1, 2, 3] 923 ``` 924 """ 925 if not self._ptr: 926 return 927 928 # key can be `None` here just fine, idk why pyright is complaining. 929 self._ptr.sort(key=key, reverse=reverse) # pyright: ignore 930 931 def index( 932 self, item: T, start: typing.SupportsIndex = 0, end: int = _sys.maxsize 933 ) -> int: 934 # << Official documentation >> 935 """Return zero-based index in the vec of the first item whose value is equal to `item`. 936 Raises a ValueError if there is no such item. 937 938 Example 939 ------- 940 ```py 941 vec = Vec((1, 2, 3)) 942 assert vec.index(2) == 1 943 ``` 944 """ 945 if self._ptr is None: 946 raise ValueError from None 947 948 return self._ptr.index(item, start, end) 949 950 def count(self, item: T) -> int: 951 """Return the number of occurrences of `item` in the vec. 952 953 `0` is returned if the vector is empty or hasn't been initialized, as well if them item not found. 954 955 Example 956 -------- 957 ```py 958 vec = Vec((1, 2, 3, 3)) 959 assert vec.count(3) == 2 960 ``` 961 """ 962 if self._ptr is None: 963 return 0 964 965 return self._ptr.count(item) 966 967 def __len__(self) -> int: 968 return len(self._ptr) if self._ptr else 0 969 970 def __setitem__(self, index: int, value: T): 971 if not self._ptr: 972 raise IndexError from None 973 974 self._ptr[index] = value 975 976 @typing.overload 977 def __getitem__(self, index: slice) -> Vec[T]: ... 978 979 @typing.overload 980 def __getitem__(self, index: int) -> T: ... 981 982 def __getitem__(self, index: int | slice) -> T | Vec[T]: 983 if not self._ptr: 984 raise IndexError("Index out of range") 985 986 if isinstance(index, slice): 987 return Vec(self._ptr[index]) 988 989 return self._ptr[index] 990 991 def __delitem__(self, index: int) -> None: 992 if not self._ptr: 993 return 994 995 del self._ptr[index] 996 997 def __contains__(self, element: T) -> bool: 998 return element in self._ptr if self._ptr else False 999 1000 def __iter__(self) -> collections.Iterator[T]: 1001 if self._ptr is None: 1002 return iter(()) 1003 1004 return self._ptr.__iter__() 1005 1006 def __repr__(self) -> str: 1007 return "[]" if not self._ptr else repr(self._ptr) 1008 1009 def __eq__(self, other: Vec[T] | list[T]) -> bool: 1010 if isinstance(other, Vec): 1011 return self._ptr == other._ptr 1012 1013 return self._ptr == other 1014 1015 def __ne__(self, other: Vec[T] | list[T]) -> bool: 1016 return not self.__eq__(other) 1017 1018 def __le__(self, other: list[T]) -> bool: 1019 if not self._ptr: 1020 return False 1021 1022 return self._ptr <= other 1023 1024 def __ge__(self, other: list[T]) -> bool: 1025 if not self._ptr: 1026 return False 1027 1028 return self._ptr >= other 1029 1030 def __lt__(self, other: list[T]) -> bool: 1031 if not self._ptr: 1032 return False 1033 1034 return self._ptr < other 1035 1036 def __gt__(self, other: list[T]) -> bool: 1037 if not self._ptr: 1038 return False 1039 1040 return self._ptr > other 1041 1042 def __bool__(self) -> bool: 1043 return bool(self._ptr) 1044 1045 def __reversed__(self) -> collections.Iterator[T]: 1046 return reversed(self._ptr or ())
70@rustc_diagnostic_item("Vec") 71@typing.final 72class Vec(typing.Generic[T], collections.MutableSequence[T], SpecContains[T]): 73 """A contiguous growable alternative to builtin `list` with extra functionalities. 74 75 The layout of `Vec<T>` is exactly the same as `list<T>`. 76 Which means `list<T>`'s methods are inherited into `Vec<T>`. 77 78 Example 79 ------- 80 ```py 81 names = Vec() 82 names.push('foo') 83 names.push('bar') 84 85 print(names) # ['foo', 'bar'] 86 assert names.len() == 2 87 ``` 88 89 Constructing 90 ------------ 91 * `Vec()`: Create an empty vec, this will not allocate the initial buffer. 92 * `Vec(other_list)`: Create a vec which points to `other_list` 93 * `Vec([1, 2, 3])`: Create a vec with `[1, 2, 3]` pre-allocated. 94 * `Vec(iterable)`: Create a vec from an `iterable`, This is `O(n)` where `n` is the number of elements, 95 since it copies `iterable`'s elements into a new list. 96 * `Vec.with_capacity(5)`: Create a vec that can hold up to 5 elements 97 98 Iterating over `Vec` 99 ------------------- 100 There're two ways to iterate over a `Vec`. The first is to normally use `for` loop. 101 102 ```py 103 for i in names: 104 print(i) 105 106 # foo 107 # bar 108 ``` 109 110 The second is to use `Vec.iter`, which yields all items in this `Vec` from start to end. 111 Then the iterator gets exhausted as usual, See `sain.Iterator`. 112 113 ```py 114 iterator = names.iter() 115 for name in iterator.map(str.upper): 116 print(name) 117 118 # FOO 119 # BAR 120 121 # No more items, The actual vec is left unchanged. 122 assert iterator.next().is_none() 123 ``` 124 125 ## Comparison operators 126 A `Vec` may be compared with another `Vec` or a `list`, any other type will return `False` 127 128 ```py 129 vec = Vec([1, 2, 3]) 130 assert vec == [1, 2, 3] # True 131 assert vec != (1, 2, 3) 132 ``` 133 134 Zero-Copy 135 --------- 136 A vec that gets initialized from a `list` will *point* to it and doesn't copy it. 137 So any element that gets appended to the list will also get pushed into the vec 138 that's pointing to it and vice-versa. 139 140 ```py 141 cells: list[str] = [] 142 vec = Vec(cells) # This DOES NOT copy the `cells`. 143 144 cells.append("foo") 145 vec[0] == "foo" # True 146 ``` 147 148 The opposite of the above is to initialize the vec from either 149 an iterable or args, or copy the list. 150 151 ```py 152 from sain.collections import vec, Vec 153 154 # Copy the list into a vec. 155 vec = Vec(cells[:]) 156 cells.append("bar") 157 158 vec[1] # IndexError: "bar" doesn't exist in vec. 159 ``` 160 """ 161 162 __slots__ = ("_ptr", "_capacity") 163 164 @typing.overload 165 def __init__(self) -> None: ... 166 167 @typing.overload 168 def __init__(self, iterable: collections.Iterable[T]) -> None: ... 169 170 def __init__(self, iterable: collections.Iterable[T] | None = None) -> None: 171 """Create an empty `Vec<T>`. 172 173 The vector will not allocate until elements are pushed onto it. 174 175 Example 176 ------ 177 ```py 178 vec: Vec[float] = Vec() 179 ``` 180 """ 181 # We won't allocate to build the list here. 182 # Instead, On first push or fist indexed set 183 # we allocate if it was None. 184 if isinstance(iterable, list): 185 # Calling `list()` on another list will copy it, So instead we just point to it. 186 self._ptr = iterable 187 elif isinstance(iterable, Vec): 188 self._ptr = iterable._ptr 189 # any other iterable that ain't a list needs to get copied into a new list. 190 else: 191 self._ptr: list[T] | None = list(iterable) if iterable else None 192 193 self._capacity: int | None = None 194 195 @classmethod 196 def with_capacity(cls, capacity: int) -> Vec[T]: 197 """Create a new `Vec` with at least the specified capacity. 198 This vec will be able to hold `capacity` elements without pushing further. 199 200 Check out `Vec.push_within_capacity` as well. 201 202 Example 203 ------- 204 ```py 205 vec = Vec.with_capacity(3) 206 assert vec.len() == 0 and vec.capacity() >= 3 207 208 vec.push(1) 209 vec.push(2) 210 vec.push(3) 211 print(vec.len()) # 3 212 213 # This won't push. 214 vec.push(4) 215 ``` 216 """ 217 v = cls() 218 v._capacity = capacity 219 return v 220 221 def as_ref(self) -> Slice[T]: 222 """Return an immutable view over this vector elements. 223 224 No copying occurs. 225 226 Example 227 ------- 228 ```py 229 def send_bytes(v: Slice[int]) -> None: 230 # access `vec` in a read-only mode. 231 socket.write_all(v) 232 233 buf = Vec([1, 2, 3]) 234 send_bytes(buf.as_ref()) 235 ``` 236 """ 237 return Slice(self) 238 239 def as_mut(self) -> SliceMut[T]: 240 """Return a mutable view over this vector elements. 241 242 No copying occurs. 243 244 Example 245 ------- 246 ```py 247 def read_bytes(buf: SliceMut[int]) -> None: 248 socket.read_to_end(buf.as_mut()) 249 250 buf: Vec[int] = Vec() 251 read_bytes(buf.as_mut()) # or just `buf` 252 assert vec.len() >= 1 253 ``` 254 """ 255 return SliceMut(self) 256 257 def len(self) -> int: 258 """Return the number of elements in this vector. 259 260 Example 261 ------- 262 ```py 263 vec = Vec((1,2,3)) 264 265 assert vec.len() == 3 266 ``` 267 """ 268 return self.__len__() 269 270 def capacity(self) -> int: 271 """Return the capacity of this vector if set, 0 if not . 272 273 The number `0` here has two different Meanings: 274 - The first means the `Vec` doesn't have a specific capacity set. 275 - The second means the `Vec` literally initialized with `0` capacity. 276 277 Example 278 ------- 279 ```py 280 vec_with_cap = Vec.with_capacity(3) 281 assert vec_with_cap.capacity().unwrap() == 3 282 283 vec = Vec([1, 2, 3]) 284 assert vec.capacity() == 0 285 ``` 286 """ 287 return 0 if self._capacity is None else self._capacity 288 289 def iter(self) -> _iter.TrustedIter[T]: 290 """Returns an iterator over this vector elements. 291 292 Example 293 ------- 294 ```py 295 vec = Vec([1 ,2, 3]) 296 for element in vec.iter().map(str): 297 print(element) 298 ``` 299 """ 300 return _iter.TrustedIter(self._ptr or ()) 301 302 def is_empty(self) -> bool: 303 """Returns true if the vector contains no elements. 304 305 Inlined into: 306 ```py 307 not self.vec 308 ``` 309 """ 310 return not self._ptr 311 312 def leak(self) -> list[T]: 313 """Consumes and leaks the Vec, returning a mutable reference to the contents. 314 315 After calling this, this vec will no longer reference the underlying buffer, 316 therefore, it becomes unusable. 317 318 if `self` is uninitialized, an empty list is returned. 319 320 This function is only useful when you want to detach from a `Vec<T>` and get a `list[T]` without 321 any copies. 322 323 Example 324 ------- 325 ```py 326 x = Vec([1, 2, 3]) 327 owned = x.leak() 328 # x is now unusable. 329 owned[0] += 1 330 assert owned == [2, 2, 3] 331 ``` 332 """ 333 if self._ptr is not None: 334 # don't point to `_ptr` anymore. 335 tmp = self._ptr 336 del self._ptr 337 return tmp 338 339 return [] 340 341 def split_off(self, at: int) -> Vec[T]: 342 """Split the vector off at the specified position, returning a new 343 vec at the range of `[at : len]`, leaving `self` at `[at : vec_len]`. 344 345 if this vec is empty, `self` is returned unchanged. 346 347 Example 348 ------- 349 ```py 350 origin = Vec((1, 2, 3, 4)) 351 split = vec.split_off(2) 352 353 print(origin, split) # [1, 2], [3, 4] 354 ``` 355 356 Raises 357 ------ 358 `IndexError` 359 This method will raise if `at` > `len(self)` 360 """ 361 len_ = self.len() 362 if at > len_: 363 raise IndexError( 364 f"Index `at` ({at}) should be <= than len of vector ({len_}) " 365 ) from None 366 367 # Either the list is empty or uninit. 368 if not self._ptr: 369 return self 370 371 split = self[at:len_] # split the items into a new vec. 372 del self._ptr[at:len_] # remove the items from the original list. 373 return split 374 375 def split_first(self) -> _option.Option[tuple[T, collections.Sequence[T]]]: 376 """Split the first and rest elements of the vector, If empty, `None` is returned. 377 378 Example 379 ------- 380 ```py 381 vec = Vec([1, 2, 3]) 382 split = vec.split_first() 383 assert split == Some((1, [2, 3])) 384 385 vec: Vec[int] = Vec() 386 split = vec.split_first() 387 assert split.is_none() 388 ``` 389 """ 390 if not self._ptr: 391 return _option.NOTHING 392 393 # optimized to only one element in the vector. 394 if self.len() == 1: 395 return _option.Some((self[0], ())) 396 397 first, *rest = self._ptr 398 return _option.Some((first, rest)) 399 400 def split_last(self) -> _option.Option[tuple[T, collections.Sequence[T]]]: 401 """Split the last and rest elements of the vector, If empty, `None` is returned. 402 403 Example 404 ------- 405 ```py 406 vec = Vec([1, 2, 3]) 407 last, rest = vec.split_last().unwrap() 408 assert (last, rest) == [3, [1, 2]] 409 ``` 410 """ 411 if not self._ptr: 412 return _option.NOTHING 413 414 # optimized to only one element in the vector. 415 if self.len() == 1: 416 return _option.Some((self[0], ())) 417 418 last, *rest = self._ptr[-1], *self._ptr[:-1] 419 return _option.Some((last, rest)) 420 421 def split_at(self, mid: int) -> tuple[Vec[T], Vec[T]]: 422 """Divide `self` into two at an index. 423 424 The first will contain all elements from `[0:mid]` excluding `mid` it self. 425 and the second will contain the remaining elements. 426 427 if `mid` > `self.len()`, Then all elements will be moved to the left, 428 returning an empty vec in right. 429 430 Example 431 ------- 432 ```py 433 buffer = Vec((1, 2, 3, 4)) 434 left, right = buffer.split_at(0) 435 assert left == [] and right == [1, 2, 3, 4] 436 437 left, right = buffer.split_at(2) 438 assert left == [1, 2] and right == [2, 3] 439 ``` 440 441 The is roughly the implementation 442 ```py 443 vec[0:mid], vec[mid:] 444 ``` 445 """ 446 return self[0:mid], self[mid:] 447 448 def swap(self, a: int, b: int): 449 """Swap two elements in the vec. 450 451 if `a` equals to `b` then it's guaranteed that elements won't change value. 452 453 Example 454 ------- 455 ```py 456 buf = Vec([1, 2, 3, 4]) 457 buf.swap(0, 3) 458 assert buf == [4, 2, 3, 1] 459 ``` 460 461 Raises 462 ------ 463 IndexError 464 If the positions of `a` or `b` are out of index. 465 """ 466 if self[a] == self[b]: 467 return 468 469 self[a], self[b] = self[b], self[a] 470 471 def swap_unchecked(self, a: int, b: int): 472 """Swap two elements in the vec. without checking if `a` == `b`. 473 474 If you care about `a` and `b` equality, see `Vec.swap`. 475 476 Example 477 ------- 478 ```py 479 buf = Vec([1, 2, 3, 1]) 480 buf.swap_unchecked(0, 3) 481 assert buf == [1, 2, 3, 1] 482 ``` 483 484 Raises 485 ------ 486 IndexError 487 If the positions of `a` or `b` are out of index. 488 """ 489 self[a], self[b] = self[b], self[a] 490 491 def first(self) -> _option.Option[T]: 492 """Get the first element in this vec, returning `None` if there's none. 493 494 Example 495 ------- 496 ```py 497 vec = Vec((1,2,3)) 498 first = vec.first() 499 assert ~first == 1 500 ``` 501 """ 502 return self.get(0) 503 504 def last(self) -> _option.Option[T]: 505 """Get the last element in this vec, returning `None` if there's none. 506 507 Example 508 ------- 509 ```py 510 vec = Vec([1, 2, 3, 4]) 511 first = vec.last() 512 assert ~first == 4 513 ``` 514 """ 515 return self.get(-1) 516 517 def truncate(self, size: int) -> None: 518 """Shortens the vec, keeping the first `size` elements and dropping the rest. 519 520 Example 521 ------- 522 ```py 523 vec = Vec([1,2,3]) 524 vec.truncate(1) 525 assert vec == [1] 526 ``` 527 """ 528 if not self._ptr: 529 return 530 531 del self._ptr[size:] 532 533 def retain(self, f: collections.Callable[[T], bool]) -> None: 534 """Retains only the elements specified by the predicate. 535 536 This operation occurs in-place without copying the original list. 537 538 Example 539 ------- 540 ```py 541 vec = Vec([1, 2, 3]) 542 vec.retain(lambda elem: elem > 1) 543 544 assert vec == [2, 3] 545 ``` 546 547 The impl for this method is very simple 548 ```py 549 for idx, e in enumerate(vec): 550 if not f(e): 551 del vec[idx] 552 ``` 553 """ 554 if not self._ptr: 555 return 556 557 idx = 0 558 while idx < len(self._ptr): 559 if not f(self._ptr[idx]): 560 del self._ptr[idx] 561 else: 562 idx += 1 563 564 def swap_remove(self, item: T) -> T: 565 """Remove the first appearance of `item` from this vector and return it. 566 567 Raises 568 ------ 569 * `ValueError`: if `item` is not in this vector. 570 * `MemoryError`: if this vector hasn't allocated, Aka nothing has been pushed to it. 571 572 Example 573 ------- 574 ```py 575 vec = Vec(('a', 'b', 'c')) 576 element = vec.remove('a') 577 assert vec == ['b', 'c'] and element == 'a' 578 ``` 579 """ 580 if self._ptr is None: 581 raise MemoryError("Vec is unallocated.") from None 582 583 return self._ptr.pop(self.index(item)) 584 585 def fill(self, value: T) -> None: 586 """Fill `self` with the given `value`. 587 588 Nothing happens if the vec is empty or unallocated. 589 590 Example 591 ```py 592 a = Vec([0, 1, 2, 3]) 593 a.fill(0) 594 assert a == [0, 0, 0, 0] 595 ``` 596 """ 597 if not self._ptr: 598 return 599 600 for n, _ in enumerate(self): 601 self[n] = value 602 603 def push(self, item: T) -> None: 604 """Push an element at the end of the vector. 605 606 Example 607 ------- 608 ```py 609 vec = Vec() 610 vec.push(1) 611 612 assert vec == [1] 613 ``` 614 """ 615 if self._capacity is not None: 616 self.push_within_capacity(item) 617 return 618 619 if self._ptr is None: 620 self._ptr = [] 621 622 self._ptr.append(item) 623 624 def push_within_capacity(self, x: T) -> Result[None, T]: 625 """Appends an element if there is sufficient spare capacity, otherwise an error is returned with the element. 626 627 Example 628 ------- 629 ```py 630 vec: Vec[int] = Vec.with_capacity(3) 631 for i in range(3): 632 match vec.push_within_capacity(i): 633 case Ok(_): 634 print("All good.") 635 case Err(elem): 636 print("Reached max cap :< can't push", elem) 637 ``` 638 639 Or you can also just call `Vec.push` and it will push if there's is sufficient capacity. 640 ```py 641 vec: Vec[int] = Vec.with_capacity(3) 642 643 vec.extend((1, 2, 3)) 644 vec.push(4) 645 646 assert vec.len() == 3 647 ``` 648 """ 649 if self._ptr is None: 650 self._ptr = [] 651 652 if self.len() == self._capacity: 653 return _result.Err(x) 654 655 self._ptr.append(x) 656 return _result.Ok(None) 657 658 def reserve(self, additional: int) -> None: 659 """Reserves capacity for at least additional more elements to be inserted in the given Vec<T>. 660 661 Example 662 ------- 663 ```py 664 vec = Vec.with_capacity(3) 665 is_vip = random.choice((True, False)) 666 667 for i in range(4): 668 match vec.push_within_capacity(i): 669 case Ok(_): 670 print("All good") 671 case Err(person): 672 # If the person is a VIP, then reserve for one more. 673 if is_vip: 674 vec.reserve(1) 675 continue 676 677 # is_vip was false. 678 print("Can't reserve for non-VIP members...", person) 679 break 680 ``` 681 """ 682 if self._capacity is not None: 683 self._capacity += additional 684 685 def shrink_to_fit(self) -> None: 686 """Shrink the capacity of this `Vec` to match its length. 687 688 If `self` is initialized with no capacity, This is a `NOP`. 689 690 Example 691 ------- 692 ```py 693 s = Vec([1, 2, 3, 4]) 694 695 s.reserve(100) 696 s.shrink_to_fit() 697 assert s.capacity() == 4 698 ``` 699 """ 700 if self._capacity is None: 701 return 702 703 # The capacity is never less than the length. 704 self._capacity = min(self.__len__(), self._capacity) 705 706 def shrink_to(self, min_capacity: int) -> None: 707 """Shrink the capacity of this `Vec` to a minimum specified capacity. 708 709 If `self` is initialized with no capacity or the current capacity is less than the lower limit, 710 This is a `NOP`. 711 712 Example 713 ------- 714 ```py 715 vec = Vec.with_capacity(10) 716 vec.extend([1, 2, 3]) 717 assert vec.capacity() >= 10 718 vec.shrink_to(4) 719 assert vec.capacity() >= 4 720 vec.shrink_to(0) 721 ``` 722 """ 723 if self._capacity is None or self._capacity <= min_capacity: 724 return 725 726 # Ensure the capacity is not reduced below the current length of the vector. 727 self._capacity = max(self.__len__(), min_capacity) 728 729 ########################## 730 # * Builtin Operations * 731 ########################## 732 733 def append(self, value: T) -> None: 734 """An alias to `Vec.push`.""" 735 self.push(value) 736 737 def get(self, index: int) -> _option.Option[T]: 738 """Get the item at the given index, or `Some[None]` if its out of bounds. 739 740 Example 741 ------- 742 ```py 743 vec = Vec((1, 2, 3)) 744 vec.get(0) == Some(1) 745 vec.get(3) == Some(None) 746 ``` 747 """ 748 try: 749 return _option.Some(self[index]) 750 except IndexError: 751 return _option.NOTHING 752 753 def insert(self, index: int, value: T) -> None: 754 """Insert an element at the position `index`. 755 756 Example 757 -------- 758 ```py 759 vec = Vec((2, 3)) 760 vec.insert(0, 1) 761 assert vec == [1, 2, 3] 762 ``` 763 """ 764 self.__setitem__(index, value) 765 766 def pop(self, index: int = -1) -> _option.Option[T]: 767 """Removes the last element from a vector and returns it, or `None` if it is empty. 768 769 Example 770 ------- 771 ```py 772 vec = Vec((1, 2, 3)) 773 assert vec.pop() == Some(3) 774 assert vec == [1, 2] 775 ``` 776 """ 777 if not self._ptr: 778 return _option.NOTHING 779 780 return _option.Some(self._ptr.pop(index)) 781 782 def pop_if(self, pred: collections.Callable[[T], bool]) -> _option.Option[T]: 783 """Removes the last element from a vector and returns it if `f` returns `True`, 784 or `None` if it is empty. 785 786 Example 787 ------- 788 ```py 789 vec = Vec((1, 2, 3)) 790 assert vec.pop_if(lambda num: num * 2 == 6) == Some(3) 791 assert vec == [1, 2] 792 ``` 793 """ 794 if not self._ptr: 795 return _option.NOTHING 796 797 if pred(self[-1]): 798 return self.pop() 799 800 return _option.NOTHING 801 802 def dedup(self) -> None: 803 """Removes consecutive repeated elements in the vector according to their `__eq__` 804 implementation. 805 806 Example 807 ------- 808 ```py 809 vec = Vec([1, 2, 2, 3, 2]) 810 vec.dedup() 811 assert vec == [1, 2, 3, 2] 812 """ 813 self.dedup_by(lambda a, b: a == b) 814 815 def dedup_by(self, same_bucket: collections.Callable[[T, T], bool]) -> None: 816 """Removes all but the first of consecutive elements in the vector satisfying a given equality. 817 818 Example 819 ------- 820 ```py 821 vec = Vec(["foo", "bar", "Bar", "baz", "bar"]) 822 vec.dedup_by(lambda a, b: a.lower() == b.lower()) 823 assert vec == ["foo", "bar", "baz", "bar"] 824 ``` 825 826 Only remove consecutive duplicates. 827 ```py 828 vec = Vec([1, 2, 2, 3, 4, 1]) 829 vec.dedup_by(lambda a, b: a == b) 830 # The final 1 is not adjacent to the first 1, so it is not removed. 831 assert vec == [1, 2, 3, 4, 1] 832 ``` 833 """ 834 835 if not self._ptr or (len_ := len(self._ptr)) <= 1: 836 return 837 838 idx = 1 839 while idx < len_: 840 if same_bucket(self._ptr[idx], self._ptr[idx - 1]): 841 del self._ptr[idx] 842 len_ -= 1 843 else: 844 idx += 1 845 846 def remove(self, item: T) -> None: 847 """Remove the first appearance of `item` from this vector. 848 849 Example 850 ------- 851 ```py 852 vec = Vec(('a', 'b', 'c')) 853 vec.remove('a') 854 assert vec == ['b', 'c'] 855 ``` 856 """ 857 if not self._ptr: 858 return 859 860 self._ptr.remove(item) 861 862 def extend(self, iterable: collections.Iterable[T]) -> None: 863 """Extend this vector from another iterable. 864 865 Example 866 ------- 867 ```py 868 vec = Vec((1, 2, 3)) 869 vec.extend((4, 5, 6)) 870 871 assert vec == [1, 2, 3, 4, 5, 6] 872 ``` 873 """ 874 if self._ptr is None: 875 self._ptr = [] 876 877 self._ptr.extend(iterable) 878 879 def copy(self) -> Vec[T]: 880 """Copy all elements of `self` into a new vector. 881 882 Example 883 ------- 884 ```py 885 original = Vec((1,2,3)) 886 copy = original.copy() 887 copy.push(4) 888 889 print(original) # [1, 2, 3] 890 ``` 891 """ 892 return Vec(self._ptr[:]) if self._ptr else Vec() 893 894 def clear(self) -> None: 895 """Clear all elements of this vector. 896 897 Example 898 ------- 899 ```py 900 vec = Vec((1,2,3)) 901 vec.clear() 902 assert vec.len() == 0 903 ``` 904 """ 905 if not self._ptr: 906 return 907 908 self._ptr.clear() 909 910 def sort( 911 self, 912 *, 913 key: collections.Callable[[T], SupportsRichComparison] | None = None, 914 reverse: bool = False, 915 ) -> None: 916 """This method sorts the list in place, using only < comparisons between items. 917 918 Example 919 ------- 920 ```py 921 vec = Vec((2, 1, 3)) 922 vec.sort() 923 assert vec == [1, 2, 3] 924 ``` 925 """ 926 if not self._ptr: 927 return 928 929 # key can be `None` here just fine, idk why pyright is complaining. 930 self._ptr.sort(key=key, reverse=reverse) # pyright: ignore 931 932 def index( 933 self, item: T, start: typing.SupportsIndex = 0, end: int = _sys.maxsize 934 ) -> int: 935 # << Official documentation >> 936 """Return zero-based index in the vec of the first item whose value is equal to `item`. 937 Raises a ValueError if there is no such item. 938 939 Example 940 ------- 941 ```py 942 vec = Vec((1, 2, 3)) 943 assert vec.index(2) == 1 944 ``` 945 """ 946 if self._ptr is None: 947 raise ValueError from None 948 949 return self._ptr.index(item, start, end) 950 951 def count(self, item: T) -> int: 952 """Return the number of occurrences of `item` in the vec. 953 954 `0` is returned if the vector is empty or hasn't been initialized, as well if them item not found. 955 956 Example 957 -------- 958 ```py 959 vec = Vec((1, 2, 3, 3)) 960 assert vec.count(3) == 2 961 ``` 962 """ 963 if self._ptr is None: 964 return 0 965 966 return self._ptr.count(item) 967 968 def __len__(self) -> int: 969 return len(self._ptr) if self._ptr else 0 970 971 def __setitem__(self, index: int, value: T): 972 if not self._ptr: 973 raise IndexError from None 974 975 self._ptr[index] = value 976 977 @typing.overload 978 def __getitem__(self, index: slice) -> Vec[T]: ... 979 980 @typing.overload 981 def __getitem__(self, index: int) -> T: ... 982 983 def __getitem__(self, index: int | slice) -> T | Vec[T]: 984 if not self._ptr: 985 raise IndexError("Index out of range") 986 987 if isinstance(index, slice): 988 return Vec(self._ptr[index]) 989 990 return self._ptr[index] 991 992 def __delitem__(self, index: int) -> None: 993 if not self._ptr: 994 return 995 996 del self._ptr[index] 997 998 def __contains__(self, element: T) -> bool: 999 return element in self._ptr if self._ptr else False 1000 1001 def __iter__(self) -> collections.Iterator[T]: 1002 if self._ptr is None: 1003 return iter(()) 1004 1005 return self._ptr.__iter__() 1006 1007 def __repr__(self) -> str: 1008 return "[]" if not self._ptr else repr(self._ptr) 1009 1010 def __eq__(self, other: Vec[T] | list[T]) -> bool: 1011 if isinstance(other, Vec): 1012 return self._ptr == other._ptr 1013 1014 return self._ptr == other 1015 1016 def __ne__(self, other: Vec[T] | list[T]) -> bool: 1017 return not self.__eq__(other) 1018 1019 def __le__(self, other: list[T]) -> bool: 1020 if not self._ptr: 1021 return False 1022 1023 return self._ptr <= other 1024 1025 def __ge__(self, other: list[T]) -> bool: 1026 if not self._ptr: 1027 return False 1028 1029 return self._ptr >= other 1030 1031 def __lt__(self, other: list[T]) -> bool: 1032 if not self._ptr: 1033 return False 1034 1035 return self._ptr < other 1036 1037 def __gt__(self, other: list[T]) -> bool: 1038 if not self._ptr: 1039 return False 1040 1041 return self._ptr > other 1042 1043 def __bool__(self) -> bool: 1044 return bool(self._ptr) 1045 1046 def __reversed__(self) -> collections.Iterator[T]: 1047 return reversed(self._ptr or ())
A contiguous growable alternative to builtin list with extra functionalities.
The layout of Vec<T> is exactly the same as list<T>.
Which means list<T>'s methods are inherited into Vec<T>.
Example
names = Vec()
names.push('foo')
names.push('bar')
print(names) # ['foo', 'bar']
assert names.len() == 2
Constructing
Vec(): Create an empty vec, this will not allocate the initial buffer.Vec(other_list): Create a vec which points toother_listVec([1, 2, 3]): Create a vec with[1, 2, 3]pre-allocated.Vec(iterable): Create a vec from aniterable, This isO(n)wherenis the number of elements, since it copiesiterable's elements into a new list.Vec.with_capacity(5): Create a vec that can hold up to 5 elements
Iterating over Vec
There're two ways to iterate over a Vec. The first is to normally use for loop.
for i in names:
print(i)
# foo
# bar
The second is to use Vec.iter, which yields all items in this Vec from start to end.
Then the iterator gets exhausted as usual, See sain.Iterator.
iterator = names.iter()
for name in iterator.map(str.upper):
print(name)
# FOO
# BAR
# No more items, The actual vec is left unchanged.
assert iterator.next().is_none()
Comparison operators
A Vec may be compared with another Vec or a list, any other type will return False
vec = Vec([1, 2, 3])
assert vec == [1, 2, 3] # True
assert vec != (1, 2, 3)
Zero-Copy
A vec that gets initialized from a list will point to it and doesn't copy it.
So any element that gets appended to the list will also get pushed into the vec
that's pointing to it and vice-versa.
cells: list[str] = []
vec = Vec(cells) # This DOES NOT copy the `cells`.
cells.append("foo")
vec[0] == "foo" # True
The opposite of the above is to initialize the vec from either an iterable or args, or copy the list.
from sain.collections import vec, Vec
# Copy the list into a vec.
vec = Vec(cells[:])
cells.append("bar")
vec[1] # IndexError: "bar" doesn't exist in vec.
Implementations
This class implements Vec in Rust.
170 def __init__(self, iterable: collections.Iterable[T] | None = None) -> None: 171 """Create an empty `Vec<T>`. 172 173 The vector will not allocate until elements are pushed onto it. 174 175 Example 176 ------ 177 ```py 178 vec: Vec[float] = Vec() 179 ``` 180 """ 181 # We won't allocate to build the list here. 182 # Instead, On first push or fist indexed set 183 # we allocate if it was None. 184 if isinstance(iterable, list): 185 # Calling `list()` on another list will copy it, So instead we just point to it. 186 self._ptr = iterable 187 elif isinstance(iterable, Vec): 188 self._ptr = iterable._ptr 189 # any other iterable that ain't a list needs to get copied into a new list. 190 else: 191 self._ptr: list[T] | None = list(iterable) if iterable else None 192 193 self._capacity: int | None = None
Create an empty Vec<T>.
The vector will not allocate until elements are pushed onto it.
Example
vec: Vec[float] = Vec()
195 @classmethod 196 def with_capacity(cls, capacity: int) -> Vec[T]: 197 """Create a new `Vec` with at least the specified capacity. 198 This vec will be able to hold `capacity` elements without pushing further. 199 200 Check out `Vec.push_within_capacity` as well. 201 202 Example 203 ------- 204 ```py 205 vec = Vec.with_capacity(3) 206 assert vec.len() == 0 and vec.capacity() >= 3 207 208 vec.push(1) 209 vec.push(2) 210 vec.push(3) 211 print(vec.len()) # 3 212 213 # This won't push. 214 vec.push(4) 215 ``` 216 """ 217 v = cls() 218 v._capacity = capacity 219 return v
Create a new Vec with at least the specified capacity.
This vec will be able to hold capacity elements without pushing further.
Check out Vec.push_within_capacity as well.
Example
vec = Vec.with_capacity(3)
assert vec.len() == 0 and vec.capacity() >= 3
vec.push(1)
vec.push(2)
vec.push(3)
print(vec.len()) # 3
# This won't push.
vec.push(4)
221 def as_ref(self) -> Slice[T]: 222 """Return an immutable view over this vector elements. 223 224 No copying occurs. 225 226 Example 227 ------- 228 ```py 229 def send_bytes(v: Slice[int]) -> None: 230 # access `vec` in a read-only mode. 231 socket.write_all(v) 232 233 buf = Vec([1, 2, 3]) 234 send_bytes(buf.as_ref()) 235 ``` 236 """ 237 return Slice(self)
Return an immutable view over this vector elements.
No copying occurs.
Example
def send_bytes(v: Slice[int]) -> None:
# access `vec` in a read-only mode.
socket.write_all(v)
buf = Vec([1, 2, 3])
send_bytes(buf.as_ref())
239 def as_mut(self) -> SliceMut[T]: 240 """Return a mutable view over this vector elements. 241 242 No copying occurs. 243 244 Example 245 ------- 246 ```py 247 def read_bytes(buf: SliceMut[int]) -> None: 248 socket.read_to_end(buf.as_mut()) 249 250 buf: Vec[int] = Vec() 251 read_bytes(buf.as_mut()) # or just `buf` 252 assert vec.len() >= 1 253 ``` 254 """ 255 return SliceMut(self)
Return a mutable view over this vector elements.
No copying occurs.
Example
def read_bytes(buf: SliceMut[int]) -> None:
socket.read_to_end(buf.as_mut())
buf: Vec[int] = Vec()
read_bytes(buf.as_mut()) # or just `buf`
assert vec.len() >= 1
257 def len(self) -> int: 258 """Return the number of elements in this vector. 259 260 Example 261 ------- 262 ```py 263 vec = Vec((1,2,3)) 264 265 assert vec.len() == 3 266 ``` 267 """ 268 return self.__len__()
Return the number of elements in this vector.
Example
vec = Vec((1,2,3))
assert vec.len() == 3
270 def capacity(self) -> int: 271 """Return the capacity of this vector if set, 0 if not . 272 273 The number `0` here has two different Meanings: 274 - The first means the `Vec` doesn't have a specific capacity set. 275 - The second means the `Vec` literally initialized with `0` capacity. 276 277 Example 278 ------- 279 ```py 280 vec_with_cap = Vec.with_capacity(3) 281 assert vec_with_cap.capacity().unwrap() == 3 282 283 vec = Vec([1, 2, 3]) 284 assert vec.capacity() == 0 285 ``` 286 """ 287 return 0 if self._capacity is None else self._capacity
Return the capacity of this vector if set, 0 if not .
The number 0 here has two different Meanings:
- The first means the
Vecdoesn't have a specific capacity set. - The second means the
Vecliterally initialized with0capacity.
Example
vec_with_cap = Vec.with_capacity(3)
assert vec_with_cap.capacity().unwrap() == 3
vec = Vec([1, 2, 3])
assert vec.capacity() == 0
289 def iter(self) -> _iter.TrustedIter[T]: 290 """Returns an iterator over this vector elements. 291 292 Example 293 ------- 294 ```py 295 vec = Vec([1 ,2, 3]) 296 for element in vec.iter().map(str): 297 print(element) 298 ``` 299 """ 300 return _iter.TrustedIter(self._ptr or ())
Returns an iterator over this vector elements.
Example
vec = Vec([1 ,2, 3])
for element in vec.iter().map(str):
print(element)
302 def is_empty(self) -> bool: 303 """Returns true if the vector contains no elements. 304 305 Inlined into: 306 ```py 307 not self.vec 308 ``` 309 """ 310 return not self._ptr
Returns true if the vector contains no elements.
Inlined into:
not self.vec
312 def leak(self) -> list[T]: 313 """Consumes and leaks the Vec, returning a mutable reference to the contents. 314 315 After calling this, this vec will no longer reference the underlying buffer, 316 therefore, it becomes unusable. 317 318 if `self` is uninitialized, an empty list is returned. 319 320 This function is only useful when you want to detach from a `Vec<T>` and get a `list[T]` without 321 any copies. 322 323 Example 324 ------- 325 ```py 326 x = Vec([1, 2, 3]) 327 owned = x.leak() 328 # x is now unusable. 329 owned[0] += 1 330 assert owned == [2, 2, 3] 331 ``` 332 """ 333 if self._ptr is not None: 334 # don't point to `_ptr` anymore. 335 tmp = self._ptr 336 del self._ptr 337 return tmp 338 339 return []
Consumes and leaks the Vec, returning a mutable reference to the contents.
After calling this, this vec will no longer reference the underlying buffer, therefore, it becomes unusable.
if self is uninitialized, an empty list is returned.
This function is only useful when you want to detach from a Vec<T> and get a list[T] without
any copies.
Example
x = Vec([1, 2, 3])
owned = x.leak()
# x is now unusable.
owned[0] += 1
assert owned == [2, 2, 3]
341 def split_off(self, at: int) -> Vec[T]: 342 """Split the vector off at the specified position, returning a new 343 vec at the range of `[at : len]`, leaving `self` at `[at : vec_len]`. 344 345 if this vec is empty, `self` is returned unchanged. 346 347 Example 348 ------- 349 ```py 350 origin = Vec((1, 2, 3, 4)) 351 split = vec.split_off(2) 352 353 print(origin, split) # [1, 2], [3, 4] 354 ``` 355 356 Raises 357 ------ 358 `IndexError` 359 This method will raise if `at` > `len(self)` 360 """ 361 len_ = self.len() 362 if at > len_: 363 raise IndexError( 364 f"Index `at` ({at}) should be <= than len of vector ({len_}) " 365 ) from None 366 367 # Either the list is empty or uninit. 368 if not self._ptr: 369 return self 370 371 split = self[at:len_] # split the items into a new vec. 372 del self._ptr[at:len_] # remove the items from the original list. 373 return split
Split the vector off at the specified position, returning a new
vec at the range of [at : len], leaving self at [at : vec_len].
if this vec is empty, self is returned unchanged.
Example
origin = Vec((1, 2, 3, 4))
split = vec.split_off(2)
print(origin, split) # [1, 2], [3, 4]
Raises
IndexError: This method will raise ifat>len(self)
375 def split_first(self) -> _option.Option[tuple[T, collections.Sequence[T]]]: 376 """Split the first and rest elements of the vector, If empty, `None` is returned. 377 378 Example 379 ------- 380 ```py 381 vec = Vec([1, 2, 3]) 382 split = vec.split_first() 383 assert split == Some((1, [2, 3])) 384 385 vec: Vec[int] = Vec() 386 split = vec.split_first() 387 assert split.is_none() 388 ``` 389 """ 390 if not self._ptr: 391 return _option.NOTHING 392 393 # optimized to only one element in the vector. 394 if self.len() == 1: 395 return _option.Some((self[0], ())) 396 397 first, *rest = self._ptr 398 return _option.Some((first, rest))
Split the first and rest elements of the vector, If empty, None is returned.
Example
vec = Vec([1, 2, 3])
split = vec.split_first()
assert split == Some((1, [2, 3]))
vec: Vec[int] = Vec()
split = vec.split_first()
assert split.is_none()
400 def split_last(self) -> _option.Option[tuple[T, collections.Sequence[T]]]: 401 """Split the last and rest elements of the vector, If empty, `None` is returned. 402 403 Example 404 ------- 405 ```py 406 vec = Vec([1, 2, 3]) 407 last, rest = vec.split_last().unwrap() 408 assert (last, rest) == [3, [1, 2]] 409 ``` 410 """ 411 if not self._ptr: 412 return _option.NOTHING 413 414 # optimized to only one element in the vector. 415 if self.len() == 1: 416 return _option.Some((self[0], ())) 417 418 last, *rest = self._ptr[-1], *self._ptr[:-1] 419 return _option.Some((last, rest))
Split the last and rest elements of the vector, If empty, None is returned.
Example
vec = Vec([1, 2, 3])
last, rest = vec.split_last().unwrap()
assert (last, rest) == [3, [1, 2]]
421 def split_at(self, mid: int) -> tuple[Vec[T], Vec[T]]: 422 """Divide `self` into two at an index. 423 424 The first will contain all elements from `[0:mid]` excluding `mid` it self. 425 and the second will contain the remaining elements. 426 427 if `mid` > `self.len()`, Then all elements will be moved to the left, 428 returning an empty vec in right. 429 430 Example 431 ------- 432 ```py 433 buffer = Vec((1, 2, 3, 4)) 434 left, right = buffer.split_at(0) 435 assert left == [] and right == [1, 2, 3, 4] 436 437 left, right = buffer.split_at(2) 438 assert left == [1, 2] and right == [2, 3] 439 ``` 440 441 The is roughly the implementation 442 ```py 443 vec[0:mid], vec[mid:] 444 ``` 445 """ 446 return self[0:mid], self[mid:]
Divide self into two at an index.
The first will contain all elements from [0:mid] excluding mid it self.
and the second will contain the remaining elements.
if mid > self.len(), Then all elements will be moved to the left,
returning an empty vec in right.
Example
buffer = Vec((1, 2, 3, 4))
left, right = buffer.split_at(0)
assert left == [] and right == [1, 2, 3, 4]
left, right = buffer.split_at(2)
assert left == [1, 2] and right == [2, 3]
The is roughly the implementation
vec[0:mid], vec[mid:]
448 def swap(self, a: int, b: int): 449 """Swap two elements in the vec. 450 451 if `a` equals to `b` then it's guaranteed that elements won't change value. 452 453 Example 454 ------- 455 ```py 456 buf = Vec([1, 2, 3, 4]) 457 buf.swap(0, 3) 458 assert buf == [4, 2, 3, 1] 459 ``` 460 461 Raises 462 ------ 463 IndexError 464 If the positions of `a` or `b` are out of index. 465 """ 466 if self[a] == self[b]: 467 return 468 469 self[a], self[b] = self[b], self[a]
Swap two elements in the vec.
if a equals to b then it's guaranteed that elements won't change value.
Example
buf = Vec([1, 2, 3, 4])
buf.swap(0, 3)
assert buf == [4, 2, 3, 1]
Raises
- IndexError: If the positions of
aorbare out of index.
471 def swap_unchecked(self, a: int, b: int): 472 """Swap two elements in the vec. without checking if `a` == `b`. 473 474 If you care about `a` and `b` equality, see `Vec.swap`. 475 476 Example 477 ------- 478 ```py 479 buf = Vec([1, 2, 3, 1]) 480 buf.swap_unchecked(0, 3) 481 assert buf == [1, 2, 3, 1] 482 ``` 483 484 Raises 485 ------ 486 IndexError 487 If the positions of `a` or `b` are out of index. 488 """ 489 self[a], self[b] = self[b], self[a]
Swap two elements in the vec. without checking if a == b.
If you care about a and b equality, see Vec.swap.
Example
buf = Vec([1, 2, 3, 1])
buf.swap_unchecked(0, 3)
assert buf == [1, 2, 3, 1]
Raises
- IndexError: If the positions of
aorbare out of index.
491 def first(self) -> _option.Option[T]: 492 """Get the first element in this vec, returning `None` if there's none. 493 494 Example 495 ------- 496 ```py 497 vec = Vec((1,2,3)) 498 first = vec.first() 499 assert ~first == 1 500 ``` 501 """ 502 return self.get(0)
Get the first element in this vec, returning None if there's none.
Example
vec = Vec((1,2,3))
first = vec.first()
assert ~first == 1
504 def last(self) -> _option.Option[T]: 505 """Get the last element in this vec, returning `None` if there's none. 506 507 Example 508 ------- 509 ```py 510 vec = Vec([1, 2, 3, 4]) 511 first = vec.last() 512 assert ~first == 4 513 ``` 514 """ 515 return self.get(-1)
Get the last element in this vec, returning None if there's none.
Example
vec = Vec([1, 2, 3, 4])
first = vec.last()
assert ~first == 4
517 def truncate(self, size: int) -> None: 518 """Shortens the vec, keeping the first `size` elements and dropping the rest. 519 520 Example 521 ------- 522 ```py 523 vec = Vec([1,2,3]) 524 vec.truncate(1) 525 assert vec == [1] 526 ``` 527 """ 528 if not self._ptr: 529 return 530 531 del self._ptr[size:]
Shortens the vec, keeping the first size elements and dropping the rest.
Example
vec = Vec([1,2,3])
vec.truncate(1)
assert vec == [1]
533 def retain(self, f: collections.Callable[[T], bool]) -> None: 534 """Retains only the elements specified by the predicate. 535 536 This operation occurs in-place without copying the original list. 537 538 Example 539 ------- 540 ```py 541 vec = Vec([1, 2, 3]) 542 vec.retain(lambda elem: elem > 1) 543 544 assert vec == [2, 3] 545 ``` 546 547 The impl for this method is very simple 548 ```py 549 for idx, e in enumerate(vec): 550 if not f(e): 551 del vec[idx] 552 ``` 553 """ 554 if not self._ptr: 555 return 556 557 idx = 0 558 while idx < len(self._ptr): 559 if not f(self._ptr[idx]): 560 del self._ptr[idx] 561 else: 562 idx += 1
Retains only the elements specified by the predicate.
This operation occurs in-place without copying the original list.
Example
vec = Vec([1, 2, 3])
vec.retain(lambda elem: elem > 1)
assert vec == [2, 3]
The impl for this method is very simple
for idx, e in enumerate(vec):
if not f(e):
del vec[idx]
564 def swap_remove(self, item: T) -> T: 565 """Remove the first appearance of `item` from this vector and return it. 566 567 Raises 568 ------ 569 * `ValueError`: if `item` is not in this vector. 570 * `MemoryError`: if this vector hasn't allocated, Aka nothing has been pushed to it. 571 572 Example 573 ------- 574 ```py 575 vec = Vec(('a', 'b', 'c')) 576 element = vec.remove('a') 577 assert vec == ['b', 'c'] and element == 'a' 578 ``` 579 """ 580 if self._ptr is None: 581 raise MemoryError("Vec is unallocated.") from None 582 583 return self._ptr.pop(self.index(item))
Remove the first appearance of item from this vector and return it.
Raises
*
ValueError(ifitemis not in this vector.):*
MemoryError(if this vector hasn't allocated, Aka nothing has been pushed to it.):
Example
vec = Vec(('a', 'b', 'c'))
element = vec.remove('a')
assert vec == ['b', 'c'] and element == 'a'
585 def fill(self, value: T) -> None: 586 """Fill `self` with the given `value`. 587 588 Nothing happens if the vec is empty or unallocated. 589 590 Example 591 ```py 592 a = Vec([0, 1, 2, 3]) 593 a.fill(0) 594 assert a == [0, 0, 0, 0] 595 ``` 596 """ 597 if not self._ptr: 598 return 599 600 for n, _ in enumerate(self): 601 self[n] = value
Fill self with the given value.
Nothing happens if the vec is empty or unallocated.
Example
a = Vec([0, 1, 2, 3])
a.fill(0)
assert a == [0, 0, 0, 0]
603 def push(self, item: T) -> None: 604 """Push an element at the end of the vector. 605 606 Example 607 ------- 608 ```py 609 vec = Vec() 610 vec.push(1) 611 612 assert vec == [1] 613 ``` 614 """ 615 if self._capacity is not None: 616 self.push_within_capacity(item) 617 return 618 619 if self._ptr is None: 620 self._ptr = [] 621 622 self._ptr.append(item)
Push an element at the end of the vector.
Example
vec = Vec()
vec.push(1)
assert vec == [1]
624 def push_within_capacity(self, x: T) -> Result[None, T]: 625 """Appends an element if there is sufficient spare capacity, otherwise an error is returned with the element. 626 627 Example 628 ------- 629 ```py 630 vec: Vec[int] = Vec.with_capacity(3) 631 for i in range(3): 632 match vec.push_within_capacity(i): 633 case Ok(_): 634 print("All good.") 635 case Err(elem): 636 print("Reached max cap :< can't push", elem) 637 ``` 638 639 Or you can also just call `Vec.push` and it will push if there's is sufficient capacity. 640 ```py 641 vec: Vec[int] = Vec.with_capacity(3) 642 643 vec.extend((1, 2, 3)) 644 vec.push(4) 645 646 assert vec.len() == 3 647 ``` 648 """ 649 if self._ptr is None: 650 self._ptr = [] 651 652 if self.len() == self._capacity: 653 return _result.Err(x) 654 655 self._ptr.append(x) 656 return _result.Ok(None)
Appends an element if there is sufficient spare capacity, otherwise an error is returned with the element.
Example
vec: Vec[int] = Vec.with_capacity(3)
for i in range(3):
match vec.push_within_capacity(i):
case Ok(_):
print("All good.")
case Err(elem):
print("Reached max cap :< can't push", elem)
Or you can also just call Vec.push and it will push if there's is sufficient capacity.
vec: Vec[int] = Vec.with_capacity(3)
vec.extend((1, 2, 3))
vec.push(4)
assert vec.len() == 3
658 def reserve(self, additional: int) -> None: 659 """Reserves capacity for at least additional more elements to be inserted in the given Vec<T>. 660 661 Example 662 ------- 663 ```py 664 vec = Vec.with_capacity(3) 665 is_vip = random.choice((True, False)) 666 667 for i in range(4): 668 match vec.push_within_capacity(i): 669 case Ok(_): 670 print("All good") 671 case Err(person): 672 # If the person is a VIP, then reserve for one more. 673 if is_vip: 674 vec.reserve(1) 675 continue 676 677 # is_vip was false. 678 print("Can't reserve for non-VIP members...", person) 679 break 680 ``` 681 """ 682 if self._capacity is not None: 683 self._capacity += additional
Reserves capacity for at least additional more elements to be inserted in the given Vec
Example
vec = Vec.with_capacity(3)
is_vip = random.choice((True, False))
for i in range(4):
match vec.push_within_capacity(i):
case Ok(_):
print("All good")
case Err(person):
# If the person is a VIP, then reserve for one more.
if is_vip:
vec.reserve(1)
continue
# is_vip was false.
print("Can't reserve for non-VIP members...", person)
break
685 def shrink_to_fit(self) -> None: 686 """Shrink the capacity of this `Vec` to match its length. 687 688 If `self` is initialized with no capacity, This is a `NOP`. 689 690 Example 691 ------- 692 ```py 693 s = Vec([1, 2, 3, 4]) 694 695 s.reserve(100) 696 s.shrink_to_fit() 697 assert s.capacity() == 4 698 ``` 699 """ 700 if self._capacity is None: 701 return 702 703 # The capacity is never less than the length. 704 self._capacity = min(self.__len__(), self._capacity)
Shrink the capacity of this Vec to match its length.
If self is initialized with no capacity, This is a NOP.
Example
s = Vec([1, 2, 3, 4])
s.reserve(100)
s.shrink_to_fit()
assert s.capacity() == 4
706 def shrink_to(self, min_capacity: int) -> None: 707 """Shrink the capacity of this `Vec` to a minimum specified capacity. 708 709 If `self` is initialized with no capacity or the current capacity is less than the lower limit, 710 This is a `NOP`. 711 712 Example 713 ------- 714 ```py 715 vec = Vec.with_capacity(10) 716 vec.extend([1, 2, 3]) 717 assert vec.capacity() >= 10 718 vec.shrink_to(4) 719 assert vec.capacity() >= 4 720 vec.shrink_to(0) 721 ``` 722 """ 723 if self._capacity is None or self._capacity <= min_capacity: 724 return 725 726 # Ensure the capacity is not reduced below the current length of the vector. 727 self._capacity = max(self.__len__(), min_capacity)
Shrink the capacity of this Vec to a minimum specified capacity.
If self is initialized with no capacity or the current capacity is less than the lower limit,
This is a NOP.
Example
vec = Vec.with_capacity(10)
vec.extend([1, 2, 3])
assert vec.capacity() >= 10
vec.shrink_to(4)
assert vec.capacity() >= 4
vec.shrink_to(0)
737 def get(self, index: int) -> _option.Option[T]: 738 """Get the item at the given index, or `Some[None]` if its out of bounds. 739 740 Example 741 ------- 742 ```py 743 vec = Vec((1, 2, 3)) 744 vec.get(0) == Some(1) 745 vec.get(3) == Some(None) 746 ``` 747 """ 748 try: 749 return _option.Some(self[index]) 750 except IndexError: 751 return _option.NOTHING
Get the item at the given index, or Some[None] if its out of bounds.
Example
vec = Vec((1, 2, 3))
vec.get(0) == Some(1)
vec.get(3) == Some(None)
753 def insert(self, index: int, value: T) -> None: 754 """Insert an element at the position `index`. 755 756 Example 757 -------- 758 ```py 759 vec = Vec((2, 3)) 760 vec.insert(0, 1) 761 assert vec == [1, 2, 3] 762 ``` 763 """ 764 self.__setitem__(index, value)
Insert an element at the position index.
Example
vec = Vec((2, 3))
vec.insert(0, 1)
assert vec == [1, 2, 3]
766 def pop(self, index: int = -1) -> _option.Option[T]: 767 """Removes the last element from a vector and returns it, or `None` if it is empty. 768 769 Example 770 ------- 771 ```py 772 vec = Vec((1, 2, 3)) 773 assert vec.pop() == Some(3) 774 assert vec == [1, 2] 775 ``` 776 """ 777 if not self._ptr: 778 return _option.NOTHING 779 780 return _option.Some(self._ptr.pop(index))
Removes the last element from a vector and returns it, or None if it is empty.
Example
vec = Vec((1, 2, 3))
assert vec.pop() == Some(3)
assert vec == [1, 2]
782 def pop_if(self, pred: collections.Callable[[T], bool]) -> _option.Option[T]: 783 """Removes the last element from a vector and returns it if `f` returns `True`, 784 or `None` if it is empty. 785 786 Example 787 ------- 788 ```py 789 vec = Vec((1, 2, 3)) 790 assert vec.pop_if(lambda num: num * 2 == 6) == Some(3) 791 assert vec == [1, 2] 792 ``` 793 """ 794 if not self._ptr: 795 return _option.NOTHING 796 797 if pred(self[-1]): 798 return self.pop() 799 800 return _option.NOTHING
Removes the last element from a vector and returns it if f returns True,
or None if it is empty.
Example
vec = Vec((1, 2, 3))
assert vec.pop_if(lambda num: num * 2 == 6) == Some(3)
assert vec == [1, 2]
802 def dedup(self) -> None: 803 """Removes consecutive repeated elements in the vector according to their `__eq__` 804 implementation. 805 806 Example 807 ------- 808 ```py 809 vec = Vec([1, 2, 2, 3, 2]) 810 vec.dedup() 811 assert vec == [1, 2, 3, 2] 812 """ 813 self.dedup_by(lambda a, b: a == b)
Removes consecutive repeated elements in the vector according to their __eq__
implementation.
Example
```py vec = Vec([1, 2, 2, 3, 2]) vec.dedup() assert vec == [1, 2, 3, 2]
815 def dedup_by(self, same_bucket: collections.Callable[[T, T], bool]) -> None: 816 """Removes all but the first of consecutive elements in the vector satisfying a given equality. 817 818 Example 819 ------- 820 ```py 821 vec = Vec(["foo", "bar", "Bar", "baz", "bar"]) 822 vec.dedup_by(lambda a, b: a.lower() == b.lower()) 823 assert vec == ["foo", "bar", "baz", "bar"] 824 ``` 825 826 Only remove consecutive duplicates. 827 ```py 828 vec = Vec([1, 2, 2, 3, 4, 1]) 829 vec.dedup_by(lambda a, b: a == b) 830 # The final 1 is not adjacent to the first 1, so it is not removed. 831 assert vec == [1, 2, 3, 4, 1] 832 ``` 833 """ 834 835 if not self._ptr or (len_ := len(self._ptr)) <= 1: 836 return 837 838 idx = 1 839 while idx < len_: 840 if same_bucket(self._ptr[idx], self._ptr[idx - 1]): 841 del self._ptr[idx] 842 len_ -= 1 843 else: 844 idx += 1
Removes all but the first of consecutive elements in the vector satisfying a given equality.
Example
vec = Vec(["foo", "bar", "Bar", "baz", "bar"])
vec.dedup_by(lambda a, b: a.lower() == b.lower())
assert vec == ["foo", "bar", "baz", "bar"]
Only remove consecutive duplicates.
vec = Vec([1, 2, 2, 3, 4, 1])
vec.dedup_by(lambda a, b: a == b)
# The final 1 is not adjacent to the first 1, so it is not removed.
assert vec == [1, 2, 3, 4, 1]
846 def remove(self, item: T) -> None: 847 """Remove the first appearance of `item` from this vector. 848 849 Example 850 ------- 851 ```py 852 vec = Vec(('a', 'b', 'c')) 853 vec.remove('a') 854 assert vec == ['b', 'c'] 855 ``` 856 """ 857 if not self._ptr: 858 return 859 860 self._ptr.remove(item)
Remove the first appearance of item from this vector.
Example
vec = Vec(('a', 'b', 'c'))
vec.remove('a')
assert vec == ['b', 'c']
862 def extend(self, iterable: collections.Iterable[T]) -> None: 863 """Extend this vector from another iterable. 864 865 Example 866 ------- 867 ```py 868 vec = Vec((1, 2, 3)) 869 vec.extend((4, 5, 6)) 870 871 assert vec == [1, 2, 3, 4, 5, 6] 872 ``` 873 """ 874 if self._ptr is None: 875 self._ptr = [] 876 877 self._ptr.extend(iterable)
Extend this vector from another iterable.
Example
vec = Vec((1, 2, 3))
vec.extend((4, 5, 6))
assert vec == [1, 2, 3, 4, 5, 6]
879 def copy(self) -> Vec[T]: 880 """Copy all elements of `self` into a new vector. 881 882 Example 883 ------- 884 ```py 885 original = Vec((1,2,3)) 886 copy = original.copy() 887 copy.push(4) 888 889 print(original) # [1, 2, 3] 890 ``` 891 """ 892 return Vec(self._ptr[:]) if self._ptr else Vec()
Copy all elements of self into a new vector.
Example
original = Vec((1,2,3))
copy = original.copy()
copy.push(4)
print(original) # [1, 2, 3]
894 def clear(self) -> None: 895 """Clear all elements of this vector. 896 897 Example 898 ------- 899 ```py 900 vec = Vec((1,2,3)) 901 vec.clear() 902 assert vec.len() == 0 903 ``` 904 """ 905 if not self._ptr: 906 return 907 908 self._ptr.clear()
Clear all elements of this vector.
Example
vec = Vec((1,2,3))
vec.clear()
assert vec.len() == 0
910 def sort( 911 self, 912 *, 913 key: collections.Callable[[T], SupportsRichComparison] | None = None, 914 reverse: bool = False, 915 ) -> None: 916 """This method sorts the list in place, using only < comparisons between items. 917 918 Example 919 ------- 920 ```py 921 vec = Vec((2, 1, 3)) 922 vec.sort() 923 assert vec == [1, 2, 3] 924 ``` 925 """ 926 if not self._ptr: 927 return 928 929 # key can be `None` here just fine, idk why pyright is complaining. 930 self._ptr.sort(key=key, reverse=reverse) # pyright: ignore
This method sorts the list in place, using only < comparisons between items.
Example
vec = Vec((2, 1, 3))
vec.sort()
assert vec == [1, 2, 3]
932 def index( 933 self, item: T, start: typing.SupportsIndex = 0, end: int = _sys.maxsize 934 ) -> int: 935 # << Official documentation >> 936 """Return zero-based index in the vec of the first item whose value is equal to `item`. 937 Raises a ValueError if there is no such item. 938 939 Example 940 ------- 941 ```py 942 vec = Vec((1, 2, 3)) 943 assert vec.index(2) == 1 944 ``` 945 """ 946 if self._ptr is None: 947 raise ValueError from None 948 949 return self._ptr.index(item, start, end)
Return zero-based index in the vec of the first item whose value is equal to item.
Raises a ValueError if there is no such item.
Example
vec = Vec((1, 2, 3))
assert vec.index(2) == 1
951 def count(self, item: T) -> int: 952 """Return the number of occurrences of `item` in the vec. 953 954 `0` is returned if the vector is empty or hasn't been initialized, as well if them item not found. 955 956 Example 957 -------- 958 ```py 959 vec = Vec((1, 2, 3, 3)) 960 assert vec.count(3) == 2 961 ``` 962 """ 963 if self._ptr is None: 964 return 0 965 966 return self._ptr.count(item)
Return the number of occurrences of item in the vec.
0 is returned if the vector is empty or hasn't been initialized, as well if them item not found.
Example
vec = Vec((1, 2, 3, 3))
assert vec.count(3) == 2