// 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.
///|
/// Copies elements from one array to another array. Works correctly even when
/// the source and destination arrays overlap.
///
/// Parameters:
///
/// * `dst` : The destination array where elements will be copied to.
/// * `dst_offset` : The starting index in the destination array where elements
/// should be copied.
/// * `src` : The source array from which elements will be copied.
/// * `src_offset` : The starting index in the source array from which elements
/// should be copied.
/// * `len` : The number of elements to copy.
///
/// The behavior is undefined if any of the following conditions are met:
///
/// * `len` is negative
/// * `dst_offset` is negative
/// * `src_offset` is negative
/// * `dst_offset + len` exceeds the length of destination array
/// * `src_offset + len` exceeds the length of source array
///
/// Example:
///
/// ```mbt check
/// test {
/// let src = [1, 2, 3, 4, 5]
/// let dst = [0, 0, 0, 0, 0]
/// Array::unsafe_blit(dst, 1, src, 2, 2)
/// @debug.debug_inspect(dst, content="[0, 3, 4, 0, 0]")
/// }
/// ```
///
#internal(unsafe, "Panic if the indices or length are out of bounds")
#doc(hidden)
pub fn[A] Array::unsafe_blit(
dst : Array[A],
dst_offset : Int,
src : Array[A],
src_offset : Int,
len : Int,
) -> Unit {
FixedArray::unsafe_blit(
dst.buffer().0,
dst_offset,
src.buffer().0,
src_offset,
len,
)
}
///|
/// Copies elements from a fixed-size array to a dynamic array. The arrays may
/// overlap, in which case the copy is performed in a way that preserves the
/// data.
///
/// Parameters:
///
/// * `dst` : The destination dynamic array where elements will be copied to.
/// * `dst_offset` : The starting index in the destination array where copying
/// begins.
/// * `src` : The source fixed-size array from which elements will be copied.
/// * `src_offset` : The starting index in the source array from which copying
/// begins.
/// * `len` : The number of elements to copy.
///
/// Example:
///
/// ```mbt check
/// test {
/// let src = FixedArray::make(5, 0)
/// let dst = Array::make(5, 0)
/// for i in 0..<5 {
/// src[i] = i + 1
/// }
/// Array::unsafe_blit_fixed(dst, 1, src, 0, 2)
/// @debug.debug_inspect(dst, content="[0, 1, 2, 0, 0]")
/// }
/// ```
pub fn[A] Array::unsafe_blit_fixed(
dst : Array[A],
dst_offset : Int,
src : FixedArray[A],
src_offset : Int,
len : Int,
) -> Unit {
UninitializedArray::unsafe_blit_fixed(
dst.buffer(),
dst_offset,
src,
src_offset,
len,
)
}
///|
test "Array::blit_to/basic" {
let src = [1, 2, 3, 4, 5]
let dst = [0, 0, 0, 0, 0]
src[1:4].blit_to(dst, dst_offset=2)
assert_true(dst == [0, 0, 2, 3, 4])
let src = [1, 2, 3, 4, 5]
let dst = [0, 0, 0, 0, 0]
src[0:3].blit_to(dst)
assert_true(dst == [1, 2, 3, 0, 0])
}
///|
test "Array::blit_to/zero_length" {
let src = [1, 2, 3]
let dst = [4, 5, 6]
src[0:0].blit_to(dst)
assert_true(dst == [4, 5, 6])
}
///|
test "Array::blit_to/grow_destination" {
let src = [1, 2, 3, 4, 5]
let dst = [0, 0]
src[0:3].blit_to(dst, dst_offset=1)
assert_true(dst == [0, 1, 2, 3])
}
///|
#warnings("-deprecated")
test "Array::blit_to/grow_destination_directly" {
let src = [1, 2, 3, 4]
let dst = [0]
Array::blit_to(src, dst, len=2, src_offset=1, dst_offset=1)
assert_true(dst == [0, 2, 3])
let self = [1, 2, 3]
Array::blit_to(self, self, len=2, dst_offset=3)
assert_true(self == [1, 2, 3, 1, 2])
}
///|
test "Array::blit_to/edge_cases" {
// Test with src_offset and dst_offset
let src = [1, 2, 3, 4, 5]
let dst = [0, 0, 0, 0, 0]
src[1:3].blit_to(dst, dst_offset=2)
assert_true(dst == [0, 0, 2, 3, 0])
// Test when src and dst are the same array
src[0:2].blit_to(src, dst_offset=3)
assert_true(src == [1, 2, 3, 1, 2])
// Test with len equal to 0
src[0:0].blit_to(dst, dst_offset=0)
assert_true(dst == [0, 0, 2, 3, 0])
// Test with len equal to the length of src
src[0:5].blit_to(dst)
assert_true(dst == [1, 2, 3, 1, 2])
}
///|
test "panic Array::blit_to/boundary_cases1" {
let src = [1, 2, 3, 4, 5]
let dst = [0, 0, 0, 0, 0]
// Invalid range (start > end will panic)
ignore(src[3:1].blit_to(dst))
}
///|
test "panic Array::blit_to/boundary_cases2" {
let src = [1, 2, 3, 4, 5]
let dst = [0, 0, 0, 0, 0]
// Invalid src_offset (negative index in view creation will panic)
ignore(src[-1:1].blit_to(dst))
}
///|
test "panic Array::blit_to/boundary_cases3" {
let src = [1, 2, 3, 4, 5]
let dst = [0, 0, 0, 0, 0]
// len exceeding src length
ignore(src[0:6].blit_to(dst))
}
///|
test "panic Array::blit_to/boundary_cases4" {
let src = [1, 2, 3, 4, 5]
let dst = [0, 0, 0, 0, 0]
// dst offset exceeding dst length
ignore(src[0:5].blit_to(dst, dst_offset=6))
}
///|
#warnings("-deprecated")
test "panic Array::blit_to/reject_overflowed_source_range" {
let src = [1]
let dst = [0]
Array::blit_to(src, dst, len=0x7fffffff, src_offset=1)
}
///|
/// TODO
/// 1. allow skip
/// 2. verify test
/// 3. concurrency test
test "Array::blit_to - random cases" {
let src = [10, 20, 30, 40, 50]
let dst = [0, 0, 0, 0, 0]
// Random len, src_offset, and dst_offset
src[2:4].blit_to(dst, dst_offset=1)
assert_true(dst == [0, 30, 40, 0, 0])
// Another random case
src[1:4].blit_to(dst, dst_offset=2)
assert_true(dst == [0, 30, 20, 30, 40])
// Yet another random case
src[4:5].blit_to(dst, dst_offset=4)
assert_true(dst == [0, 30, 20, 30, 50])
}
///|
test "Array::blit_to - boundary cases" {
let src = [1, 2, 3, 4, 5]
let dst = [0, 0, 0, 0, 0]
// Test with src_offset at the end of src
src[4:5].blit_to(dst, dst_offset=0)
assert_true(dst == [5, 0, 0, 0, 0])
// Test with dst_offset at the end of dst
src[0:1].blit_to(dst, dst_offset=4)
assert_true(dst == [5, 0, 0, 0, 1])
// Test with len equal to the remaining length of src
src[3:5].blit_to(dst, dst_offset=3)
assert_true(dst == [5, 0, 0, 4, 5])
}
///|
test "Array::unsafe_blit_fixed" {
let src = FixedArray::make(3, 1) // Create a FixedArray with 3 elements of value 1
let dst = Array::make(5, 0) // Create an Array with 5 elements of value 0
Array::unsafe_blit_fixed(dst, 1, src, 0, 2) // Copy 2 elements from src[0] to dst[1]
assert_true(dst == [0, 1, 1, 0, 0])
}
///|
test "ArrayView::blit_to/basic" {
let src = [1, 2, 3, 4, 5]
let view = src[1:4] // view = [2, 3, 4]
let dst = [0, 0, 0, 0, 0]
view.blit_to(dst)
assert_true(dst == [2, 3, 4, 0, 0])
}
///|
test "ArrayView::blit_to/with_offset" {
let src = [1, 2, 3, 4, 5]
let view = src[1:4] // view = [2, 3, 4]
let dst = [0, 0, 0, 0, 0]
view.blit_to(dst, dst_offset=2)
assert_true(dst == [0, 0, 2, 3, 4])
}
///|
test "ArrayView::blit_to/grow_destination" {
let src = [1, 2, 3, 4, 5]
let view = src[1:4] // view = [2, 3, 4]
let dst = [0, 0]
view.blit_to(dst, dst_offset=1)
assert_true(dst == [0, 2, 3, 4])
}
///|
test "ArrayView::blit_to/empty_view" {
let src = [1, 2, 3, 4, 5]
let view = src[2:2] // empty view
let dst = [0, 0, 0]
view.blit_to(dst)
assert_true(dst == [0, 0, 0])
}
///|
test "ArrayView::blit_to/nested_view" {
let src = [1, 2, 3, 4, 5, 6, 7]
let view1 = src[1:6] // [2, 3, 4, 5, 6]
let view2 = view1[1:4] // [3, 4, 5]
let dst = [0, 0, 0, 0, 0]
view2.blit_to(dst, dst_offset=1)
assert_true(dst == [0, 3, 4, 5, 0])
}
///|
test "panic ArrayView::blit_to/invalid_offset" {
let src = [1, 2, 3, 4, 5]
let view = src[1:4]
let dst = [0, 0, 0]
ignore(view.blit_to(dst, dst_offset=-1))
}
///|
test "panic ArrayView::blit_to/offset_exceeds_length" {
let src = [1, 2, 3, 4, 5]
let view = src[1:4]
let dst = [0, 0, 0]
ignore(view.blit_to(dst, dst_offset=4))
}
// test "Array::blit_to - invalid cases" {
// let src = [1, 2, 3, 4, 5]
// let dst = [0, 0, 0, 0, 0]
// // Invalid len
// Array::blit_to(src, dst, len=-1)
// inspect(dst, content="[0, 0, 0, 0, 0]")
// // Invalid src_offset
// Array::blit_to(src, dst, len=2, src_offset=-1)
// inspect(dst, content="[0, 0, 0, 0, 0]")
// // Invalid dst_offset
// Array::blit_to(src, dst, len=2, dst_offset=-1)
// inspect(dst, content="[0, 0, 0, 0, 0]")
// // len exceeding src length
// Array::blit_to(src, dst, len=6)
// inspect(dst, content="[0, 0, 0, 0, 0]")
// // len exceeding dst length
// Array::blit_to(src, dst, len=5, dst_offset=1)
// inspect(dst, content="[0, 0, 0, 0, 0]")
// }