// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// #region type definition and intrinsics
///|
/// An `ArrayView` represents a view into a section of an array without copying the data.
/// It stores its own start offset and length when it is created, so iteration
/// over a view keeps using those bounds even if the underlying array is later
/// structurally modified.
///
/// # Example
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3, 4, 5]
/// let view = arr[1:4] // Creates a view of elements at indices 1,2,3
/// @test.assert_eq(view[0], 2)
/// @test.assert_eq(view.length(), 3)
/// }
/// ```
#builtin.valtype
type ArrayView[T]
///|
fn[T] ArrayView::buf(self : ArrayView[T]) -> UninitializedArray[T] = "%arrayview.buf"
///|
fn[T] ArrayView::start(self : ArrayView[T]) -> Int = "%arrayview.start"
///|
fn[T] ArrayView::len(self : ArrayView[T]) -> Int = "%arrayview.len"
///|
fn[T] ArrayView::make(
buf : UninitializedArray[T],
start : Int,
len : Int,
) -> ArrayView[T] = "%arrayview.make"
// #endregion
// #region methods
///|
/// Returns the length (number of elements) of an array view.
///
/// Parameters:
///
/// * `array_view` : The array view whose length is to be determined.
///
/// Returns an integer representing the number of elements in the array view.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3, 4, 5]
/// let view = arr[2:4]
/// inspect(view.length(), content="2")
/// }
/// ```
#intrinsic("%arrayview.length")
pub fn[T] ArrayView::length(self : ArrayView[T]) -> Int {
self.len()
}
///|
/// Returns whether the array view is empty.
///
/// Example:
///
/// ```mbt check
/// test {
/// let view = [1, 2, 3][:]
/// inspect(view.is_empty(), content="false")
/// let empty = [1, 2][0:0]
/// inspect(empty.is_empty(), content="true")
/// }
/// ```
pub fn[T] ArrayView::is_empty(self : ArrayView[T]) -> Bool {
self.length() == 0
}
///|
/// Return the starting index of this view in the underlying array.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [10, 20, 30]
/// let v = arr[1:]
/// inspect(v.start_offset(), content="1")
/// }
/// ```
pub fn[T] ArrayView::start_offset(self : Self[T]) -> Int {
self.start()
}
///|
/// Retrieves an element at the specified index from the array view.
///
/// Parameters:
///
/// * `self` : The array view to access.
/// * `index` : The position in the array view from which to retrieve the
/// element.
///
/// Returns the element at the specified index.
///
/// Throws a runtime error if the index is out of bounds (less than 0 or greater
/// than or equal to the length of the array view).
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3, 4, 5]
/// let view = arr[2:4]
/// inspect(view[0], content="3")
/// inspect(view[1], content="4")
/// }
/// ```
#intrinsic("%arrayview.get")
#alias("_[_]")
pub fn[T] ArrayView::at(self : ArrayView[T], index : Int) -> T {
guard index >= 0 && index < self.len() else {
index_out_of_bounds(self.len(), index)
}
self.buf().unsafe_get(self.start() + index)
}
///|
/// Retrieves an element from the array view at the specified index.
///
/// Parameters:
///
/// * `self` : The array view to retrieve the element from.
/// * `index` : The position in the array view from which to retrieve the
/// element.
///
/// Returns `Some(element)` if the index is within bounds, or `None` if the index
/// is out of bounds.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3, 4, 5]
/// let view = arr[1:4]
/// debug_inspect(view.get(0), content="Some(2)")
/// debug_inspect(view.get(1), content="Some(3)")
/// debug_inspect(view.get(2), content="Some(4)")
/// debug_inspect(view.get(5), content="None")
/// }
/// ```
pub fn[T] ArrayView::get(self : ArrayView[T], index : Int) -> T? {
let len = self.length()
guard index >= 0 && index < len else { None }
Some(self.buf().unsafe_get(self.start() + index))
}
///|
/// Returns the last element of the array view, if any.
///
/// Example:
///
/// ```mbt check
/// test {
/// let view = [1, 2, 3][:]
/// debug_inspect(view.last(), content="Some(3)")
/// let empty = [1, 2][0:0]
/// debug_inspect(empty.last(), content="None")
/// }
/// ```
pub fn[T] ArrayView::last(self : ArrayView[T]) -> T? {
let len = self.length()
if len == 0 {
None
} else {
Some(self.unsafe_get(len - 1))
}
}
///|
/// Retrieves an element from the array view at the specified index without
/// performing bounds checking.
///
/// Parameters:
///
/// * `array_view` : The array view to retrieve the element from.
/// * `index` : The position in the array view from which to retrieve the
/// element.
///
/// Returns the element at the specified index in the array view.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3, 4, 5]
/// let view = arr[1:4]
/// inspect(view.unsafe_get(1), content="3")
/// }
/// ```
#intrinsic("%arrayview.unsafe_get")
#internal(unsafe, "Panic if index is out of bounds")
#doc(hidden)
pub fn[T] ArrayView::unsafe_get(self : ArrayView[T], index : Int) -> T {
self.buf()[self.start() + index]
}
///|
/// Creates a view of a portion of the array. The view provides read-write access
/// to the underlying array without copying the elements.
///
/// Parameters:
///
/// * `array` : The array to create a view from.
/// * `start` : The starting index of the view (inclusive). Defaults to 0.
/// * `end` : The ending index of the view (exclusive). If not provided, defaults
/// to the length of the array.
///
/// Returns an `ArrayView` that provides a window into the specified portion of
/// the array.
///
/// Throws a panic if the indices are invalid (i.e., `start` is negative, `end`
/// is greater than the array length, or `start` is greater than `end`).
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3, 4, 5]
/// let view = arr[1:4] // Create a view of elements at indices 1, 2, and 3
/// inspect(view[0], content="2") // First element of view is arr[1]
/// inspect(view.length(), content="3") // View contains 3 elements
/// }
/// ```
#alias("_[_:_]")
#alias(sub, deprecated="Use _[_:_] instead")
pub fn[T] Array::view(
self : Array[T],
start? : Int = 0,
end? : Int,
) -> ArrayView[T] {
let len = self.length()
let end = match end {
Some(end) | (None with end = len) => end
}
guard start >= 0 && start <= end && end <= len else {
abort("View index out of bounds")
}
ArrayView::make(self.buffer(), start, end - start)
}
///|
/// Creates a view of a portion of the array, returning `None` when indices are
/// invalid.
///
/// Parameters:
///
/// * `array` : The array to create a view from.
/// * `start` : The starting index of the view (inclusive). Defaults to 0.
/// * `end` : The ending index of the view (exclusive). If not provided, defaults
/// to the length of the array.
///
/// Returns `Some(ArrayView)` that provides a window into the specified portion
/// of the array, or `None` when the indices are invalid.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3, 4, 5]
/// let start = 1
/// let end = 4
/// debug_inspect(
/// arr.get_view(start~, end~),
/// content=(
/// #|Some()
/// ),
/// )
/// let start = 3
/// let end = 10
/// debug_inspect(arr.get_view(start~, end~), content="None")
/// }
/// ```
pub fn[T] Array::get_view(
self : Array[T],
start? : Int = 0,
end? : Int,
) -> ArrayView[T]? {
let len = self.length()
let end = match end {
Some(end) | (None with end = len) => end
}
guard start >= 0 && start <= end && end <= len else { None }
Some(ArrayView::make(self.buffer(), start, end - start))
}
///|
/// Creates a new view into a portion of the array view.
///
/// Parameters:
///
/// * `self` : The array view to create a new view from.
/// * `start` : The starting index in the current view (inclusive). Defaults to
/// 0.
/// * `end` : The ending index in the current view (exclusive). Defaults to the
/// length of the current view.
///
/// Returns a new `ArrayView` that provides a window into the specified portion
/// of the original array view. The indices are relative to the start of the
/// current view.
///
/// Throws a panic if:
///
/// * `start` is negative
/// * `end` is greater than the length of the current view
/// * `start` is greater than `end`
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3, 4, 5]
/// let view = arr[1:4] // view = [2, 3, 4]
/// let subview = view[1:2] // subview = [3]
/// inspect(subview[0], content="3")
/// }
/// ```
#alias("_[_:_]")
#alias(sub, deprecated="Use _[_:_] instead")
pub fn[T] ArrayView::view(
self : ArrayView[T],
start? : Int = 0,
end? : Int,
) -> ArrayView[T] {
let len = self.length()
let end = match end {
Some(end) | (None with end = len) => end
}
guard start >= 0 && start <= end && end <= len else {
abort("View index out of bounds")
}
ArrayView::make(self.buf(), self.start() + start, end - start)
}
///|
/// Creates a new view into a portion of the array view, returning `None` when
/// indices are invalid.
///
/// Parameters:
///
/// * `self` : The array view to create a new view from.
/// * `start` : The starting index in the current view (inclusive). Defaults to
/// 0.
/// * `end` : The ending index in the current view (exclusive). Defaults to the
/// length of the current view.
///
/// Returns `Some(ArrayView)` that provides a window into the specified portion
/// of the original array view, or `None` when the indices are invalid.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3, 4, 5]
/// let view = arr[1:4] // view = [2, 3, 4]
/// let start = 1
/// let end = 2
/// debug_inspect(
/// view.get_view(start~, end~),
/// content=(
/// #|Some()
/// ),
/// )
/// let start = 4
/// let end = 5
/// debug_inspect(view.get_view(start~, end~), content="None")
/// }
/// ```
pub fn[T] ArrayView::get_view(
self : ArrayView[T],
start? : Int = 0,
end? : Int,
) -> ArrayView[T]? {
let len = self.length()
let end = match end {
Some(end) | (None with end = len) => end
}
guard start >= 0 && start <= end && end <= len else { None }
Some(ArrayView::make(self.buf(), self.start() + start, end - start))
}
///|
fn[T] unsafe_cast_fixedarray_to_uninitializedarray(
arr : FixedArray[T],
) -> UninitializedArray[T] = "%identity"
///|
/// Creates a new `ArrayView` from a `FixedArray`.
///
/// Parameters:
///
/// * `self` : The fixed array to create a new view from.
/// * `start` : The starting index in the array (inclusive). Defaults to 0.
/// * `end` : The ending index in the array (exclusive). Defaults to the
/// length of the array.
///
/// Returns a new `ArrayView` that provides a window into the specified portion
/// of the original fixed array.
///
/// Throws a panic if:
///
/// * `start` is negative
/// * `end` is greater than the length of the array
/// * `start` is greater than `end`
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr : FixedArray[Int] = [1, 2, 3, 4, 5]
/// let view = arr[1:4] // view = [2, 3, 4]
/// inspect(view[0], content="2")
/// }
/// ```
#alias("_[_:_]")
#alias(sub, deprecated="Use _[_:_] instead")
pub fn[T] FixedArray::view(
self : FixedArray[T],
start? : Int = 0,
end? : Int,
) -> ArrayView[T] {
let len = self.length()
let end = match end {
Some(end) | (None with end = len) => end
}
guard start >= 0 && start <= end && end <= len else {
abort("View index out of bounds")
}
ArrayView::make(
unsafe_cast_fixedarray_to_uninitializedarray(self),
start,
end - start,
)
}
///|
/// Creates a new `ArrayView` from a `FixedArray`, returning `None` when indices
/// are invalid.
///
/// Parameters:
///
/// * `self` : The fixed array to create a new view from.
/// * `start` : The starting index in the array (inclusive). Defaults to 0.
/// * `end` : The ending index in the array (exclusive). Defaults to the
/// length of the array.
///
/// Returns `Some(ArrayView)` that provides a window into the specified portion
/// of the original fixed array, or `None` when the indices are invalid.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr : FixedArray[Int] = [1, 2, 3, 4, 5]
/// let start = 1
/// let end = 4
/// debug_inspect(
/// arr.get_view(start~, end~),
/// content=(
/// #|Some()
/// ),
/// )
/// let start = 2
/// let end = 10
/// debug_inspect(arr.get_view(start~, end~), content="None")
/// }
/// ```
pub fn[T] FixedArray::get_view(
self : FixedArray[T],
start? : Int = 0,
end? : Int,
) -> ArrayView[T]? {
let len = self.length()
let end = match end {
Some(end) | (None with end = len) => end
}
guard start >= 0 && start <= end && end <= len else { None }
Some(
ArrayView::make(
unsafe_cast_fixedarray_to_uninitializedarray(self),
start,
end - start,
),
)
}
///|
/// Return an iterator over suffix views of this array view.
///
/// Set `include_empty=true` to include the empty suffix at the end.
///
/// Example:
///
/// ```mbt check
/// test {
/// let v = [1, 2][:]
/// debug_inspect(
/// v.suffixes().collect(),
/// content=(
/// #|[, ]
/// ),
/// )
/// debug_inspect(
/// v.suffixes(include_empty=true).collect(),
/// content=(
/// #|[, , ]
/// ),
/// )
/// }
/// ```
pub fn[T] ArrayView::suffixes(
self : Self[T],
include_empty? : Bool = false,
) -> Iter[ArrayView[T]] {
let len = self.length()
let mut i = 0
Iter::new(
fn() -> ArrayView[T]? {
if i < len {
let suffix = self[i:]
i += 1
Some(suffix)
} else if i == len {
i += 1
if include_empty {
Some(self[len:])
} else {
None
}
} else {
None
}
},
size_hint=if include_empty { len + 1 } else { len },
)
}
///|
/// Split the array view into contiguous sub-views of length `size`. The last
/// sub-view may be shorter if the view length is not a multiple of `size`. The
/// returned sub-views share the original backing array — no elements are
/// copied.
///
/// Panics if `size <= 0`.
///
/// Example:
///
/// ```mbt check
/// test {
/// let v = [1, 2, 3, 4, 5, 6, 7][:]
/// debug_inspect(
/// v.chunks(3),
/// content=(
/// #|[, , ]
/// ),
/// )
/// }
/// ```
pub fn[T] ArrayView::chunks(
self : ArrayView[T],
size : Int,
) -> Array[ArrayView[T]] {
guard! size > 0
let len = self.length()
if len == 0 {
return []
}
let num_chunks = (len + size - 1) / size
Array::makei(num_chunks, i => {
let start = i * size
let end = Int::min(start + size, len)
self[start:end]
})
}
///|
/// Groups consecutive elements of the view into chunks where adjacent
/// elements satisfy the given predicate. Each returned sub-view shares the
/// original backing array.
///
/// Example:
///
/// ```mbt check
/// test {
/// let v = [1, 1, 2, 2, 2, 3, 1][:]
/// debug_inspect(
/// v.chunk_by((a, b) => a == b),
/// content=(
/// #|[
/// #| ,
/// #| ,
/// #| ,
/// #| ,
/// #|]
/// ),
/// )
/// }
/// ```
#locals(pred)
pub fn[T] ArrayView::chunk_by(
self : ArrayView[T],
pred : (T, T) -> Bool raise?,
) -> Array[ArrayView[T]] raise? {
let chunks = []
if self.is_empty() {
return chunks
}
let start = for i in 1..,
/// #| ,
/// #| ,
/// #|]
/// ),
/// )
/// }
/// ```
pub fn[T] ArrayView::windows(
self : ArrayView[T],
size : Int,
) -> Array[ArrayView[T]] {
guard! size > 0
let len = self.length() - size + 1
if len < 1 {
return []
}
Array::makei(len, i => self[i:i + size])
}
///|
/// Returns an iterator that yields each element of the array view in sequence
/// from start to end.
///
/// Parameters:
///
/// * `array_view` : The array view to iterate over.
///
/// Returns an iterator that yields elements of type `A` from the array view.
/// The iterator uses the view's stored length, so structural mutations to the
/// underlying array after the view is created do not change how many steps the
/// iterator attempts to take.
///
/// Structural shrinking of the underlying array is unsupported and may cause
/// later iterator steps to fail. The same caveat applies to `rev_iter()` and
/// `iter2()`.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3]
/// let view = arr[1:]
/// let mut sum = 0
/// view.iter().each(x => sum += x)
/// inspect(sum, content="5")
/// }
/// ```
#alias(iterator, deprecated)
pub fn[X] ArrayView::iter(self : ArrayView[X]) -> Iter[X] {
let mut i = 0
let len = self.length()
Iter::new(
fn() {
guard i < len else { None }
let elem = self.unsafe_get(i)
i += 1
Some(elem)
},
size_hint=len,
)
}
///|
/// Return a reverse iterator over elements of this view.
///
/// Deprecated alias for reverse iteration; prefer `rev_iterator`.
///
/// Example:
///
/// ```mbt check
/// test {
/// let values = [1, 2, 3][:].rev_iter().collect()
/// debug_inspect(values, content="[3, 2, 1]")
/// }
/// ```
#alias(rev_iterator, deprecated)
pub fn[X] ArrayView::rev_iter(self : ArrayView[X]) -> Iter[X] {
let len = self.length()
let mut i = len
Iter::new(
fn() {
guard i > 0 else { None }
i -= 1
Some(self.unsafe_get(i))
},
size_hint=len,
)
}
///|
/// Returns an iterator that yields tuples of index and value
/// indices start from 0.
///
/// Example:
/// ```mbt check
/// test {
/// let arr = [1, 2, 3]
/// let view = arr[1:]
/// let mut sum = 0
/// let mut sum_keys = 0
/// view
/// .iter2()
/// .each((i, x) => {
/// sum += x
/// sum_keys += i
/// })
/// inspect(sum, content="5")
/// inspect(sum_keys, content="1")
/// }
/// ```
#alias(iterator2, deprecated)
pub fn[X] ArrayView::iter2(self : ArrayView[X]) -> Iter2[Int, X] {
let mut i = 0
let len = self.length()
Iter2::new(
fn() {
guard i < len else { None }
let result = Some((i, self.unsafe_get(i)))
i += 1
result
},
size_hint=len,
)
}
///|
/// Iterates over each element in the array view and applies a function to it.
///
/// Parameters:
///
/// * `self` : The array view to iterate over.
/// * `function` : A function that takes an element of type `T` and returns
/// nothing. This function will be applied to each element in the array view.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3][:]
/// let mut sum = 0
/// arr.each(x => sum += x)
/// inspect(sum, content="6")
/// }
/// ```
#locals(f)
pub fn[T] ArrayView::each(
self : ArrayView[T],
f : (T) -> Unit raise?,
) -> Unit raise? {
for v in self {
f(v)
}
}
///|
/// Iterates over the elements of the array view with index.
///
/// # Example
///
/// ```mbt check
/// test {
/// let v = [3, 4, 5][:]
/// let mut sum = 0
/// v.eachi((i, x) => sum += x + i)
/// inspect(sum, content="15")
/// }
/// ```
#locals(f)
pub fn[T] ArrayView::eachi(
self : ArrayView[T],
f : (Int, T) -> Unit raise?,
) -> Unit raise? {
for i, v in self {
f(i, v)
}
}
///|
/// Iterates over the elements of the array view in reverse order (last to
/// first).
///
/// Example:
///
/// ```mbt check
/// test {
/// let v = [1, 2, 3, 4, 5][1:4]
/// let out = []
/// v.rev_each(x => out.push(x))
/// debug_inspect(out, content="[4, 3, 2]")
/// }
/// ```
#locals(f)
pub fn[T] ArrayView::rev_each(
self : ArrayView[T],
f : (T) -> Unit raise?,
) -> Unit raise? {
let len = self.length()
for i in 0.. out.push((i, x)))
/// debug_inspect(out, content="[(0, 30), (1, 20), (2, 10)]")
/// }
/// ```
#locals(f)
pub fn[T] ArrayView::rev_eachi(
self : ArrayView[T],
f : (Int, T) -> Unit raise?,
) -> Unit raise? {
let len = self.length()
for i in 0.. elem % 2 == 0))
/// assert_true(v[1:4].all(elem => elem % 2 == 0))
/// }
/// ```
#locals(f)
#alias(every)
pub fn[T] ArrayView::all(
self : ArrayView[T],
f : (T) -> Bool raise?,
) -> Bool raise? {
for v in self {
if !f(v) {
return false
}
}
true
}
///|
/// Check if any of the elements in the array view match the condition.
///
/// # Example
///
/// ```mbt check
/// test {
/// let v = [1, 2, 3, 4, 5][:]
/// assert_true(v.any(ele => ele < 6))
/// assert_false(v.any(ele => ele < 1))
/// }
/// ```
#locals(f)
#alias(exists)
pub fn[T] ArrayView::any(
self : ArrayView[T],
f : (T) -> Bool raise?,
) -> Bool raise? {
for v in self {
if f(v) {
return true
}
}
false
}
///|
/// Checks whether the array view contains a specific element by comparing each
/// element with the target value using the equality operator.
///
/// Parameters:
///
/// * `view` : The array view to search in.
/// * `target` : The value to search for in the array view.
///
/// Returns a boolean value indicating whether the target value exists in the
/// array view.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3, 4, 5][:]
/// inspect(arr.contains(3), content="true")
/// inspect(arr.contains(6), content="false")
/// }
/// ```
pub fn[T : Eq] ArrayView::contains(self : ArrayView[T], value : T) -> Bool {
for v in self {
if v == value {
break true
}
} nobreak {
false
}
}
///|
/// Counts how many elements in the array view are equal to `value`.
///
/// # Example
/// ```mbt check
/// test {
/// let view = [1, 2, 1, 3, 1][:]
/// inspect(view.count(1), content="3")
/// inspect(view.count(4), content="0")
/// }
/// ```
pub fn[T : Eq] ArrayView::count(self : ArrayView[T], value : T) -> Int {
for v in self; count = 0 {
if v == value {
continue count + 1
}
continue count
} nobreak {
count
}
}
///|
/// Counts how many elements in the array view satisfy the predicate.
///
/// # Example
/// ```mbt check
/// test {
/// let view = [1, 2, 3, 4, 5][:]
/// inspect(view.count_if(x => x % 2 == 0), content="2")
/// }
/// ```
#locals(f)
pub fn[T] ArrayView::count_if(
self : ArrayView[T],
f : (T) -> Bool raise?,
) -> Int raise? {
for v in self; count = 0 {
if f(v) {
continue count + 1
}
continue count
} nobreak {
count
}
}
///|
/// Searches for the first occurrence of a value in the array view.
///
/// # Example
/// ```mbt check
/// test {
/// let view = [1, 2, 3, 2, 4][:]
/// debug_inspect(view.search(2), content="Some(1)")
/// debug_inspect(view.search(5), content="None")
/// }
/// ```
pub fn[T : Eq] ArrayView::search(self : ArrayView[T], value : T) -> Int? {
for i, x in self {
if x == value {
break Some(i)
}
} nobreak {
None
}
}
///|
/// Searches for the first element in the view that satisfies the predicate
/// `f` and returns its (view-relative) index, or `None` if no element matches.
///
/// Example:
///
/// ```mbt check
/// test {
/// let view = [1, 2, 3, 4, 5][1:]
/// debug_inspect(view.search_by(x => x > 3), content="Some(2)")
/// debug_inspect(view.search_by(x => x > 99), content="None")
/// }
/// ```
#locals(f)
pub fn[T] ArrayView::search_by(
self : ArrayView[T],
f : (T) -> Bool raise?,
) -> Int? raise? {
for i, v in self {
if f(v) {
break Some(i)
}
} nobreak {
None
}
}
///|
/// Checks if the array view starts with the given prefix.
///
/// # Example
/// ```mbt check
/// test {
/// let view = [1, 2, 3, 4, 5][:]
/// inspect(view.starts_with([1, 2]), content="true")
/// inspect(view.starts_with([2, 3]), content="false")
/// }
/// ```
pub fn[T : Eq] ArrayView::starts_with(
self : ArrayView[T],
prefix : ArrayView[T],
) -> Bool {
if prefix.length() > self.length() {
return false
}
for i in 0.. Bool {
let suffix_len = suffix.length()
let self_len = self.length()
if suffix_len > self_len {
return false
}
for i in 0..)
/// ),
/// )
/// debug_inspect(v.strip_prefix([2, 3]), content="None")
/// }
/// ```
pub fn[T : Eq] ArrayView::strip_prefix(
self : ArrayView[T],
prefix : ArrayView[T],
) -> ArrayView[T]? {
if self.starts_with(prefix) {
Some(self[prefix.length():])
} else {
None
}
}
///|
/// Returns a sub-view with `suffix` removed from the end, or `None` if the
/// view does not end with `suffix`. The returned view shares the original
/// backing array — no allocation.
///
/// Example:
///
/// ```mbt check
/// test {
/// let v = [1, 2, 3, 4, 5][:]
/// debug_inspect(
/// v.strip_suffix([4, 5]),
/// content=(
/// #|Some()
/// ),
/// )
/// debug_inspect(v.strip_suffix([3, 4]), content="None")
/// }
/// ```
pub fn[T : Eq] ArrayView::strip_suffix(
self : ArrayView[T],
suffix : ArrayView[T],
) -> ArrayView[T]? {
if self.ends_with(suffix) {
Some(self[:self.length() - suffix.length()])
} else {
None
}
}
///|
/// Performs a binary search on a sorted array view.
///
/// # Example
/// ```mbt check
/// test {
/// let view = [1, 3, 5, 7, 9][:]
/// debug_inspect(view.binary_search(5), content="Ok(2)")
/// debug_inspect(view.binary_search(6), content="Err(3)")
/// }
/// ```
pub fn[T : Compare] ArrayView::binary_search(
self : ArrayView[T],
value : T,
) -> Result[Int, Int] {
let len = self.length()
for i = 0, j = len; i < j; {
let h = i + (j - i) / 2
if self.unsafe_get(h) < value {
continue h + 1, j
} else {
continue i, h
}
} nobreak {
if i < len && self.unsafe_get(i) == value {
Ok(i)
} else {
Err(i)
}
}
}
///|
/// Performs a binary search using a custom comparison function.
///
/// # Example
/// ```mbt check
/// test {
/// let view = [1, 3, 5, 7, 9][:]
/// let result = view.binary_search_by(x => x.compare(5))
/// debug_inspect(result, content="Ok(2)")
/// }
/// ```
#locals(cmp)
pub fn[T] ArrayView::binary_search_by(
self : ArrayView[T],
cmp : (T) -> Int raise?,
) -> Result[Int, Int] raise? {
let len = self.length()
for i = 0, j = len; i < j; {
let h = i + (j - i) / 2
if cmp(self.unsafe_get(h)) < 0 {
continue h + 1, j
} else {
continue i, h
}
} nobreak {
if i < len && cmp(self.unsafe_get(i)) == 0 {
Ok(i)
} else {
Err(i)
}
}
}
///|
/// Fold out values from an ArrayView according to certain rules.
///
/// # Example
/// ```mbt check
/// test {
/// let sum = [1, 2, 3, 4, 5][:].fold(init=0, (sum, elem) => sum + elem)
/// inspect(sum, content="15")
/// }
/// ```
#locals(f)
pub fn[A, B] ArrayView::fold(
self : ArrayView[A],
init~ : B,
f : (B, A) -> B raise?,
) -> B raise? {
for x in self; acc = init {
continue f(acc, x)
} nobreak {
acc
}
}
///|
/// Fold out values from an ArrayView according to certain rules in reversed turn.
///
/// # Example
/// ```mbt check
/// test {
/// let sum = [1, 2, 3, 4, 5][:].rev_fold(init=0, (sum, elem) => sum + elem)
/// inspect(sum, content="15")
/// }
/// ```
#locals(f)
pub fn[A, B] ArrayView::rev_fold(
self : ArrayView[A],
init~ : B,
f : (B, A) -> B raise?,
) -> B raise? {
for i = self.length() - 1, acc = init; i >= 0; {
continue i - 1, f(acc, self.unsafe_get(i))
} nobreak {
acc
}
}
///|
/// Fold out values from an ArrayView according to certain rules with index.
///
/// # Example
/// ```mbt check
/// test {
/// let sum = [1, 2, 3, 4, 5][:].foldi(init=0, (index, sum, _elem) => sum + index)
/// inspect(sum, content="10")
/// }
/// ```
#locals(f)
pub fn[A, B] ArrayView::foldi(
self : ArrayView[A],
init~ : B,
f : (Int, B, A) -> B raise?,
) -> B raise? {
for i, x in self; acc = init {
continue f(i, acc, x)
} nobreak {
acc
}
}
///|
/// Fold out values from an ArrayView according to certain rules in reversed turn with index.
///
/// # Example
/// ```mbt check
/// test {
/// let sum = [1, 2, 3, 4, 5][:].rev_foldi(init=0, (index, sum, _elem) => {
/// sum + index
/// })
/// inspect(sum, content="10")
/// }
/// ```
#locals(f)
pub fn[A, B] ArrayView::rev_foldi(
self : ArrayView[A],
init~ : B,
f : (Int, B, A) -> B raise?,
) -> B raise? {
let len = self.length()
for i in len>..0; acc = init {
continue f(len - i - 1, acc, self.unsafe_get(i))
} nobreak {
acc
}
}
///|
/// Maps a function over the elements of the array view.
///
/// # Example
/// ```mbt check
/// test {
/// let v = [3, 4, 5]
/// let v2 = v[1:].map(x => x + 1)
/// @test.assert_eq(v2, [5, 6])
/// }
/// ```
#locals(f)
pub fn[T, U] ArrayView::map(
self : ArrayView[T],
f : (T) -> U raise?,
) -> Array[U] raise? {
let arr = Array::make_uninit(self.length())
for i, x in self {
arr.unsafe_set(i, f(x))
}
arr
}
///|
/// Maps a function over the elements of the array view with index.
///
/// # Example
/// ```mbt check
/// test {
/// let v = [3, 4, 5]
/// let v2 = v[1:].mapi((i, x) => x + i)
/// @test.assert_eq(v2, [4, 6])
/// }
/// ```
#locals(f)
pub fn[T, U] ArrayView::mapi(
self : ArrayView[T],
f : (Int, T) -> U raise?,
) -> Array[U] raise? {
let arr = Array::make_uninit(self.length())
for i, x in self {
arr.unsafe_set(i, f(i, x))
}
arr
}
///|
/// Filters the array view with a predicate function.
///
/// # Example
/// ```mbt check
/// test {
/// let arr = [1, 2, 3, 4, 5, 6]
/// let v = arr[2:].filter(x => x % 2 == 0)
/// @test.assert_eq(v, [4, 6])
/// }
/// ```
#locals(f)
pub fn[T] ArrayView::filter(
self : ArrayView[T],
f : (T) -> Bool raise?,
) -> Array[T] raise? {
let arr = []
for v in self {
if f(v) {
arr.push(v)
}
}
arr
}
///|
/// Apply a function to each element of the view, keeping only the `Some`
/// results. Returns a freshly allocated `Array`.
///
/// Example:
///
/// ```mbt check
/// test {
/// let v = [1, 2, 3, 4, 5][1:4]
/// debug_inspect(
/// v.filter_map(x => if x % 2 == 0 { Some(x * 10) } else { None }),
/// content="[20, 40]",
/// )
/// }
/// ```
#locals(f)
pub fn[A, B] ArrayView::filter_map(
self : ArrayView[A],
f : (A) -> B? raise?,
) -> Array[B] raise? {
let result = []
for x in self {
if f(x) is Some(x) {
result.push(x)
}
}
result
}
///|
/// Copy the view elements into a newly allocated `Array`.
///
/// # Example
/// ```mbt check
/// test {
/// let view = [1, 2, 3, 4, 5, 6][2:4]
/// let arr = view.to_owned()
/// @test.assert_eq(arr, [3, 4])
/// }
/// ```
#alias(to_array, deprecated)
pub fn[T] ArrayView::to_owned(self : ArrayView[T]) -> Array[T] {
let len = self.length()
if len == 0 {
[]
} else {
Array::unsafe_make_and_blit(
self.buf(),
allocate_len=len,
src_offset=self.start(),
len~,
)
}
}
///|
/// Concatenate strings within an array into a single complete string.
///
/// Example:
///
/// ```mbt check
/// test {
/// let a : Array[String] = ["1", "2", "3"]
/// let array_view = a[:]
/// inspect(array_view.join(","), content="1,2,3")
/// }
/// ```
pub fn[A : ToStringView] ArrayView::join(
self : ArrayView[A],
separator : StringView,
) -> String {
match self {
[] => ""
[hd, .. tl] => {
let hd = hd.to_string_view()
let size_hint = for s in tl; size_hint = hd.length() {
continue size_hint + s.to_string_view().length() + separator.length()
} nobreak {
size_hint
}
let size_hint = size_hint << 1
let buf = StringBuilder(size_hint~)
// buf.write_string(hd)
buf.write_view(hd)
if separator is "" {
for s in tl {
// buf.write_string(s)
let s = s.to_string_view()
buf.write_view(s)
}
} else {
for s in tl {
let s = s.to_string_view()
buf.write_view(separator)
// buf.write_string(s)
buf.write_view(s)
}
}
buf.to_string()
}
}
}
///|
/// Performs a lexicographical comparison of two array views.
///
/// This method compares the array views element by element until a difference
/// is found or one view is exhausted. Unlike the `Compare` trait implementation
/// which uses shortlex order (shorter views come first), this method compares
/// based purely on element values until a difference is found.
///
/// # Returns
///
/// - A negative integer if `self` is lexicographically less than `other`
/// - Zero if `self` is lexicographically equal to `other`
/// - A positive integer if `self` is lexicographically greater than `other`
///
/// # Example
///
/// ```mbt check
/// test {
/// inspect([1, 2][:].lexical_compare([1, 2, 3]), content="-1")
/// inspect([1, 2, 3][:].lexical_compare([1, 2]), content="1")
/// inspect([1, 2, 3][:].lexical_compare([1, 2, 3]), content="0")
/// inspect([1, 2, 3][:].lexical_compare([1, 2, 4]), content="-1")
/// }
/// ```
pub fn[T : Compare] ArrayView::lexical_compare(
self : ArrayView[T],
other : ArrayView[T],
) -> Int {
let self_len = self.length()
let other_len = other.length()
let min_len = if self_len < other_len { self_len } else { other_len }
for i in 0..
/// ),
/// )
/// }
/// ```
pub fn[T] ArrayView::rev(self : ArrayView[T]) -> Array[T] {
let len = self.length()
let arr = Array::make_uninit(len)
for i in 0.. Bool {
if self.length() != other.length() {
return false
}
for i, x in self {
if !(x == other.unsafe_get(i)) {
return false
}
} nobreak {
true
}
}
///|
pub impl[T : Compare] Compare for ArrayView[T] with fn compare(self, other) -> Int {
let len_self = self.length()
let len_other = other.length()
let cmp = len_self.compare(len_other)
guard cmp == 0 else { return cmp }
for i, x in self {
let cmp = x.compare(other.unsafe_get(i))
guard cmp == 0 else { break cmp }
} nobreak {
0
}
}
///|
pub impl[A : Hash] Hash for ArrayView[A] with fn hash_combine(self, hasher) {
for e in self {
hasher.combine(e)
}
}
///|
/// Concatenates two array views into a new view backed by a freshly allocated
/// array. The resulting view contains all elements from `self` followed by all
/// elements from `other`.
///
/// Note: although `+` looks cheap, this allocates a new owned `Array[T]`
/// because views cannot own data — the returned view spans the whole new
/// array.
///
/// Example:
///
/// ```mbt check
/// test {
/// let a = [1, 2, 3, 4, 5][1:4]
/// let b = [10, 20, 30][:2]
/// debug_inspect(
/// a + b,
/// content=(
/// #|
/// ),
/// )
/// }
/// ```
pub impl[T] Add for ArrayView[T] with fn add(self, other) {
let len_self = self.length()
let len_other = other.length()
if len_self == 0 {
Array::unsafe_make_and_blit(
other.buf(),
allocate_len=len_other,
src_offset=other.start(),
len=len_other,
)
} else {
let result = Array::unsafe_make_and_blit(
self.buf(),
allocate_len=len_self + len_other,
src_offset=self.start(),
len=len_self,
)
UninitializedArray::unsafe_blit(
result.buffer(),
len_self,
other.buf(),
other.start(),
len_other,
)
result
}
}
// #endregion