Module collections/array_list

collections/array_list
Stability: stable — changes additively from here.

Dynamic array (vector) with amortized O(1) push and O(1) indexed access.

Stability

stable — every breaking flip this type owed Rust shipped in v0.2.28: push is infallible with try_push beside it (D9), iter() yields POINTERS while into_iter() yields values (D14), and sort is the stable merge with sort_unstable as the heapsort (D17). The P1 battery is complete and test-covered, and plans/archive/STD_API_STABILIZATION.md §4 lists nothing still open against this module, so further work here is additive.

Types

ArrayList type-function
fn(T : Type) -> Type

Generic growable array similar to Rust's Vec<T>. Heap-allocated with automatic resizing and reference-counted cleanup.

Type Parameters

NameTypeNotes
TTypecomptime

Trait Implementations

impl(generic(T : Type), ArrayList(T), ...)
len : (fn(self : &Self) -> usize)

Number of elements. O(1) — the length is stored, never counted.

Returns: usize

is_empty : (fn(self : &Self) -> bool)

True when the list holds no elements — len() == 0.

Returns: bool

capacity : (fn(self : &Self) -> usize)

Elements the current buffer can hold before push has to reallocate.

SIZE_MAX for a zero-sized element type, which never grows — see _zst_anchor. Rust's Vec::capacity reports usize::MAX for the same reason.

Returns: usize

_cap : (fn(self : &Self) -> usize)

Returns: usize

_owned : (fn(self : &Self) -> bool)

Returns: bool

_set_cap : (fn(self : &mut Self, cap : usize) -> unit)

Returns: unit

_buf_resize : (fn(self : &mut Self, bytes : usize) -> ?*void)

Returns: ?*void

_buf_free : (fn(self : &Self, p : &*T) -> unit)

Returns: unit

allocator : (fn(self : &Self) -> Option(Allocator))

The allocator the buffer belongs to: the one given to new_in / with_capacity_in, or .None for a list on the global allocator.

Returns: Option(Allocator)

ptr : (fn(self : &Self) -> ?*T)

Raw pointer to the element buffer, or .None when nothing is allocated yet — Rust's Vec::as_ptr, minus the dangling-pointer guarantee.

The pointer is only valid until the next reallocation (push past capacity, reserve, ensure_total_capacity, shrink_to_fit), and it borrows: it does not keep the list alive.

Returns: ?*T

spare_capacity : (fn(self : &mut Self) -> Option(*T))

A pointer to the first uninitialized slot, ptr() + len(): the start of the capacity() - len() slots a reader fills before assume_init commits them. .None when nothing is allocated yet (reserve first).

