// 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.
///|
/// Retrieves an element at the specified index from a fixed-size array.
///
/// Parameters:
///
/// * `array` : The fixed-size array to access.
/// * `index` : The position in the array 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 : FixedArray[Int] = [1, 2, 3]
/// debug_inspect(arr.get(1), content="Some(2)")
/// let arr : FixedArray[Int] = [1, 2, 3]
/// debug_inspect(arr.get(3), content="None")
/// }
/// ```
pub fn[T] FixedArray::get(self : FixedArray[T], idx : Int) -> T? {
let len = self.length()
guard idx >= 0 && idx < len else { None }
Some(self.unsafe_get(idx))
}
///|
/// Returns an empty fixed-size array of the specified type.
///
/// Parameters:
///
/// * `X` : The type parameter specifying the element type of the array.
///
/// Returns an empty fixed-size array of type `FixedArray[X]`.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr : FixedArray[Int] = ([] : FixedArray[_])
/// inspect(arr.length(), content="0")
/// inspect(arr.is_empty(), content="true")
/// }
/// ```
pub impl[X] Default for FixedArray[X] with fn default() {
[]
}
///|
/// Fill the array with a given value.
///
/// This method fills all or part of a FixedArray with the given value.
///
/// # Parameters
/// - `value`: The value to fill the array with
/// - `start`: The starting index (inclusive, default: 0)
/// - `end`: The ending index (exclusive, optional)
///
/// If `end` is not provided, fills from `start` to the end of the array.
/// If `start` equals `end`, no elements are modified.
///
/// # Panics
/// - Panics if `start` is negative or greater than or equal to the array length
/// - Panics if `end` is provided and is less than `start` or greater than array length
/// - Does nothing if the array is empty
///
/// # Example
/// ```mbt check
/// test {
/// // Fill entire array
/// let fa : FixedArray[Int] = [0, 0, 0, 0, 0]
/// fa.fill(3)
/// debug_inspect(
/// fa,
/// content=(
/// #|
/// ),
/// )
///
/// // Fill from index 1 to 3 (exclusive)
/// let fa2 : FixedArray[Int] = [0, 0, 0, 0, 0]
/// fa2.fill(9, start=1, end=3)
/// debug_inspect(
/// fa2,
/// content=(
/// #|
/// ),
/// )
///
/// // Fill from index 2 to end
/// let fa3 : FixedArray[String] = ["a", "b", "c", "d"]
/// fa3.fill("x", start=2)
/// debug_inspect(
/// fa3,
/// content=(
/// #|
/// ),
/// )
/// }
/// ```
#owned(value)
pub fn[T] FixedArray::fill(
self : FixedArray[T],
value : T,
start? : Int = 0,
end? : Int,
) -> Unit {
let array_length = self.length()
guard array_length > 0 else { return }
guard! start >= 0 && start < array_length
let length = match end {
None => array_length - start
Some(e) => {
guard! e >= start && e <= array_length
e - start
}
}
self.unchecked_fill(start, value, length)
}
///|
#coverage.skip
#intrinsic("%fixedarray.fill")
#owned(value)
fn[T] FixedArray::unchecked_fill(
self : FixedArray[T],
start : Int,
value : T,
len : Int,
) -> Unit {
for i in start..<(start + len) {
self[i] = value
}
}
///|
/// Tests whether the FixedArray contains no elements.
///
/// Parameters:
///
/// * `FixedArray` : The FixedArray to check.
///
/// Returns `true` if the FixedArray has no elements, `false` otherwise.
///
/// Example:
///
/// ```mbt check
/// test {
/// let empty : FixedArray[Int] = []
/// inspect(empty.is_empty(), content="true")
/// let non_empty = [1, 2, 3]
/// inspect(non_empty.is_empty(), content="false")
/// }
/// ```
pub fn[T] FixedArray::is_empty(self : FixedArray[T]) -> Bool {
self.length() == 0
}
///|
///
/// Performs a binary search on a sorted array to find the index of a given element.
///
/// # Example
/// ```mbt check
/// test {
/// let v : FixedArray[Int] = [3, 4, 5]
/// let result = v.binary_search(3)
/// @test.assert_eq(result, Ok(0)) // The element 3 is found at index 0
/// }
/// ```
///
/// # Arguments
/// - `self`: The array in which to perform the search.
/// - `value`: The element to search for in the array.
///
/// # Returns
/// - `Result[Int, Int]`:
/// If the element is found, an `Ok` variant is returned, containing the index of the matching element in the array.
/// If there are multiple matches, the leftmost match will be returned.
/// If the element is not found, an `Err` variant is returned, containing the index where the element could be inserted to maintain the sorted order.
///
/// # Notes
/// - Ensure that the array is sorted in increasing order before calling this function.
/// - If the array is not sorted, the returned result is undefined and should not be relied on.
pub fn[T : Compare] FixedArray::binary_search(
self : FixedArray[T],
value : T,
) -> Result[Int, Int] {
self[:].binary_search(value)
}
///|
/// Performs a binary search on a sorted array using a custom comparison
/// function. Returns the position of the matching element if found, or the
/// position where the element could be inserted while maintaining the sorted
/// order.
///
/// Parameters:
///
/// * `array` : The sorted array to search in.
/// * `comparator` : A function that compares each element with the target value,
/// returning:
/// * A negative integer if the element is less than the target
/// * Zero if the element equals the target
/// * A positive integer if the element is greater than the target
///
/// Returns a `Result` containing either:
///
/// * `Ok(index)` if a matching element is found at position `index`
/// * `Err(index)` if no match is found, where `index` is the position where the
/// element could be inserted
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr : FixedArray[Int] = [1, 3, 5, 7, 9]
/// let find_3 = arr.binary_search_by(x => x.compare(3))
/// debug_inspect(find_3, content="Ok(1)")
/// let find_4 = arr.binary_search_by(x => x.compare(4))
/// debug_inspect(find_4, content="Err(2)")
/// }
/// ```
///
/// Notes:
///
/// * Assumes the array is sorted according to the ordering implied by the
/// comparison function
/// * For multiple matches, returns the leftmost matching position
/// * Returns an insertion point that maintains the sort order when no match is
/// found
pub fn[T] FixedArray::binary_search_by(
self : FixedArray[T],
cmp : (T) -> Int raise?,
) -> Result[Int, Int] raise? {
self[:].binary_search_by(cmp)
}
///|
/// Iterates over each element.
///
/// # Arguments
///
/// - `self`: The array to iterate over.
/// - `f`: The function to apply to each element.
///
/// # Example
///
/// ```mbt check
/// test {
/// let arr = []
/// [1, 2, 3, 4, 5].each(x => arr.push(x))
/// @test.assert_eq(arr, [1, 2, 3, 4, 5])
/// }
/// ```
#locals(f)
pub fn[T] FixedArray::each(
self : FixedArray[T],
f : (T) -> Unit raise?,
) -> Unit raise? {
for v in self {
f(v)
}
}
///|
test "each" {
let mut i = 0
let mut failed = false
let f = elem => {
if elem != i + 1 {
failed = true
}
i += 1
}
{
i = 0
([] : FixedArray[_]).each(f)
assert_false(failed)
inspect(i, content="0")
}
{
i = 0
([1] : FixedArray[_]).each(f)
assert_false(failed)
inspect(i, content="1")
}
i = 0
([1, 2, 3, 4, 5] : FixedArray[_]).each(f)
assert_false(failed)
inspect(i, content="5")
}
///|
/// Iterates over the array with index.
///
/// # Arguments
///
/// - `self`: The array to iterate over.
/// - `f`: A function that takes an `Int` representing the index and a `T` representing the element of the array, and returns `Unit`.
///
/// # Example
///
/// ```mbt check
/// test {
/// let arr = []
/// [1, 2, 3, 4, 5].eachi((index, elem) => arr.push((index, elem)))
/// @test.assert_eq(arr, [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)])
/// }
/// ```
#locals(f)
pub fn[T] FixedArray::eachi(
self : FixedArray[T],
f : (Int, T) -> Unit raise?,
) -> Unit raise? {
for i, v in self {
f(i, v)
}
}
///|
test "eachi" {
let mut i = 0
let mut failed = false
let f = (index, elem) => {
if index != i || elem != i + 1 {
failed = true
}
i += 1
}
{
i = 0
([] : FixedArray[_]).eachi(f)
assert_false(failed)
inspect(i, content="0")
}
{
i = 0
([1] : FixedArray[_]).eachi(f)
assert_false(failed)
inspect(i, content="1")
}
i = 0
([1, 2, 3, 4, 5] : FixedArray[_]).eachi(f)
assert_false(failed)
inspect(i, content="5")
}
///|
/// Iterates over each element in reversed turn.
///
/// # Arguments
///
/// - `self`: The array to iterate over.
/// - `f`: The function to apply to each element.
///
/// # Example
///
/// ```mbt check
/// test {
/// let arr = []
/// [1, 2, 3, 4, 5].rev_each(x => arr.push(x))
/// @test.assert_eq(arr, [5, 4, 3, 2, 1])
/// }
/// ```
#locals(f)
pub fn[T] FixedArray::rev_each(
self : FixedArray[T],
f : (T) -> Unit raise?,
) -> Unit raise? {
for i in self.length()>..0 {
f(self.unsafe_get(i))
}
}
///|
test "rev_each" {
let mut i = 6
let mut failed = false
let f = elem => {
if elem != i - 1 {
failed = true
}
i -= 1
}
{
i = 1
([] : FixedArray[_]).rev_each(f)
assert_false(failed)
inspect(i, content="1")
}
{
i = 2
([1] : FixedArray[_]).rev_each(f)
assert_false(failed)
inspect(i, content="1")
}
i = 6
([1, 2, 3, 4, 5] : FixedArray[_]).rev_each(f)
assert_false(failed)
inspect(i, content="1")
}
///|
/// Iterates over the array with index in reversed turn.
///
/// # Arguments
///
/// - `self`: The array to iterate over.
/// - `f`: A function that takes an `Int` representing the index and a `T` representing the element of the array, and returns `Unit`.
///
/// # Example
///
/// ```mbt check
/// test {
/// let arr = []
/// [1, 2, 3, 4, 5].rev_eachi((index, elem) => arr.push((index, elem)))
/// @test.assert_eq(arr, [(0, 5), (1, 4), (2, 3), (3, 2), (4, 1)])
/// }
/// ```
#locals(f)
pub fn[T] FixedArray::rev_eachi(
self : FixedArray[T],
f : (Int, T) -> Unit raise?,
) -> Unit raise? {
let len = self.length()
for i in 0.. {
if index != j || elem != i - 1 {
failed = true
}
i -= 1
j += 1
}
{
i = 1
j = 0
([] : FixedArray[_]).rev_eachi(f)
assert_false(failed)
inspect(i, content="1")
inspect(j, content="0")
}
{
i = 2
j = 0
([1] : FixedArray[_]).rev_eachi(f)
assert_false(failed)
inspect(i, content="1")
inspect(j, content="1")
}
i = 6
j = 0
([1, 2, 3, 4, 5] : FixedArray[_]).rev_eachi(f)
assert_false(failed)
inspect(i, content="1")
inspect(j, content="5")
}
///|
/// Applies a function to each element of the array and returns a new array with the results.
///
/// # Example
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3, 4, 5]
/// let doubled = arr.map(x => x * 2)
/// @test.assert_eq(doubled, [2, 4, 6, 8, 10])
/// }
/// ```
#locals(f)
pub fn[T, U] FixedArray::map(
self : FixedArray[T],
f : (T) -> U raise?,
) -> FixedArray[U] raise? {
if self.is_empty() {
return []
}
let len = self.length()
let res = FixedArray::make(len, f(self.unsafe_get(0)))
for i in 1.. x)
assert_true(empty == [])
let simple_arr : FixedArray[_] = [6]
let simple_doubled = simple_arr.map(x => x * 2)
assert_true(simple_doubled == [12])
let arr : FixedArray[_] = [1, 2, 3, 4, 5]
let doubled = arr.map(x => x * 2)
assert_true(doubled == [2, 4, 6, 8, 10])
}
///|
/// Maps a function over the elements of the arr with index.
///
/// # Example
/// ```mbt check
/// test {
/// let arr = [3, 4, 5]
/// let added = arr.mapi((i, x) => x + i)
/// @test.assert_eq(added, [3, 5, 7])
/// }
/// ```
#locals(f)
pub fn[T, U] FixedArray::mapi(
self : FixedArray[T],
f : (Int, T) -> U raise?,
) -> FixedArray[U] raise? {
if self.is_empty() {
return []
}
let len = self.length()
let res = FixedArray::make(len, f(0, self.unsafe_get(0)))
for i in 1.. x + i)
assert_true(empty == [])
let simple_arr : FixedArray[_] = [6]
let simple_doubled = simple_arr.mapi((i, x) => x * 2 + i)
assert_true(simple_doubled == [12])
let arr : FixedArray[_] = [1, 2, 3, 4, 5]
let doubled = arr.mapi((i, x) => x * 2 + i)
assert_true(doubled == [2, 5, 8, 11, 14])
}
///|
/// Creates a new fixed-size array of the specified length, where each element is
/// initialized using a function that maps indices to values.
///
/// Parameters:
///
/// * `length` : The length of the array to create. If `length` is less than or
/// equal to 0, returns an empty array.
/// * `initializer` : A function that takes an index (from 0 to `length - 1`) and
/// returns a value of type `T` for that position.
///
/// Returns a new fixed array containing the values produced by applying the
/// initializer function to each index.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = FixedArray::makei(3, i => i * 2)
/// debug_inspect(
/// arr,
/// content=(
/// #|
/// ),
/// )
/// }
/// ```
#locals(value)
pub fn[T] FixedArray::makei(
length : Int,
value : (Int) -> T raise?,
) -> FixedArray[T] raise? {
if length <= 0 {
[]
} else {
let array = FixedArray::make(length, value(0))
for i in 1.. i)
inspect(empty.length(), content="0")
let simple_arr = FixedArray::makei(1, i => i)
inspect(simple_arr.length(), content="1")
inspect(simple_arr[0], content="0")
let arr = FixedArray::makei(2, i => i)
inspect(arr.length(), content="2")
inspect(arr[0], content="0")
inspect(arr[1], content="1")
}
///|
/// Creates a new fixed-size array from a dynamic array. The resulting fixed
/// array will have the same length and elements as the input array.
///
/// Parameters:
///
/// * `array` : A dynamic array containing elements of type `T` that will be
/// converted to a fixed array.
///
/// Returns a new fixed array containing the same elements as the input array.
///
/// Example:
///
/// ```mbt check
/// test {
/// let dynamic_array : ReadOnlyArray[Int] = [1, 2, 3, 4, 5]
/// let fixed_array = FixedArray::from_array(dynamic_array)
/// debug_inspect(
/// fixed_array,
/// content=(
/// #|
/// ),
/// )
/// }
/// ```
pub fn[T] FixedArray::from_array(array : ArrayView[T]) -> FixedArray[T] {
FixedArray::makei(array.length(), i => array.unsafe_get(i))
}
///|
test "from_array" {
let array = FixedArray::from_array([1, 2, 3, 4, 5])
assert_true(array == [1, 2, 3, 4, 5])
}
///|
/// Fold out values from an array 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] FixedArray::fold(
self : FixedArray[A],
init~ : B,
f : (B, A) -> B raise?,
) -> B raise? {
for x in self; acc = init {
continue f(acc, x)
} nobreak {
acc
}
}
///|
test "fold" {
let sum = ([] : FixedArray[_]).fold(init=1, (sum, elem) => sum + elem)
inspect(sum, content="1")
let sum = ([1] : FixedArray[_]).fold(init=2, (sum, elem) => sum + elem)
inspect(sum, content="3")
let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).fold(init=0, (sum, elem) => {
sum + elem
})
inspect(sum, content="15")
}
///|
/// Fold out values from an array 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] FixedArray::rev_fold(
self : FixedArray[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
}
}
///|
test "rev_fold" {
let sum = ([] : FixedArray[_]).rev_fold(init=1, (sum, elem) => sum + elem)
inspect(sum, content="1")
let sum = ([1] : FixedArray[_]).rev_fold(init=2, (sum, elem) => sum + elem)
inspect(sum, content="3")
let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).rev_fold(init=0, (sum, elem) => {
sum + elem
})
inspect(sum, content="15")
}
///|
/// Fold out values from an array 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] FixedArray::foldi(
self : FixedArray[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
}
}
///|
test "fold_lefti" {
let f = (index, sum, elem) => index + sum + elem
{
let sum = ([] : FixedArray[_]).foldi(init=1, f)
inspect(sum, content="1")
}
{
let sum = ([1] : FixedArray[_]).foldi(init=2, f)
inspect(sum, content="3")
}
let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).foldi(init=0, f)
inspect(sum, content="25")
}
///|
/// Fold out values from an array 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] FixedArray::rev_foldi(
self : FixedArray[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
}
}
///|
test "rev_foldi" {
let f = (index, sum, elem) => index + sum + elem
{
let sum = ([] : FixedArray[_]).rev_foldi(init=1, f)
inspect(sum, content="1")
}
{
let sum = ([1] : FixedArray[_]).rev_foldi(init=2, f)
inspect(sum, content="3")
}
let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).rev_foldi(init=0, f)
inspect(sum, content="25")
}
///|
/// Reverses the array in place by swapping elements from both ends until
/// reaching the middle.
///
/// Parameters:
///
/// * `array` : The array to be reversed. The array will be modified in place.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr : FixedArray[_] = [1, 2, 3, 4, 5]
/// arr.rev_in_place()
/// debug_inspect(
/// arr,
/// content=(
/// #|
/// ),
/// )
/// }
/// ```
#alias(rev_inplace, deprecated)
pub fn[T] FixedArray::rev_in_place(self : FixedArray[T]) -> Unit {
let mid_len = self.length() / 2
for i in 0..
/// ),
/// )
/// // Original array remains unchanged
/// debug_inspect(
/// arr,
/// content=(
/// #|
/// ),
/// )
/// }
/// ```
pub fn[T] FixedArray::rev(self : FixedArray[T]) -> FixedArray[T] {
match self {
[] => []
[.., first] => {
let res = FixedArray::make(self.length(), first)
let len = self.length()
for i in 1.. Unit {
let temp = self[i]
self[i] = self[j]
self[j] = temp
}
///|
test "swap" {
{
let arr : FixedArray[Int] = [1]
arr.swap(0, 0)
assert_true(arr == [1])
}
{
let arr : FixedArray[_] = [1, 2]
arr.swap(0, 0)
assert_true(arr == [1, 2])
arr.swap(0, 1)
assert_true(arr == [2, 1])
}
let arr : FixedArray[_] = [1, 2, 3, 4, 5]
arr.swap(3, 3)
assert_true(arr == [1, 2, 3, 4, 5])
arr.swap(1, 3)
assert_true(arr == [1, 4, 3, 2, 5])
}
///|
/// Check if all the elements in the array match the condition.
///
/// # Example
///
/// ```mbt check
/// test {
/// let arr : FixedArray[Int] = [1, 2, 3, 4, 5]
/// assert_true(arr.all(ele => ele < 6))
/// assert_false(arr.all(ele => ele < 5))
/// }
/// ```
///
#alias(every)
pub fn[T] FixedArray::all(
self : FixedArray[T],
f : (T) -> Bool raise?,
) -> Bool raise? {
self[:].all(f)
}
///|
test "all" {
{
let arr : FixedArray[Int] = []
assert_true(arr.all(ele => ele < 6))
assert_true(arr.all(ele => ele < 5))
}
{
let arr : FixedArray[_] = [5]
assert_true(arr.all(ele => ele < 6))
assert_false(arr.all(ele => ele < 5))
}
let arr : FixedArray[_] = [1, 2, 3, 4, 5]
assert_true(arr.all(ele => ele < 6))
assert_false(arr.all(ele => ele < 5))
}
///|
/// Check if any of the elements in the array match the condition.
///
/// # Example
///
/// ```mbt check
/// test {
/// let arr : FixedArray[Int] = [1, 2, 3, 4, 5]
/// assert_true(arr.any(ele => ele < 6))
/// assert_true(arr.any(ele => ele < 5))
/// }
/// ```
#alias(exists)
pub fn[T] FixedArray::any(
self : FixedArray[T],
f : (T) -> Bool raise?,
) -> Bool raise? {
self[:].any(f)
}
///|
test "any" {
{
let arr : FixedArray[Int] = []
assert_false(arr.any(ele => ele < 6))
assert_false(arr.any(ele => ele < 5))
}
{
let arr : FixedArray[_] = [5]
assert_true(arr.any(ele => ele < 6))
assert_false(arr.any(ele => ele < 5))
}
let arr : FixedArray[_] = [1, 2, 3, 4, 5]
assert_true(arr.any(ele => ele < 6))
assert_true(arr.any(ele => ele < 5))
}
///|
test "fill" {
{
let arr : FixedArray[Int] = []
arr.fill(3)
assert_true(arr == [])
}
{
let arr : FixedArray[_] = [6]
arr.fill(5)
assert_true(arr == [5])
}
let arr : FixedArray[_] = [0, 0, 0, 0, 0]
arr.fill(3)
assert_true(arr == [3, 3, 3, 3, 3])
}
///|
/// Search the array index for a given element.
///
/// # Example
/// ```mbt check
/// test {
/// let arr : FixedArray[Int] = [3, 4, 5]
/// @test.assert_eq(arr.search(3), Some(0))
/// }
/// ```
pub fn[T : Eq] FixedArray::search(self : FixedArray[T], value : T) -> Int? {
self[:].search(value)
}
///|
test "search" {
{
let arr : FixedArray[Int] = []
assert_true(arr.search(3) == None)
assert_true(arr.search(-1) == None)
}
{
let arr : FixedArray[_] = [3]
assert_true(arr.search(3) == Some(0))
assert_true(arr.search(-1) == None)
}
let arr : FixedArray[_] = [1, 2, 3, 4, 5]
assert_true(arr.search(1) == Some(0))
assert_true(arr.search(5) == Some(4))
assert_true(arr.search(3) == Some(2))
assert_true(arr.search(-1) == None)
}
///|
/// Checks if the array contains an element.
///
/// # Example
/// ```mbt check
/// test {
/// let arr : FixedArray[Int] = [3, 4, 5]
/// assert_true(arr.contains(3))
/// }
/// ```
pub fn[T : Eq] FixedArray::contains(self : FixedArray[T], value : T) -> Bool {
for x in self {
if x == value {
return true
}
}
false
}
///|
test "contains" {
{
let arr : FixedArray[Int] = []
assert_false(arr.contains(3))
assert_false(arr.contains(-1))
}
{
let arr : FixedArray[_] = [3]
assert_true(arr.contains(3))
assert_false(arr.contains(-1))
}
let arr : FixedArray[_] = [3, 4, 5]
assert_true(arr.contains(3))
assert_true(arr.contains(4))
assert_true(arr.contains(5))
assert_false(arr.contains(6))
}
///|
/// Check if the array starts with a given prefix.
///
/// # Example
/// ```mbt check
/// test {
/// let arr : FixedArray[Int] = [3, 4, 5]
/// assert_true(arr.starts_with([3, 4]))
/// }
/// ```
pub fn[T : Eq] FixedArray::starts_with(
self : FixedArray[T],
prefix : ArrayView[T],
) -> Bool {
self[:].starts_with(prefix)
}
///|
test "starts_with" {
{
let arr : FixedArray[Int] = []
assert_true(arr.starts_with([]))
assert_false(arr.starts_with([1]))
}
{
let arr : FixedArray[_] = [3]
assert_true(arr.starts_with([]))
assert_true(arr.starts_with([3]))
assert_false(arr.starts_with([2]))
assert_false(arr.starts_with([3, 1]))
}
let arr : FixedArray[_] = [3, 4, 5]
assert_true(arr.starts_with([]))
assert_true(arr.starts_with([3]))
assert_false(arr.starts_with([2]))
assert_true(arr.starts_with([3, 4]))
assert_false(arr.starts_with([3, 2]))
assert_true(arr.starts_with([3, 4, 5]))
assert_false(arr.starts_with([3, 4, 2]))
assert_false(arr.starts_with([3, 4, 5, 6]))
}
///|
/// Check if the array ends with a given suffix.
///
/// # Example
/// ```mbt check
/// test {
/// let v : FixedArray[Int] = [3, 4, 5]
/// assert_true(v.ends_with([5]))
/// }
/// ```
pub fn[T : Eq] FixedArray::ends_with(
self : FixedArray[T],
suffix : ArrayView[T],
) -> Bool {
self[:].ends_with(suffix)
}
///|
test "ends_with" {
{
let arr : FixedArray[Int] = []
assert_true(arr.ends_with([]))
assert_false(arr.ends_with([1]))
}
{
let arr : FixedArray[_] = [3]
assert_true(arr.ends_with([]))
assert_true(arr.ends_with([3]))
assert_false(arr.ends_with([2]))
assert_false(arr.ends_with([3, 1]))
}
let arr : FixedArray[_] = [3, 4, 5]
assert_true(arr.ends_with([]))
assert_true(arr.ends_with([5]))
assert_false(arr.ends_with([2]))
assert_true(arr.ends_with([4, 5]))
assert_false(arr.ends_with([4, 2]))
assert_false(arr.ends_with([2, 5]))
assert_true(arr.ends_with([3, 4, 5]))
assert_false(arr.ends_with([3, 4, 2]))
assert_false(arr.ends_with([3, 2, 5]))
assert_false(arr.ends_with([2, 4, 5]))
assert_false(arr.ends_with([3, 4, 5, 6]))
assert_false(arr.ends_with([2, 3, 4, 5]))
}
///|
/// Checks if two fixed arrays are equal.
///
/// Two arrays are considered equal if they have the same length and all
/// corresponding elements are equal. The elements in the arrays must implement
/// the `Eq` trait.
///
/// Parameters:
///
/// * `self` : The first fixed array to compare.
/// * `other` : The second fixed array to compare.
///
/// Returns `true` if the arrays are equal, `false` otherwise.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr1 : FixedArray[Int] = [1, 2, 3]
/// let arr2 : FixedArray[Int] = [1, 2, 3]
/// let arr3 : FixedArray[Int] = [1, 2, 4]
/// inspect(arr1 == arr2, content="true")
/// inspect(arr1 == arr3, content="false")
/// }
/// ```
pub impl[T : Eq] Eq for FixedArray[T] with fn equal(
self : FixedArray[T],
that : FixedArray[T],
) -> Bool {
if self.length() != that.length() {
return false
}
for i, x in self {
if x != that[i] {
return false
}
}
true
}
///|
pub impl[T : Hash] Hash for FixedArray[T] with fn hash_combine(self, hasher) {
for v in self {
v.hash_combine(hasher)
}
}
///|
test "equal" {
{
inspect(([] : FixedArray[Int]) == [], content="true")
inspect(([] : FixedArray[_]) == [1], content="false")
inspect(([1, 2] : FixedArray[_]) == [], content="false")
}
{
inspect(([1] : FixedArray[_]) == [1], content="true")
inspect(([1] : FixedArray[_]) == [2], content="false")
inspect(([1, 2] : FixedArray[_]) == [1], content="false")
inspect(([1] : FixedArray[_]) == [1, 2], content="false")
}
inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [1, 2, 3, 4, 5], content="true")
inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [1, 2, 3, 4], content="false")
inspect(([1, 2, 3, 4] : FixedArray[_]) == [1, 2, 3, 4, 5], content="false")
inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [6, 2, 3, 4, 5], content="false")
inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [1, 2, 6, 4, 5], content="false")
inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [1, 2, 3, 4, 6], content="false")
}
///|
/// Compares two fixed arrays based on shortlex order by their elements. First
/// compares the lengths of the arrays, then compares elements pairwise until a
/// difference is found or all elements have been compared.
///
/// Parameters:
///
/// * `self` : The first fixed array to compare.
/// * `other` : The second fixed array to compare.
///
/// Returns an integer that indicates the relative order:
///
/// * A negative value if `self` is less than `other`
/// * Zero if `self` equals `other`
/// * A positive value if `self` is greater than `other`
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr1 = [1, 2, 3]
/// let arr2 = [1, 2, 4]
/// let arr3 = [1, 2]
/// inspect(arr1.compare(arr2), content="-1") // arr1 < arr2
/// inspect(arr2.compare(arr1), content="1") // arr2 > arr1
/// inspect(arr1.compare(arr3), content="1") // arr1 > arr3 (longer)
/// inspect(arr1.compare(arr1), content="0") // arr1 = arr1
/// }
/// ```
pub impl[T : Compare] Compare for FixedArray[T] with fn compare(self, other) {
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 in 0..
/// ),
/// )
/// }
/// ```
pub impl[T] Add for FixedArray[T] with fn add(self, other) {
let slen = self.length()
let nlen = other.length()
FixedArray::makei(slen + nlen, i => {
if i < slen {
self[i]
} else {
other[i - slen]
}
})
}
///|
test "add" {
{
assert_true(([] : FixedArray[Int]) + [] == [])
assert_true(([] : FixedArray[_]) + [1, 2, 3, 4, 5] == [1, 2, 3, 4, 5])
assert_true(([1, 2, 3, 4, 5] : FixedArray[_]) + [] == [1, 2, 3, 4, 5])
}
{
assert_true(([1] : FixedArray[_]) + [2] == [1, 2])
assert_true(([1] : FixedArray[_]) + [1, 2, 3, 4, 5] == [1, 1, 2, 3, 4, 5])
assert_true(([1, 2, 3, 4, 5] : FixedArray[_]) + [1] == [1, 2, 3, 4, 5, 1])
}
assert_true(
([1, 2, 3, 4, 5] : FixedArray[_]) + [6, 7, 8, 9, 10] ==
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
)
}
///|
test "iter" {
let arr : FixedArray[_] = [1, 2, 3, 4, 5]
let iter = arr.iter()
let exb = StringBuilder()
let mut i = 0
iter.each(x => {
exb.write_string(x.to_string())
exb.write_char('\n')
i += 1
})
assert_true(i == arr.length())
inspect(
exb,
content=(
#|1
#|2
#|3
#|4
#|5
#|
),
)
}
///|
/// Creates a new fixed array from an iterator.
///
/// Parameters:
///
/// * `iterator` : An iterator of type `Iter[T]` from which elements will be
/// collected into a fixed array.
///
/// Returns a new fixed array containing all elements from the iterator.
///
/// Example:
///
/// ```mbt check
/// test {
/// let arr = [1, 2, 3]
/// let fixed_arr = FixedArray::from_iter(arr.iter())
/// debug_inspect(
/// fixed_arr,
/// content=(
/// #|
/// ),
/// )
/// }
/// ```
#alias(from_iterator, deprecated)
pub fn[T] FixedArray::from_iter(iter : Iter[T]) -> FixedArray[T] {
FixedArray::from_array(iter.collect())
}
///|
/// Returns the last element of a fixed array if it exists.
///
/// Parameters:
///
/// * `self` : The fixed array to get the last element from.
///
/// Returns `Some(element)` containing the last element if the array is not
/// empty, or `None` if the array is empty.
///
/// Example:
///
/// ```mbt check
/// test {
/// let array : FixedArray[Int] = [1, 2, 3]
/// debug_inspect(array.last(), content="Some(3)")
/// let empty : FixedArray[Int] = []
/// debug_inspect(empty.last(), content="None")
/// }
/// ```
pub fn[A] FixedArray::last(self : FixedArray[A]) -> A? {
match self {
[] => None
[.., last] => Some(last)
}
}
///|
/// Concatenate the string-renderable elements of the array into a single
/// complete string, separated by `separator`.
///
/// Example:
///
/// ```mbt check
/// test {
/// let fixed_array : FixedArray[String] = ["1", "2", "3"]
/// inspect(fixed_array.join(","), content="1,2,3")
/// }
/// ```
pub fn[A : ToStringView] FixedArray::join(
self : FixedArray[A],
separator : StringView,
) -> String {
let len = self.length()
if len == 0 {
return ""
}
let first = self[0].to_string_view()
let size_hint = for i in 1.. Iter[X] {
self[:].iter()
}
///|
/// Return an index-value iterator over the fixed array.
///
/// Deprecated alias; prefer `iterator2`.
///
/// Example:
///
/// ```mbt check
/// test {
/// debug_inspect(
/// ([10, 20] : FixedArray[Int]).iter2().to_array(),
/// content="[(0, 10), (1, 20)]",
/// )
/// }
/// ```
#alias(iterator2, deprecated)
pub fn[X] FixedArray::iter2(self : FixedArray[X]) -> Iter2[Int, X] {
self[:].iter2()
}
///|
/// Creates a new array that is a copy of the original array.
///
/// Parameters:
///
/// * `self` : The array to be copied. The type of elements in the array must be
/// `T`.
///
/// Returns a new array containing all elements from the original array in the
/// same order.
///
/// Example:
///
/// ```mbt check
/// test {
/// let original = [1, 2, 3]
/// let copied = original.copy()
/// debug_inspect(copied, content="[1, 2, 3]")
/// inspect(physical_equal(original, copied), content="false")
/// }
/// ```
#cfg(not(target="js"))
#alias(clone, deprecated)
pub fn[T] FixedArray::copy(self : FixedArray[T]) -> FixedArray[T] {
let len = self.length()
if len == 0 {
[]
} else {
FixedArray::make_and_blit(self, allocate_len=len, init=self[0], len~)
}
}
///|
/// Creates a new array that is a copy of the original array.
///
/// Parameters:
///
/// * `self` : The array to be copied. The type of elements in the array must be
/// `T`.
///
/// Returns a new array containing all elements from the original array in the
/// same order.
///
/// Example:
///
/// ```mbt check
/// test {
/// let original = [1, 2, 3]
/// let copied = original.copy()
/// @debug.debug_inspect(copied, content="[1, 2, 3]")
/// inspect(physical_equal(original, copied), content="false")
/// }
/// ```
#cfg(target="js")
#alias(clone, deprecated)
pub fn[T] FixedArray::copy(self : FixedArray[T]) -> FixedArray[T] {
JSArray::ofAnyFixedArray(self).copy().toAnyFixedArray()
}
///|
/// Performs a lexicographical comparison of two fixed arrays.
///
/// This method compares the arrays element by element until a difference is
/// found or one array is exhausted. Unlike the `Compare` trait implementation
/// which uses shortlex order (shorter arrays 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 {
/// let a : FixedArray[Int] = [1, 2]
/// let b : FixedArray[Int] = [1, 2, 3]
/// inspect(a.lexical_compare(b), content="-1")
/// inspect(b.lexical_compare(a), content="1")
/// let c : FixedArray[Int] = [1, 2, 3]
/// inspect(b.lexical_compare(c), content="0")
/// let d : FixedArray[Int] = [1, 2, 4]
/// inspect(b.lexical_compare(d), content="-1")
/// }
/// ```
pub fn[T : Compare] FixedArray::lexical_compare(
self : FixedArray[T],
other : FixedArray[T],
) -> Int {
self[:].lexical_compare(other)
}