The result is a raw pointer VALUE, so the safe-mode gate keeps it out of safe code exactly as it keeps out ptr(). Claiming memory initialized needs this token, which safe code cannot obtain (ATS's view of the region; issues/fixed/safe-code-reaches-freed-memory-through-arraylist-set-len.md). A struct that merely CONTAINS a pointer, such as RawSlice(T), would not be gated: safe code may hold String.raw_bytes(). The pointer is valid until the next reallocation, like ptr().

Returns: Option(*T)

assume_init : ( fn( self : &mut Self, n : usize, spare : &*T, requires(n <= (self.capacity() - self.len())), ensures(self.len() == (old(self.len()) + n)), assumed() ) -> unit )

Commit the first n spare slots (spare is the token from spare_capacity) as live elements: the length grows by n. Nothing is initialized or dropped; the caller has written those n slots. PANICS unless spare is this list's current end and n <= capacity() - len().

Returns: unit

new : (fn(ensures(r.len() == usize(0)), assumed()) -> (r : Self))

Empty list on the global allocator. Allocates nothing — the first push buys the buffer (four elements), as Rust's Vec::new does. new_in(a) places the buffer in a instead.

Returns: (r : Self)

slice_copy : (fn(self : &Self, r : Range(usize)) -> Self)

Owned copy of the elements in [r.start, r.end) — JS-style range slicing with value semantics (plans/archive/SLICE_REWORK.md: list(a..b) lowers to this).

The end is CLAMPED to the length rather than checked, so an over-long range yields a short list instead of panicking; slice is the checked, Result-returning spelling. Elements are copied (dup'd for a refcounted T), so the result is independent of the source.

Returns: Self

slice_copy_inclusive : (fn(self : &Self, r : RangeInclusive(usize)) -> Self)

Inclusive-range companion of slice_copy (list(a..=b)).

Returns: Self

from : (fn(generic(N : usize), sink(arr) : Array(T, N)) -> Self)

Consuming constructor from a fixed-size array — Rust's Vec::from([T; N]): ArrayList(i32).from([i32(1), i32(2), i32(3)]).

The array is taken by sink, so the caller's binding ends at the call and its elements are now the list's. A caller that keeps the array passes a copy: ArrayList(T).from(arr.clone()). N comes from the array's type, so the exact capacity is reserved up front and no growth happens.

Returns: Self

with_capacity : (fn(cap : usize, ensures(r.len() == usize(0)), assumed()) -> (r : Self))

Empty list whose buffer already holds cap elements, on the global allocator — Rust's Vec::with_capacity.

PANICS on "capacity overflow" when sizeof(T) * cap would wrap (Rust panics with the same message), and on allocation failure. A zero-sized element type takes the one-byte anchor buffer instead of allocating cap of nothing.

Returns: (r : Self)

new_in : (fn(alloc : Allocator) -> Self)

Empty list whose buffer lives in alloc — Rust's Vec::new_in.

Every growth, shrink and the final release go through alloc, wherever and on whichever thread the last reference dies. Unlike new, this takes one allocation right away: a block holding only alloc's 16-byte owner prefix, which is how the list remembers its allocator (the list object itself stays the size of a plain one). PANICS when that allocation fails.

Returns: Self

with_capacity_in : (fn(alloc : Allocator, cap : usize) -> Self)

Empty list with room for cap elements, its buffer in alloc — Rust's Vec::with_capacity_in. PANICS on capacity overflow and on allocation failure, like with_capacity.

Returns: Self

_zst_anchor : (fn() -> Self)

The one buffer an ArrayList of a ZERO-SIZED element type ever has.

sizeof(T) == 0 (unit, an all-unit aggregate, Array(unit, N)) means the elements occupy no bytes: a store writes nothing, a read reads nothing, and the byte size of every buffer is 0. Rust's Vec<()> never allocates and reports capacity() == usize::MAX. Yo cannot conjure a non-null dangling pointer, so the stand-in is ONE one-byte block, allocated once and never resized: the capacity is the largest untagged value (capacity() reports SIZE_MAX), so push never reaches the grow path, and shrink_to_fit is a no-op. Going through the allocator with sizeof(T) * cap == 0 instead would malloc(0) and then realloc(p, 0) — which frees p and returns NULL on glibc and the Windows CRT — and the list would report "allocation failed" on its second growth.

Returns: Self

_zst_anchor_buf : (fn() -> *T)

Returns: *T

try_push : (fn(self : &mut Self, value : T) -> Result(unit, ArrayListError))

Append an element, reporting allocation failure as .Err(.AllocError(.OutOfMemory)) instead of panicking.

The allocator-aware form (D9); push is the one to reach for. Amortized O(1) — the buffer doubles (4 elements first), so a growth INVALIDATES every pointer previously handed out by ptr(), iter() or the Index impl.

Returns: Result(unit, ArrayListError)

push : ( fn( self : &mut Self, value : T, // The element clause is proof-only (it quantifies), so it is never // spliced as a runtime assert; the verifier uses it to prove what a // loop of pushes built. ensures( self.len() == (old(self.len()) + usize(1)), forall(k : usize, (k < self.len()) ==> (self(k) == cond((k == old(self.len())) => value, true => old(self)(k)))) ), assumed() ) -> unit )

Append an element — amortized O(1).

PANICS on allocation failure: Rust's Vec::push aborts, and so do this list's own ensure_total_capacity / with_capacity. Before D9 this returned a Result that every one of its callers discarded, usually via a throwaway _p := binding — a Result nobody checks is strictly worse than a panic, because it reads as if the failure were handled. Use try_push when the caller genuinely handles OOM.

A growth reallocates, so any pointer into the buffer (ptr(), iter(), self(i)) is invalid afterwards.

Returns: unit

pop : (fn(self : &mut Self) -> Option(T))

Remove and return the last element, or .None when empty — O(1), and the capacity is kept.

Returns: Option(T)

get : (fn(self : &Self, index : usize) -> Option(T))

Copy of the element at index, or .None when index >= len().

The bounds-checked reader. self(index) (the Index impl) reads the element in place and panics out of range instead; get_cloned(i) clones an element that is not copied implicitly, and with(i, body) writes one in place (plans/VALUES_BY_DEFAULT.md decision 20).

Returns: Option(T)

shrink_to_fit : (fn(self : &mut Self) -> Result(unit, ArrayListError))

Give the unused tail of the buffer back to the allocator so that capacity() == len() — Rust's Vec::shrink_to_fit.

Reallocates (an empty list frees its buffer outright), so every pointer into the buffer is invalid afterwards and the next push grows again. .Err(.AllocError(.OutOfMemory)) when the shrinking realloc fails — the list is left untouched and usable. A zero-sized element type is a no-op: its anchor buffer cannot shrink.

Returns: Result(unit, ArrayListError)

_free_elements : (fn(self : &mut Self) -> unit)

Returns: unit

drain : ( fn( self : &mut Self, r : Range(usize), requires(r.start <= r.end, r.end <= self.len()), ensures(self.len() == (old(self.len()) - (r.end - r.start))), assumed() ) -> Self )

Remove the elements in [r.start, r.end) and return them, in order, as a fresh list — Rust's Vec::drain, collected eagerly rather than lazily (Yo has no borrowing iterator to hold the source open).

O(n): the tail shifts left to close the gap. PANICS on an inverted range or an end past the length — the old remove(start, count) silently clamped the count, which hid caller bugs.

Returns: Self

insert : ( fn( self : &mut Self, idx : usize, value : T, requires(idx <= self.len()), ensures(self.len() == (old(self.len()) + usize(1))), assumed() ) -> unit )

Insert value at idx, shifting the tail right — O(n). idx == len appends, as in Rust.

Returns: unit

append : (fn(self : &mut Self, other : &mut Self) -> unit)

Move every element of other onto the end of self, leaving other EMPTY — Rust's append. extend copies instead.

Returns: unit

first : (fn(self : &Self) -> Option(T))

First element, or .None when empty.

Returns: Option(T)

last : (fn(self : &Self) -> Option(T))

Last element, or .None when empty.

Returns: Option(T)

reserve : (fn(self : &mut Self, additional : usize) -> unit)

Reserve room for additional MORE elements.

Rust's spelling. ensure_total_capacity takes a TOTAL, which is the same call with a different meaning and an easy one to get wrong at a call site.

Returns: unit

with : (fn(generic(R : Type), self : &mut Self, index : usize, body : &Impl(Fn(v : &mut T) -> R)) -> R)

Run body on the element at index, borrowed in place, and return its result — decision 20's non-copying access (plans/VALUES_BY_DEFAULT.md): the element is neither copied out nor written back. Panics when index >= len().

{ ArrayList } :: import("std/collections/array_list");
{ String } :: import("std/string");
(mut(names) : ArrayList(String)) = ArrayList(String).new();
names.push(`ada`);
n := names.with(usize(0), s => {
  s.push_str(" lovelace");
  s.len()
});
assert((n == usize(12)) && (names(usize(0)) == `ada lovelace`), "written in place");

Returns: R

take : (fn(self : &mut Self, index : usize, where(T <: Default)) -> T)

Move the element at index out and leave T's default in its slot — std/mem's take(&mut xs(i)). Nothing is copied, so a move-only T works. Panics when index >= len().

{ ArrayList } :: import("std/collections/array_list");
{ String } :: import("std/string");
(mut(names) : ArrayList(String)) = ArrayList(String).new();
names.push(`ada`);
s := names.take(usize(0));
assert((s == `ada`) && (names(usize(0)) == ``), "the slot keeps the default");

Returns: T

swap : ( fn( self : &mut Self, i : usize, j : usize, requires(i < self.len(), j < self.len()), ensures(self.len() == old(self.len())), assumed() ) -> unit )

Exchange the elements at i and j.

Moves the raw slots, like reverse — no dup/drop, so this is RC-neutral however the element type is refcounted.

Returns: unit

swap_remove : ( fn( self : &mut Self, idx : usize, requires(idx < self.len()), ensures(self.len() == (old(self.len()) - usize(1))), assumed() ) -> (r : T) )

Remove the element at idx and return it, moving the LAST element into the hole — O(1), and it does not preserve order. Rust's swap_remove.

Returns: (r : T)

truncate : (fn(self : &mut Self, new_len : usize) -> unit)

Shorten to new_len, dropping the elements past it. Longer new_len is a no-op, as in Rust.

Returns: unit

resize : (fn(self : &mut Self, new_len : usize, value : &T) -> unit)

Resize to exactly new_len, dropping the tail when shrinking and appending copies of value when growing. Rust's resize.

Distinct from resize_with_byte, which memsets raw storage and is only meaningful for a plain-old-data element type.

Returns: unit

fill : (fn(self : &mut Self, value : &T) -> unit)

Overwrite every element with value, keeping the length. Rust's fill.

Returns: unit

split_off : (fn(self : &mut Self, at : usize) -> Self)

Split off [at, len) into a new list, leaving [0, at) here.

Returns: Self

remove : ( fn( self : &mut Self, idx : usize, requires(idx < self.len()), ensures(self.len() == (old(self.len()) - usize(1))), assumed() ) -> (r : T) )

Remove the element at idx and return it, shifting the tail left — O(n), order preserved. Rust's Vec::remove.

PANICS when idx >= len(). swap_remove is the O(1) alternative when order does not matter.

Returns: (r : T)

slice : (fn(self : &Self, start : usize, end : usize) -> Result(Self, ArrayListError))

Owned copy of [start, end), or an .IndexOutOfBounds error — the CHECKED counterpart of slice_copy, which clamps instead.

An inverted range reports .IndexOutOfBounds(index : start, length : end). O(end - start), one allocation of the exact size.

Returns: Result(Self, ArrayListError)

ensure_total_capacity : (fn(self : &mut Self, min_cap : usize) -> unit)

Grow the buffer so it holds at least min_cap elements in TOTAL, doubling as it goes; a request under the current capacity does nothing.

reserve(additional) is the Rust spelling and takes a COUNT TO ADD — the same call with a different meaning, and the easy one to get right at a call site. PANICS on capacity overflow and on allocation failure (try_push is the only allocator-aware entry point). Reallocates, so pointers into the buffer do not survive it.

Returns: unit

extend_from_ptr : (fn(self : &mut Self, src : &*T, count : usize) -> unit)

Append count elements from a raw buffer with one memcpy.

The caller guarantees src holds count initialized, correctly aligned Ts that do not alias this list's buffer. The bytes are copied WITHOUT per-element dup, so for a refcounted T this MOVES the source elements: the caller must not also release them. Reaching for it on a plain-data element type is the point — that is where it beats a push loop.

Returns: unit

clear : (fn(self : &mut Self) -> unit)

Drop every element and set the length to 0, KEEPING the capacity — Rust's Vec::clear. Use shrink_to_fit afterwards to release the buffer too.

Returns: unit

fill_with_byte : (fn(self : &mut Self, byte_val : int) -> unit)

Overwrite the live len() elements with a repeated byte via memset — the fast way to zero a bool / integer list.

Writes over the elements without dropping them, so it is only sound for a plain-data T: on a refcounted element type it strands every handle it overwrites. fill(value) is the type-safe form.

Returns: unit

resize_with_byte : (fn(self : &mut Self, new_len : usize, byte_val : int) -> unit)

Set the length to exactly new_len, memsetting any newly exposed slots to a repeated byte.

Shrinking does NOT run destructors and growing does not construct anything, so — like fill_with_byte — this is for a plain-data T only; resize(new_len, value) is the type-safe form. Growing may reallocate and can panic on allocation failure.

Returns: unit

impl(generic(T : Type), ArrayList(T), Index(usize)(...))
Output : T

The output type is the element type T.

index : (fn(self : &Self, idx : usize) -> &Self.Output)

The element at idx, read (a read projection). Panics if the index is out of bounds.

Parameters

NameTypeNotes
idxusize

Returns: &Self.Output

impl(generic(T : Type), ArrayList(T), IndexMut(usize)(...))
Output : T

The output type is the element type T.

index_mut : (fn(self : &mut Self, idx : usize) -> &mut Self.Output)

The element at idx, written (a mutable projection). Panics if the index is out of bounds.

Parameters

NameTypeNotes
idxusize

Returns: &mut Self.Output

impl(generic(T : Type), ArrayList(T), IndexUnchecked(...))
Output : T

The output type is the element type T, the same as Index(usize)'s.

index_unchecked : (fn(self : &Self, idx : usize) -> *Self.Output)

index minus the length test. Codegen calls this only at a subscript the verifier proved in bounds (plans/backlog/SAFE_MODE_5B_CONTAINER_BOUNDS_ELISION.md).

Parameters

NameTypeNotes
idxusize

Returns: *Self.Output

impl(generic(T : Type), ArrayList(T), IndexUncheckedMut(...))
Output : T

The output type is the element type T, the same as IndexMut(usize)'s.

index_unchecked_mut : (fn(self : &mut Self, idx : usize) -> *Self.Output)

index_mut minus the length test, on the same terms as index_unchecked.

Parameters

NameTypeNotes
idxusize

Returns: *Self.Output

impl(generic(T : Type), ArrayList(T), Drop(...))
drop : (fn(self : &mut Self) -> unit)

Drops every live element and frees the buffer. Runs when the last reference to the list goes away, not at the end of the binding's scope.

Returns: unit

impl(generic(T : Type), ArrayList(T), Trace(...))
trace : (fn(self : &Self, tracer : GcTracer) -> unit)

Cycle-GC tracing. The elements live in a malloc'd buffer the compiler's auto-derived field walk cannot reach, so trace each element's buffer slot. tracer.visit takes the slot POINTER and reads it WITHOUT touching the element's reference count — a by-value managed handle would be dup'd then dropped, freeing a live element mid-collection.

Parameters

NameTypeNotes
tracerGcTracer

Returns: unit

impl(generic(T : Type), ArrayList(T), IntoIterator(...))
Item : T
IntoIter : ArrayListIter(T)
into_iter : (fn(self : Self) -> ArrayListIter(T))

Returns: ArrayListIter(T)

impl(generic(T : Type), ArrayList(T), ...)
iter : (fn(self : &Self) -> ArrayListIterPtr(T))

Raw walk over the buffer: yields a *(T) into the list's buffer and leaves the list intact — for(list.iter(), ptr => ...), where into_iter consumes the list and yields values (D14; the iter / into_iter split every other std collection already had). Safe code reads elements with for(&list, x => ...); this is the pragma(Pragma.AllowUnsafe) form (decision 39).

The iterator holds the buffer pointer and the current length, not the list (B7b), so the list must outlive the walk, and must not grow or shrink during it: a reallocation invalidates the pointers already yielded.

Returns: ArrayListIterPtr(T)

indices : (fn(self : &Self) -> Range(usize))

The positions 0 .. len(), a Range(usize) that holds no handle to the list: the index cursor of decision 39 (plans/VALUES_BY_DEFAULT.md). Read each element through the list, xs(i), so every step re-derives it from the current buffer: a push during the walk is seen at the next step, and an index past a shrink is the out-of-bounds panic, never a read of a freed buffer. The range is fixed when it is made.

Returns: Range(usize)

impl(generic(T : Type), ArrayList(T), BorrowedWalk(...))
WalkCursor : usize
WalkElem : T
walk_start : (fn(self : &Self) -> usize)

The first position (equal to the end for an empty collection).

Returns: usize

walk_valid : (fn(self : &Self, cur : &usize) -> bool)

Whether cur names an element.

Parameters

NameTypeNotes
cur&usize

Returns: bool

walk_ref : (fn(self : &Self, cur : &usize) -> &T)

The element at cur, read in place (a read projection). Panics if cur names no element.

Parameters

NameTypeNotes
cur&usize

Returns: &T

walk_next : (fn(self : &Self, cur : &usize) -> usize)

The position after cur.

Parameters

NameTypeNotes
cur&usize

Returns: usize

impl(generic(T : Type), ArrayList(T), BorrowedWalkMut(...))
walk_elem : (fn(self : &mut Self, cur : &usize) -> &mut T)

The element at cur, written in place (a mutable projection). Panics if cur names no element.

Parameters

NameTypeNotes
cur&usize

Returns: &mut T

impl(generic(T : Type), where(T <: Eq(T)), ArrayList(T), ...)
dedup : (fn(self : &mut Self) -> unit)

Remove CONSECUTIVE duplicates, keeping the first of each run — Rust's dedup. Only adjacent equals collapse, so [1,2,1] is unchanged; sort first if you want set semantics.

Returns: unit

starts_with : (fn(self : &Self, prefix : &Self) -> bool)

Whether self begins with prefix — Rust's starts_with.

Returns: bool

ends_with : (fn(self : &Self, suffix : &Self) -> bool)

Whether self ends with suffix — Rust's ends_with.

Returns: bool

contains : (fn(self : &Self, value : &T) -> bool)

Whether any element equals value — a linear scan, O(n), stopping at the first match. Rust's Vec::contains.

Returns: bool

index_of : (fn(self : &Self, value : &T) -> Option(usize))

Index of the FIRST element equal to value, or .None — a linear scan, O(n). Rust spells this iter().position(...); on a sorted list reach for binary_search instead.

Returns: Option(usize)

impl(generic(T : Type), ArrayList(T), ...)
reverse : (fn(self : &mut Self) -> unit)

Reverse the elements in place, O(n).

Exchanges raw slots bitwise, like swap, so no element is copied or dropped: RC-neutral however T is refcounted, and a move-only T reverses too.

Returns: unit

impl(generic(T : Type), where(T <: Ord(T)), ArrayList(T), ...)
sort : (fn(self : &mut Self) -> unit)

Sort ascending by Ord. STABLE (D17): equal elements keep their input order, as sort does in Rust, Python, Java and Go.

O(n log n) with one usize index array plus scratch allocated for the merge — sort_unstable is the allocation-free heapsort for when order among equals does not matter.

Returns: unit

sort_unstable : (fn(self : &mut Self) -> unit)

Sort ascending by Ord WITHOUT preserving the order of equal elements — Rust's sort_unstable. Heapsort: O(n log n) worst case, in place, no allocation, no recursion (see _heapsort_by).

Returns: unit

impl(generic(T : Type), where(T <: Eq(T)), ArrayList(T), Eq(ArrayList(T))(...))
impl(generic(T : Type), ArrayList(T), Default(...))
default : (fn() -> Self)

The default value of the type.

Returns: Self

impl(generic(T : Type), where(T <: Clone), ArrayList(T), Clone(...))
clone : (fn(self : &Self) -> Self)

Create an independent clone of self.

Returns: Self

impl(generic(T : Type), ArrayList(T), FromIterator(...))
Elem : T
from_iter_new : (fn() -> Self)

The empty collection collect starts from.

Returns: Self

from_iter_add : (fn(sink(acc) : Self, item : &T) -> Self)

Add one element to a partially-built collection and return it.

Parameters

NameTypeNotes
item&T

Returns: Self

impl(generic(T : Type), ArrayList(T), ...)
sort_by : (fn(self : &mut Self, less : &Impl(Fn(a : &T, b : &T) -> bool)) -> unit)

Sort by a caller-supplied strict "less" — less(a, b) is true when a must come before b. STABLE: equal elements keep their input order, matching Rust's sort_by. Use sort_unstable_by for the allocation-free heapsort.

Returns: unit

sort_by_key : ( fn( generic(K : Type), self : &mut Self, key : &Impl(Fn(v : &T) -> K), where(K <: Ord(K)) ) -> unit )

Sort ascending by a KEY extracted from each element — Rust's sort_by_key. Stable, like sort_by, which it delegates to.

The key type is a method-level generic(K : Type), which the clause order requires to come BEFORE self; it is inferred from the closure at the call site, so xs.sort_by_key(p => p.age) needs no annotation.

Returns: unit

binary_search_by : (fn(self : &Self, cmp : &Impl(Fn(v : &T) -> Ordering)) -> Result(usize, usize))

Binary search over a list ordered by cmp — Rust's binary_search_by.

cmp reports how each ELEMENT orders against the target (.Less when the element comes first), so searching does not require constructing a T to compare against — which is the whole reason to reach for this over binary_search. .Ok(index) of a match (any one of an equal run), or .Err(insertion_index).

Returns: Result(usize, usize)

chunks : (fn(self : Self, size : usize) -> ArrayListChunks(T))

Non-overlapping chunks of size, in order — Rust's chunks. The final chunk is SHORT when the length is not a multiple of size.

PANICS on size == 0, as Rust does. Consumes the list (D20).

Returns: ArrayListChunks(T)

windows : (fn(self : Self, size : usize) -> ArrayListWindows(T))

Overlapping windows of EXACTLY size, advancing one element at a time — Rust's windows. Yields nothing when the list is shorter than size.

PANICS on size == 0, as Rust does. Consumes the list (D20).

Returns: ArrayListWindows(T)

sort_unstable_by : (fn(self : &mut Self, less : &Impl(Fn(a : &T, b : &T) -> bool)) -> unit)

Sort by a caller-supplied strict "less" WITHOUT preserving the order of equal elements (heapsort). Rust's sort_unstable_by.

Returns: unit

retain : (fn(self : &mut Self, pred : &Impl(Fn(v : &T) -> bool)) -> unit)

Keep only the elements pred accepts, in place and in order; the rejected elements are dropped. One pass: the survivors are collected into a fresh list, clear releases every original, extend moves the survivors back — O(n) with a single allocation, and every RC step is one of the module's proven public operations (push / clear / extend). The first cut compacted through raw pointers and double-released RC elements (the Linux-ASan heap-use-after-free on PR #313's first run; local ASan is non-functional, so CI was the first to see it); the second walked backwards over drain, which was O(n²) with an allocation per rejection (issues/fixed/array-list-retain-is-quadratic.md).

Returns: unit

extend : (fn(self : &mut Self, other : ArrayList(T)) -> unit)

Append every element of other, consuming it — Rust's Vec::extend(other). extend_cloned(&other) appends clones and keeps other.

When other is the only handle to its list, the elements MOVE: one memcpy, and the emptied list is freed. While ArrayList is still a shared handle (until plans/VALUES_BY_DEFAULT.md's B8), another handle may share the list; the elements are then copied, so the other handle keeps them (lookahead D21's rule for the consuming iterators). That copy is decision 20's check, so a move-only T is E0901 here until B8.

Returns: unit

impl(generic(T : Type), where(T <: Clone), ArrayList(T), ...)
extend_cloned : (fn(self : &mut Self, other : &ArrayList(T)) -> unit)

Append a clone of every element of other, which is left as it was. Each element is cloned in place through other(i).

Returns: unit

get_cloned : (fn(self : &Self, index : usize) -> Option(T))

A clone of the element at index, or .None when index >= len() — get for an element that is not copied implicitly (decision 20). The element is cloned in place, never copied out first.

{ ArrayList } :: import("std/collections/array_list");
{ String } :: import("std/string");
(mut(names) : ArrayList(String)) = ArrayList(String).new();
names.push(`ada`);
assert(names.get_cloned(usize(0)) == .Some(`ada`), "a clone of the element");

Returns: Option(T)

first_cloned : (fn(self : &Self) -> Option(T))

A clone of the first element, or .None when empty.

Returns: Option(T)

last_cloned : (fn(self : &Self) -> Option(T))

A clone of the last element, or .None when empty.

Returns: Option(T)

impl(generic(T : Type), where(T <: Ord(T)), ArrayList(T), ...)
ArrayListError

Error variants for ArrayList operations.

Variants

VariantFieldsDescription
AllocErrorerror: AllocError

Memory allocation failed.

IndexOutOfBoundsindex: usize, length: usize

Index is out of bounds for the current length.

EmptyList

Attempted to access an element from an empty list.

Methods
clone : (ArrayListError) fn(self : &ArrayListError) -> ArrayListError

Parameters

NameTypeNotes
selfArrayListError

Returns: ArrayListError

ArrayListIter type-function
fn(T : Type) -> Type

Value iterator over an ArrayList — yields each element BY VALUE, which dups a refcounted T. This is what into_iter() (and therefore for(list, ...)) returns; iter() yields pointers instead (D14).

It OWNS the list: into_iter takes it by value (B7b). Until ArrayList is a value type that is a shared handle, so the elements are still copied out rather than moved (lookahead D21), and _length is re-read on every next: a push through another handle during a forward walk extends the walk. Double-ended: next_back takes from the far end.

Type Parameters

NameTypeNotes
TTypecomptime

Trait Implementations

impl(generic(T : Type), ArrayListIter(T), Iterator(...))
Item : T
next : (fn(self : &mut Self) -> Option(T))

Advance the iterator and return the next value, or None when exhausted.

Returns: Option(T)

impl(generic(T : Type), ArrayListIter(T), DoubleEndedIterator(...))
Item : T
next_back : (fn(self : &mut Self) -> Option(T))

Advance the iterator from the back and return the previous value, or None when the two ends have met.

Returns: Option(T)

ArrayListIterPtr type-function
fn(T : Type) -> Type

Pointer iterator over an ArrayList — yields *(T) INTO the list's own buffer (D14). This is what iter() returns; into_iter() keeps yielding values.

The elements are borrowed, not dup'd, so iterating a list of RC values costs no refcount traffic and writing through the pointer mutates the list in place. HashMapIterPtr established the shape.

A raw view (decision 39, B7b): it holds the buffer pointer and the length iter() saw, NOT the list, so it keeps nothing alive and is meant for pragma(Pragma.AllowUnsafe) code. The list must outlive the walk and keep its length: any operation that REALLOCATES the buffer (push past capacity, reserve, shrink_to_fit) invalidates every pointer, and a shrink leaves the walk reading past the live elements.

Type Parameters

NameTypeNotes
TTypecomptime

Trait Implementations

impl(generic(T : Type), ArrayListIterPtr(T), Iterator(...))
Item : *T
next : (fn(self : &mut Self) -> Option(*T))

Advance the iterator and return the next value, or None when exhausted.

Returns: Option(*T)

impl(generic(T : Type), ArrayListIterPtr(T), DoubleEndedIterator(...))
Item : *T
next_back : (fn(self : &mut Self) -> Option(*T))

Advance the iterator from the back and return the previous value, or None when the two ends have met.

Returns: Option(*T)

ArrayListChunks type-function
fn(T : Type) -> Type

Iterator over non-overlapping CHUNKS of a list.

Yo has no slice type, so each chunk is a freshly allocated ArrayList(T) COPY rather than a borrowed view — the honest rendering of Rust's chunks, whose item is a &[T]. Mutating a yielded chunk does not touch the source. The iterator owns its source: chunks takes the list by value (lookahead D20), so xs.clone().chunks(n) walks a list that is read again later.

Type Parameters

NameTypeNotes
TTypecomptime

Trait Implementations

impl(generic(T : Type), ArrayListChunks(T), Iterator(...))
Item : ArrayList(T)
next : (fn(self : &mut Self) -> Option(ArrayList(T)))

Advance the iterator and return the next value, or None when exhausted.

Returns: Option(ArrayList(T))

ArrayListWindows type-function
fn(T : Type) -> Type

Iterator over overlapping WINDOWS of a list — see ArrayListChunks for why each window is a copy.

Type Parameters

NameTypeNotes
TTypecomptime

Trait Implementations

impl(generic(T : Type), ArrayListWindows(T), Iterator(...))
Item : ArrayList(T)
next : (fn(self : &mut Self) -> Option(ArrayList(T)))

Advance the iterator and return the next value, or None when exhausted.

Returns: Option(ArrayList(T))