///|
/// Auto-generated core modules for moonbit-eval interpreter
/// This file contains embedded RuntimeModule definitions for all moonbitlang/core modules
///|
let core_modules : Map[String, RuntimeModule] = {
"abort": moonbitlang_core_abort_module,
"moonbitlang/core/abort": moonbitlang_core_abort_module,
"array": moonbitlang_core_array_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"bench": moonbitlang_core_bench_module,
"moonbitlang/core/bench": moonbitlang_core_bench_module,
"bigint": moonbitlang_core_bigint_module,
"moonbitlang/core/bigint": moonbitlang_core_bigint_module,
"bool": moonbitlang_core_bool_module,
"moonbitlang/core/bool": moonbitlang_core_bool_module,
"buffer": moonbitlang_core_buffer_module,
"moonbitlang/core/buffer": moonbitlang_core_buffer_module,
"builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"byte": moonbitlang_core_byte_module,
"moonbitlang/core/byte": moonbitlang_core_byte_module,
"bytes": moonbitlang_core_bytes_module,
"moonbitlang/core/bytes": moonbitlang_core_bytes_module,
"char": moonbitlang_core_char_module,
"moonbitlang/core/char": moonbitlang_core_char_module,
"cmp": moonbitlang_core_cmp_module,
"moonbitlang/core/cmp": moonbitlang_core_cmp_module,
"deque": moonbitlang_core_deque_module,
"moonbitlang/core/deque": moonbitlang_core_deque_module,
"double": moonbitlang_core_double_module,
"moonbitlang/core/double": moonbitlang_core_double_module,
"double/internal/ryu": moonbitlang_core_double_internal_ryu_module,
"moonbitlang/core/double/internal/ryu": moonbitlang_core_double_internal_ryu_module,
"env": moonbitlang_core_env_module,
"moonbitlang/core/env": moonbitlang_core_env_module,
"float": moonbitlang_core_float_module,
"moonbitlang/core/float": moonbitlang_core_float_module,
"hashmap": moonbitlang_core_hashmap_module,
"moonbitlang/core/hashmap": moonbitlang_core_hashmap_module,
"hashset": moonbitlang_core_hashset_module,
"moonbitlang/core/hashset": moonbitlang_core_hashset_module,
"immut/array": moonbitlang_core_immut_array_module,
"moonbitlang/core/immut/array": moonbitlang_core_immut_array_module,
"immut/hashmap": moonbitlang_core_immut_hashmap_module,
"moonbitlang/core/immut/hashmap": moonbitlang_core_immut_hashmap_module,
"immut/hashset": moonbitlang_core_immut_hashset_module,
"moonbitlang/core/immut/hashset": moonbitlang_core_immut_hashset_module,
"immut/internal/path": moonbitlang_core_immut_internal_path_module,
"moonbitlang/core/immut/internal/path": moonbitlang_core_immut_internal_path_module,
"immut/internal/sparse_array": moonbitlang_core_immut_internal_sparse_array_module,
"moonbitlang/core/immut/internal/sparse_array": moonbitlang_core_immut_internal_sparse_array_module,
"immut/list": moonbitlang_core_immut_list_module,
"moonbitlang/core/immut/list": moonbitlang_core_immut_list_module,
"immut/priority_queue": moonbitlang_core_immut_priority_queue_module,
"moonbitlang/core/immut/priority_queue": moonbitlang_core_immut_priority_queue_module,
"immut/sorted_map": moonbitlang_core_immut_sorted_map_module,
"moonbitlang/core/immut/sorted_map": moonbitlang_core_immut_sorted_map_module,
"immut/sorted_set": moonbitlang_core_immut_sorted_set_module,
"moonbitlang/core/immut/sorted_set": moonbitlang_core_immut_sorted_set_module,
"int": moonbitlang_core_int_module,
"moonbitlang/core/int": moonbitlang_core_int_module,
"int16": moonbitlang_core_int16_module,
"moonbitlang/core/int16": moonbitlang_core_int16_module,
"int64": moonbitlang_core_int64_module,
"moonbitlang/core/int64": moonbitlang_core_int64_module,
"json": moonbitlang_core_json_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
"list": moonbitlang_core_list_module,
"moonbitlang/core/list": moonbitlang_core_list_module,
"math": moonbitlang_core_math_module,
"moonbitlang/core/math": moonbitlang_core_math_module,
"option": moonbitlang_core_option_module,
"moonbitlang/core/option": moonbitlang_core_option_module,
"prelude": moonbitlang_core_prelude_module,
"moonbitlang/core/prelude": moonbitlang_core_prelude_module,
"priority_queue": moonbitlang_core_priority_queue_module,
"moonbitlang/core/priority_queue": moonbitlang_core_priority_queue_module,
"queue": moonbitlang_core_queue_module,
"moonbitlang/core/queue": moonbitlang_core_queue_module,
"quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module,
"moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module,
"random": moonbitlang_core_random_module,
"moonbitlang/core/random": moonbitlang_core_random_module,
"random/internal/random_source": moonbitlang_core_random_internal_random_source_module,
"moonbitlang/core/random/internal/random_source": moonbitlang_core_random_internal_random_source_module,
"rational": moonbitlang_core_rational_module,
"moonbitlang/core/rational": moonbitlang_core_rational_module,
"ref": moonbitlang_core_ref_module,
"moonbitlang/core/ref": moonbitlang_core_ref_module,
"result": moonbitlang_core_result_module,
"moonbitlang/core/result": moonbitlang_core_result_module,
"set": moonbitlang_core_set_module,
"moonbitlang/core/set": moonbitlang_core_set_module,
"sorted_map": moonbitlang_core_sorted_map_module,
"moonbitlang/core/sorted_map": moonbitlang_core_sorted_map_module,
"sorted_set": moonbitlang_core_sorted_set_module,
"moonbitlang/core/sorted_set": moonbitlang_core_sorted_set_module,
"strconv": moonbitlang_core_strconv_module,
"moonbitlang/core/strconv": moonbitlang_core_strconv_module,
"string": moonbitlang_core_string_module,
"moonbitlang/core/string": moonbitlang_core_string_module,
"test": moonbitlang_core_test_module,
"moonbitlang/core/test": moonbitlang_core_test_module,
"tuple": moonbitlang_core_tuple_module,
"moonbitlang/core/tuple": moonbitlang_core_tuple_module,
"uint": moonbitlang_core_uint_module,
"moonbitlang/core/uint": moonbitlang_core_uint_module,
"uint16": moonbitlang_core_uint16_module,
"moonbitlang/core/uint16": moonbitlang_core_uint16_module,
"uint64": moonbitlang_core_uint64_module,
"moonbitlang/core/uint64": moonbitlang_core_uint64_module,
"unit": moonbitlang_core_unit_module,
"moonbitlang/core/unit": moonbitlang_core_unit_module,
}
///|
fn dummy_loc() -> @basic.Location {
{
start: { fname: "", lnum: 0, bol: 0, cnum: 0 },
end: { fname: "", lnum: 0, bol: 0, cnum: 0 },
}
}
///|
let moonbitlang_core_abort_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/abort",
deps={},
fn(_env, build) {
{
"abort": build(
(
#|pub fn[T] abort(msg : String) -> T { let _ = msg
#| panic_impl() }
),
),
}
},
)
///|
let moonbitlang_core_array_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/array",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/bytes": moonbitlang_core_bytes_module,
"moonbitlang/core/string": moonbitlang_core_string_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module,
},
fn(_env, build) {
{
"copy": build(
(
#|pub fn[T] FixedArray::copy(self : FixedArray[T]) -> FixedArray[T] { let len = self.length()
#| if len == 0 {
#| []
#| } else {
#| let arr = FixedArray::make(len, self[0])
#| FixedArray::unsafe_blit(arr, 0, self, 0, len)
#| arr
#| } }
),
),
"from_iter": build(
(
#|pub fn[T] Array::from_iter(iter : Iter[T]) -> Array[T] { iter.collect() }
),
),
"push_iter": build(
(
#|pub fn[T] Array::push_iter(self : Self[T], iter : Iter[T]) -> Unit { for x in iter {
#| self.push(x)
#| } }
),
),
"shuffle_in_place": build(
(
#|pub fn[T] shuffle_in_place(self : Array[T], rand~ : (Int) -> Int) -> Unit { let n = self.length()
#| for i = n - 1; i > 0; i = i - 1 {
#| let j = rand(i + 1) % (i + 1)
#| // for safety, perf is not a concern here
#| // TODO: maybe return an error later
#| self.swap(i, j)
#| } }
),
),
"shuffle": build(
(
#|pub fn[T] shuffle(self : Array[T], rand~ : (Int) -> Int) -> Array[T] { let new_arr = self.copy()
#| Array::shuffle_in_place(new_arr, rand~)
#| new_arr }
),
),
"last": build(
(
#|pub fn[A] last(self : Array[A]) -> A? { match self {
#| [] => None
#| [.., last] => Some(last)
#| } }
),
),
"zip": build(
(
#|pub fn[A, B] zip(self : Array[A], other : Array[B]) -> Array[(A, B)] { let length = if self.length() < other.length() {
#| self.length()
#| } else {
#| other.length()
#| }
#| let arr = Array::new(capacity=length)
#| for i in 0.. (Array[T1], Array[T2]) { let arr1 : Array[T1] = Array::new(capacity=self.length())
#| let arr2 : Array[T2] = Array::new(capacity=self.length())
#| for pair in self {
#| let (x, y) = pair
#| arr1.push(x)
#| arr2.push(y)
#| }
#| (arr1, arr2) }
),
),
"zip_to_iter2": build(
(
#|pub fn[A, B] zip_to_iter2(self : Array[A], other : Array[B]) -> Iter2[A, B] { Iter2::new(yield_ => {
#| let length = if self.length() < other.length() {
#| self.length()
#| } else {
#| other.length()
#| }
#| for i in 0.. String { self[:].join(separator) }
),
),
"from_array": build(
(
#|pub fn[T] FixedArray::from_array(array : Array[T]) -> FixedArray[T] { FixedArray::makei(array.length(), i => array[i]) }
),
),
"rev_inplace": build(
(
#|pub fn[T] FixedArray::rev_inplace(self : FixedArray[T]) -> Unit { let mid_len = self.length() / 2
#| for i in 0.. 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 }
),
),
"search": build(
(
#|pub fn[T : Eq] FixedArray::search(self : FixedArray[T], value : T) -> Int? { for i in 0.. Bool { for i in 0.. FixedArray[T] { FixedArray::from_array(iter.collect()) }
),
),
"last": build(
(
#|pub fn[A] FixedArray::last(self : FixedArray[A]) -> A? { match self {
#| [] => None
#| [.., last] => Some(last)
#| } }
),
),
"sort_by_key": build(
(
#|pub fn[T, K : Compare] sort_by_key(self : Array[T], map : (T) -> K) -> Unit { quick_sort_by(
#| self[:],
#| (a, b) => map(a).compare(map(b)),
#| None,
#| get_limit(self.length()),
#| ) }
),
),
"sort_by": build(
(
#|pub fn[T] sort_by(self : Array[T], cmp : (T, T) -> Int) -> Unit { quick_sort_by(self[:], cmp, None, get_limit(self.length())) }
),
),
"try_bubble_sort_by": build(
(
#|fn[T] try_bubble_sort_by(arr : ArrayView[T], cmp : (T, T) -> Int) -> Bool { let max_tries = 8
#| let mut tries = 0
#| for i in 1.. 0 && cmp(arr[j - 1], arr[j]) > 0; j = j - 1 {
#| sorted = false
#| arr.swap(j, j - 1)
#| }
#| if !sorted {
#| tries += 1
#| if tries > max_tries {
#| return false
#| }
#| }
#| }
#| true }
),
),
"bubble_sort_by": build(
(
#|fn[T] bubble_sort_by(arr : ArrayView[T], cmp : (T, T) -> Int) -> Unit { for i in 1.. 0 && cmp(arr[j - 1], arr[j]) > 0; j = j - 1 {
#| arr.swap(j, j - 1)
#| }
#| } }
),
),
"choose_pivot_by": build(
(
#|fn[T] choose_pivot_by(arr : ArrayView[T], cmp : (T, T) -> Int) -> (Int, Bool) { let len = arr.length()
#| let use_median_of_medians = 50
#| let max_swaps = 4 * 3
#| let mut swaps = 0
#| let b = len / 4 * 2
#| if len >= 8 {
#| let a = len / 4 * 1
#| let c = len / 4 * 3
#| let sort_2 = (a : Int, b : Int) => if cmp(arr[a], arr[b]) > 0 {
#| arr.swap(a, b)
#| swaps += 1
#| }
#| let sort_3 = (a : Int, b : Int, c : Int) => {
#| sort_2(a, b)
#| sort_2(b, c)
#| sort_2(a, b)
#| }
#| if len > use_median_of_medians {
#| sort_3(a - 1, a, a + 1)
#| sort_3(b - 1, b, b + 1)
#| sort_3(c - 1, c, c + 1)
#| }
#| sort_3(a, b, c)
#| }
#| if swaps == max_swaps {
#| arr.rev_inplace()
#| (len - b - 1, true)
#| } else {
#| (b, swaps == 0)
#| } }
),
),
"heap_sort_by": build(
(
#|fn[T] heap_sort_by(arr : ArrayView[T], cmp : (T, T) -> Int) -> Unit { let len = arr.length()
#| for i = len / 2 - 1; i >= 0; i = i - 1 {
#| sift_down_by(arr, i, cmp)
#| }
#| for i = len - 1; i > 0; i = i - 1 {
#| arr.swap(0, i)
#| sift_down_by(arr[0:i], 0, cmp)
#| } }
),
),
"fixed_heap_sort_by": build(
(
#|fn[T] fixed_heap_sort_by(arr : FixedArraySlice[T], cmp : (T, T) -> Int) -> Unit { let len = arr.length()
#| for i = len / 2 - 1; i >= 0; i = i - 1 {
#| fixed_sift_down_by(arr, i, cmp)
#| }
#| for i = len - 1; i > 0; i = i - 1 {
#| arr.swap(0, i)
#| fixed_sift_down_by(arr.slice(0, i), 0, cmp)
#| } }
),
),
"copy": build(
(
#|pub fn[T] copy(self : Array[T]) -> Array[T] { let len = self.length()
#| if len == 0 {
#| []
#| } else {
#| let arr = Array::make(len, self[0])
#| Array::unsafe_blit(arr, 0, self, 0, len)
#| arr
#| } }
),
),
"copy": build(
(
#|pub fn[T] FixedArray::copy(self : FixedArray[T]) -> FixedArray[T] { JSArray::ofAnyFixedArray(self).copy().toAnyFixedArray() }
),
),
"copy": build(
(
#|pub fn[T] copy(self : Array[T]) -> Array[T] { JSArray::ofAnyArray(self).copy().toAnyArray() }
),
),
"stable_sort": build(
(
#|pub fn[T : Compare] FixedArray::stable_sort(self : FixedArray[T]) -> Unit { timsort({ array: self, start: 0, end: self.length() }) }
),
),
"timsort": build(
(
#|fn[T : Compare] timsort(arr : FixedArraySlice[T]) -> Unit { // Slices of up to this length get sorted using insertion sort.
#| let max_insertion = 20
#| // Short arrays get sorted in-place via insertion sort to avoid allocations.
#| let len = arr.length()
#| if len <= max_insertion {
#| FixedArraySlice::insertion_sort(arr)
#| }
#| let mut end = 0
#| let mut start = 0
#| let runs : Array[TimSortRun] = []
#| while end < len {
#| let (streak_end, was_reversed) = find_streak(arr.slice(start, arr.end))
#| end += streak_end
#| if was_reversed {
#| arr.slice(start, end).rev_inplace()
#| }
#| // Insert some more elements into the run if it's too short. Insertion sort is faster than
#| // merge sort on short sequences, so this significantly improves performance.
#| end = provide_sorted_batch(arr, start, end)
#| runs.push({ start, len: end - start })
#| start = end
#| while true {
#| guard collapse(runs, len) is Some(r) else { break }
#| let left = runs[r]
#| let right = runs[r + 1]
#| merge(arr.slice(left.start, right.start + right.len), left.len)
#| runs[r + 1] = { start: left.start, len: left.len + right.len }
#| runs.remove(r) |> ignore
#| }
#| } }
),
),
"merge": build(
(
#|fn[T : Compare] merge(arr : FixedArraySlice[T], mid : Int) -> Unit { let buf_len = arr.length() - mid
#| let buf : FixedArray[T] = FixedArray::make(buf_len, arr[mid])
#| for i in 0..=
#| 0 &&
#| p2 >= 0; {
#| if arr[p1] > buf[p2] {
#| arr[p] = arr[p1]
#| continue p1 - 1, p2, p - 1
#| } else {
#| arr[p] = buf[p2]
#| continue p1, p2 - 1, p - 1
#| }
#| } else {
#| p2
#| }
#| for i = buf_remaining; i >= 0; i = i - 1 {
#| arr[i] = buf[i]
#| } }
),
),
"find_streak": build(
(
#|fn[T : Compare] find_streak(arr : FixedArraySlice[T]) -> (Int, Bool) { let len = arr.length()
#| if len < 2 {
#| return (len, false)
#| }
#| let assume_reverse = arr[1] < arr[0]
#| if assume_reverse {
#| for end = 2 {
#| if end < len && arr[end] < arr[end - 1] {
#| continue end + 1
#| } else {
#| break (end, true)
#| }
#| }
#| } else {
#| for end = 2 {
#| if end < len && arr[end] >= arr[end - 1] {
#| continue end + 1
#| } else {
#| break (end, false)
#| }
#| }
#| } }
),
),
"collapse": build(
(
#|fn collapse(runs : Array[TimSortRun], stop : Int) -> Int? { let n : Int = runs.length()
#| if n >= 2 &&
#| (
#| runs[n - 1].start + runs[n - 1].len == stop ||
#| runs[n - 2].len <= runs[n - 1].len ||
#| (n >= 3 && runs[n - 3].len <= runs[n - 2].len + runs[n - 1].len) ||
#| (n >= 4 && runs[n - 4].len <= runs[n - 3].len + runs[n - 2].len)
#| ) {
#| if n >= 3 && runs[n - 3].len < runs[n - 1].len {
#| Some(n - 3)
#| } else {
#| Some(n - 2)
#| }
#| } else {
#| None
#| } }
),
),
"sort": build(
(
#|pub fn[T : Compare] FixedArray::sort(self : FixedArray[T]) -> Unit { fixed_quick_sort(
#| { array: self, start: 0, end: self.length() },
#| None,
#| fixed_get_limit(self.length()),
#| ) }
),
),
"fixed_get_limit": build(
(
#|fn fixed_get_limit(len : Int) -> Int { let mut len = len
#| let mut limit = 0
#| while len > 0 {
#| len = len / 2
#| limit += 1
#| }
#| limit }
),
),
"fixed_try_bubble_sort": build(
(
#|fn[T : Compare] fixed_try_bubble_sort(arr : FixedArraySlice[T]) -> Bool { let max_tries = 8
#| let mut tries = 0
#| for i in 1.. 0 && arr[j - 1] > arr[j]; j = j - 1 {
#| sorted = false
#| arr.swap(j, j - 1)
#| }
#| if !sorted {
#| tries += 1
#| if tries > max_tries {
#| return false
#| }
#| }
#| }
#| true }
),
),
"fixed_bubble_sort": build(
(
#|fn[T : Compare] fixed_bubble_sort(arr : FixedArraySlice[T]) -> Unit { for i in 1.. 0 && arr[j - 1] > arr[j]; j = j - 1 {
#| arr.swap(j, j - 1)
#| }
#| } }
),
),
"fixed_choose_pivot": build(
(
#|fn[T : Compare] fixed_choose_pivot(arr : FixedArraySlice[T]) -> (Int, Bool) { let len = arr.length()
#| let use_median_of_medians = 50
#| let max_swaps = 4 * 3
#| let mut swaps = 0
#| let b = len / 4 * 2
#| if len >= 8 {
#| let a = len / 4 * 1
#| let c = len / 4 * 3
#| let sort_2 = (a : Int, b : Int) => if arr[a] > arr[b] {
#| arr.swap(a, b)
#| swaps += 1
#| }
#| let sort_3 = (a : Int, b : Int, c : Int) => {
#| sort_2(a, b)
#| sort_2(b, c)
#| sort_2(a, b)
#| }
#| if len > use_median_of_medians {
#| sort_3(a - 1, a, a + 1)
#| sort_3(b - 1, b, b + 1)
#| sort_3(c - 1, c, c + 1)
#| }
#| sort_3(a, b, c)
#| }
#| if swaps == max_swaps {
#| arr.rev_inplace()
#| (len - b - 1, true)
#| } else {
#| (b, swaps == 0)
#| } }
),
),
"fixed_heap_sort": build(
(
#|fn[T : Compare] fixed_heap_sort(arr : FixedArraySlice[T]) -> Unit { let len = arr.length()
#| for i = len / 2 - 1; i >= 0; i = i - 1 {
#| fixed_sift_down(arr, i)
#| }
#| for i = len - 1; i > 0; i = i - 1 {
#| arr.swap(0, i)
#| fixed_sift_down(arr.slice(0, i), 0)
#| } }
),
),
"fixed_sift_down": build(
(
#|fn[T : Compare] fixed_sift_down(arr : FixedArraySlice[T], index : Int) -> Unit { let mut index = index
#| let len = arr.length()
#| let mut child = index * 2 + 1
#| while child < len {
#| if child + 1 < len && arr[child] < arr[child + 1] {
#| child = child + 1
#| }
#| if arr[index] >= arr[child] {
#| return
#| }
#| arr.swap(index, child)
#| index = child
#| child = index * 2 + 1
#| } }
),
),
"fixed_test_sort": build(
(
#|fn fixed_test_sort(f : (FixedArray[Int]) -> Unit) -> Unit raise { let arr : FixedArray[_] = [5, 4, 3, 2, 1]
#| f(arr)
#| assert_eq(arr, [1, 2, 3, 4, 5])
#| let arr : FixedArray[_] = [5, 5, 5, 5, 1]
#| f(arr)
#| assert_eq(arr, [1, 5, 5, 5, 5])
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| f(arr)
#| assert_eq(arr, [1, 2, 3, 4, 5])
#| let arr = FixedArray::make(1000, 0)
#| for i in 0..<1000 {
#| arr[i] = 1000 - i - 1
#| }
#| for i = 10; i < 1000; i = i + 10 {
#| arr.swap(i, i - 1)
#| }
#| f(arr)
#| let expected = FixedArray::make(1000, 0)
#| for i in 0..<1000 {
#| expected[i] = i
#| }
#| assert_eq(arr, expected) }
),
),
"is_sorted": build(
(
#|pub fn[T : Compare] FixedArray::is_sorted(arr : FixedArray[T]) -> Bool { for i in 1.. Int { if x > y {
#| y
#| } else {
#| x
#| } }
),
),
"rev_inplace": build(
(
#|pub fn[T] View::rev_inplace(self : View[T]) -> Unit { let mid_len = self.length() / 2
#| for i in 0.. Unit raise?) -> Unit raise? { for v in self {
#| f(v)
#| } }
),
),
"all": build(
(
#|pub fn[T] View::all(self : View[T], f : (T) -> Bool raise?) -> Bool raise? { for v in self {
#| if !f(v) {
#| return false
#| }
#| }
#| true }
),
),
"any": build(
(
#|pub fn[T] View::any(self : View[T], f : (T) -> Bool raise?) -> Bool raise? { for v in self {
#| if f(v) {
#| return true
#| }
#| }
#| false }
),
),
"contains": build(
(
#|pub fn[T : Eq] View::contains(self : View[T], value : T) -> Bool { for v in self {
#| if v == value {
#| break true
#| }
#| } else {
#| false
#| } }
),
),
"iter": build(
(
#|pub fn[A] View::iter(self : View[A]) -> Iter[A] { Iter::new(yield_ => for v in self {
#| guard yield_(v) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }) }
),
),
"iter2": build(
(
#|pub fn[A] View::iter2(self : View[A]) -> Iter2[Int, A] { Iter2::new(yield_ => for i, v in self {
#| guard yield_(i, v) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }) }
),
),
"map": build(
(
#|pub fn[T, U] View::map(self : View[T], f : (T) -> U raise?) -> Array[U] raise? { if self.length() == 0 {
#| return []
#| }
#| Array::makei(self.length(), i => f(self[i])) }
),
),
"map_inplace": build(
(
#|pub fn[T] View::map_inplace(self : View[T], f : (T) -> T raise?) -> Unit raise? { for i, v in self {
#| self[i] = f(v)
#| } }
),
),
"to_array": build(
(
#|pub fn[T] View::to_array(self : View[T]) -> Array[T] { let len = self.length()
#| if len == 0 {
#| []
#| } else {
#| let arr = Array::make(len, self[0])
#| for i, v in self {
#| arr[i] = v
#| }
#| arr
#| } }
),
),
"join": build(
(
#|pub fn View::join(self : ArrayView[String], separator : @string.View) -> String { match self {
#| [] => \"\"
#| [hd, .. tl] => {
#| let mut size_hint = hd.length()
#| for s in tl {
#| size_hint += s.length() + separator.length()
#| }
#| size_hint = size_hint << 1
#| let buf = StringBuilder::new(size_hint~)
#| buf.write_string(hd)
#| if separator is \"\" {
#| for s in tl {
#| buf.write_string(s)
#| }
#| } else {
#| for s in tl {
#| buf.write_substring(
#| separator.data(),
#| separator.start_offset(),
#| separator.length(),
#| )
#| buf.write_string(s)
#| }
#| }
#| buf.to_string()
#| }
#| } }
),
),
"sort": build(
(
#|pub fn[T : Compare] sort(self : Array[T]) -> Unit { let len = self.length()
#| quick_sort(self[:len], None, get_limit(len)) }
),
),
"quick_sort": build(
(
#|fn[T : Compare] quick_sort(arr : ArrayView[T], pred : T?, limit : Int) -> Unit { let mut limit = limit
#| let mut arr = arr
#| let mut pred = pred
#| let mut was_partitioned = true
#| let mut balanced = true
#| let insertion_sort_len = 16
#| while true {
#| let len = arr.length()
#| if len <= insertion_sort_len {
#| if len >= 2 {
#| ArrayView::insertion_sort(arr)
#| }
#| return
#| }
#| // Too many imbalanced partitions may lead to O(n^2) performance in quick sort.
#| // If the limit is reached, use heap sort to ensure O(n log n) performance.
#| if limit == 0 {
#| heap_sort(arr)
#| return
#| }
#| let (pivot_index, likely_sorted) = choose_pivot(arr)
#| // Try bubble sort if the array is likely already sorted.
#| if was_partitioned && balanced && likely_sorted {
#| if try_bubble_sort(arr) {
#| return
#| }
#| }
#| let (pivot, partitioned) = partition(arr, pivot_index)
#| was_partitioned = partitioned
#| balanced = minimum(pivot, len - pivot) >= len / 8
#| if !balanced {
#| limit -= 1
#| }
#| if pred is Some(pred) {
#| // pred is less than all elements in arr
#| // If pivot equals to pred, then we can skip all elements that are equal to pred.
#| if pred == arr[pivot] {
#| let mut i = pivot
#| while i < len && pred == arr[i] {
#| i = i + 1
#| }
#| arr = arr[i:len]
#| continue
#| }
#| }
#| let left = arr[0:pivot]
#| let right = arr[pivot + 1:len]
#| // Reduce the stack depth by only call quick_sort on the smaller partition.
#| if left.length() < right.length() {
#| quick_sort(left, pred, limit)
#| pred = Some(arr[pivot])
#| arr = right
#| } else {
#| quick_sort(right, Some(arr[pivot]), limit)
#| arr = left
#| }
#| } }
),
),
"get_limit": build(
(
#|fn get_limit(len : Int) -> Int { let mut len = len
#| let mut limit = 0
#| while len > 0 {
#| len = len / 2
#| limit += 1
#| }
#| limit }
),
),
"try_bubble_sort": build(
(
#|fn[T : Compare] try_bubble_sort(arr : ArrayView[T]) -> Bool { let max_tries = 8
#| let mut tries = 0
#| for i in 1.. 0 && arr[j - 1] > arr[j]; j = j - 1 {
#| sorted = false
#| arr.swap(j, j - 1)
#| }
#| if !sorted {
#| tries += 1
#| if tries > max_tries {
#| return false
#| }
#| }
#| }
#| true }
),
),
"insertion_sort": build(
(
#|fn[T : Compare] ArrayView::insertion_sort(arr : ArrayView[T]) -> Unit { for i in 1.. 0 && arr[j - 1] > arr[j]; j = j - 1 {
#| arr.swap(j, j - 1)
#| }
#| } }
),
),
"partition": build(
(
#|fn[T : Compare] partition(arr : ArrayView[T], pivot_index : Int) -> (Int, Bool) { arr.swap(pivot_index, arr.length() - 1)
#| let pivot = arr[arr.length() - 1]
#| let mut i = 0
#| let mut partitioned = true
#| for j in 0..<(arr.length() - 1) {
#| if arr[j] < pivot {
#| if i != j {
#| arr.swap(i, j)
#| partitioned = false
#| }
#| i = i + 1
#| }
#| }
#| arr.swap(i, arr.length() - 1)
#| (i, partitioned) }
),
),
"choose_pivot": build(
(
#|fn[T : Compare] choose_pivot(arr : ArrayView[T]) -> (Int, Bool) { let len = arr.length()
#| let use_median_of_medians = 50
#| let max_swaps = 4 * 3
#| let mut swaps = 0
#| let b = len / 4 * 2
#| if len >= 8 {
#| let a = len / 4 * 1
#| let c = len / 4 * 3
#| let sort_2 = (a : Int, b : Int) => if arr[a] > arr[b] {
#| arr.swap(a, b)
#| swaps += 1
#| }
#| let sort_3 = (a : Int, b : Int, c : Int) => {
#| sort_2(a, b)
#| sort_2(b, c)
#| sort_2(a, b)
#| }
#| if len > use_median_of_medians {
#| sort_3(a - 1, a, a + 1)
#| sort_3(b - 1, b, b + 1)
#| sort_3(c - 1, c, c + 1)
#| }
#| sort_3(a, b, c)
#| }
#| if swaps == max_swaps {
#| arr.rev_inplace()
#| (len - b - 1, true)
#| } else {
#| (b, swaps == 0)
#| } }
),
),
"heap_sort": build(
(
#|fn[T : Compare] heap_sort(arr : ArrayView[T]) -> Unit { let len = arr.length()
#| for i = len / 2 - 1; i >= 0; i = i - 1 {
#| sift_down(arr, i)
#| }
#| for i = len - 1; i > 0; i = i - 1 {
#| arr.swap(0, i)
#| sift_down(arr[0:i], 0)
#| } }
),
),
"sift_down": build(
(
#|fn[T : Compare] sift_down(arr : ArrayView[T], index : Int) -> Unit { let mut index = index
#| let len = arr.length()
#| let mut child = index * 2 + 1
#| while child < len {
#| if child + 1 < len && arr[child] < arr[child + 1] {
#| child = child + 1
#| }
#| if arr[index] >= arr[child] {
#| return
#| }
#| arr.swap(index, child)
#| index = child
#| child = index * 2 + 1
#| } }
),
),
"test_sort": build(
(
#|fn test_sort(f : (Array[Int]) -> Unit) -> Unit raise { let arr = [5, 4, 3, 2, 1]
#| f(arr)
#| assert_eq(arr, [1, 2, 3, 4, 5])
#| let arr = [5, 5, 5, 5, 1]
#| f(arr)
#| assert_eq(arr, [1, 5, 5, 5, 5])
#| let arr = [1, 2, 3, 4, 5]
#| f(arr)
#| assert_eq(arr, [1, 2, 3, 4, 5])
#| let arr = Array::new(capacity=1000)
#| for i in 0..<1000 {
#| arr.push(1000 - i - 1)
#| }
#| for i = 10; i < 1000; i = i + 10 {
#| arr.swap(i, i - 1)
#| }
#| f(arr)
#| let expected = Array::new(capacity=1000)
#| for i in 0..<1000 {
#| expected.push(i)
#| }
#| assert_eq(arr, expected) }
),
),
"length": build(
(
#|fn[T] FixedArraySlice::length(self : FixedArraySlice[T]) -> Int { self.end - self.start }
),
),
"op_get": build(
(
#|fn[T] FixedArraySlice::op_get(self : FixedArraySlice[T], index : Int) -> T { self.array[self.start + index] }
),
),
"rev_inplace": build(
(
#|fn[T] FixedArraySlice::rev_inplace(self : FixedArraySlice[T]) -> Unit { let len = self.length()
#| let mid_len = len / 2
#| for i in 0.. Unit, k : Int) -> Double { let ts = monotonic_clock_start()
#| for i in 0.. Unit, count : UInt) -> Summary { let count = count.land(0x7FFFFFFF).reinterpret_as_int()
#| let threshold = 100000.0 // 100 ms
#| let target_batch_size = loop 1 {
#| trial => {
#| let single_us = iter_n_microseconds(inner, trial) / trial.to_double()
#| let target_batch_size = threshold /
#| (if single_us < 1.0 { 1.0 } else { single_us })
#| if trial.to_double() * single_us > threshold {
#| break target_batch_size
#| }
#| continue trial * 2
#| }
#| }
#| let batch_size = if target_batch_size < 1.0 {
#| 1
#| } else {
#| target_batch_size.ceil().to_int()
#| }
#| let samples = Array::makei(count, _ => iter_n_microseconds(inner, batch_size) /
#| batch_size.to_double())
#| samples.sort()
#| winsorize(sorted_data=samples, 5.0)
#| Summary::new(name?, sorted_data=samples, batch_size) }
),
),
"keep": build(
(
#|pub fn[Any] keep(self : T, value : Any) -> Unit { let trait_object : &OpaqueValue = value
#| self._storage = trait_object }
),
),
"dump_summaries": build(
(
#|pub fn dump_summaries(self : T) -> String { \"[\\{self.buffer.to_string()}]\" }
),
),
"monotonic_clock_end": build(
(
#|pub fn monotonic_clock_end(ts : Timestamp) -> Double { let elapsed_secs : Double = instant_elapsed_as_secs_f64(ts)
#| elapsed_secs * 1000000.0 }
),
),
"new": build(
(
#|pub fn new() -> T { let buffer = StringBuilder::new()
#| let summaries = Array::new()
#| { buffer, summaries, _storage: () } }
),
),
"sum": build(
(
#|fn sum(data : Array[Double]) -> Double { let mut sum = 0.0
#| for i in data {
#| sum += i
#| }
#| sum }
),
),
"min": build(
(
#|fn min(sorted_data~ : Array[Double]) -> Double { sorted_data[0] }
),
),
"max": build(
(
#|fn max(sorted_data~ : Array[Double]) -> Double { sorted_data[sorted_data.length() - 1] }
),
),
"mean": build(
(
#|fn mean(data : Array[Double], sum~ : Double) -> Double { let count = data.length()
#| sum / count.to_double() }
),
),
"median": build(
(
#|fn median(sorted_data~ : Array[Double]) -> Double { percentile(sorted_data~, pct=50.0) }
),
),
"variance": build(
(
#|fn variance(data : Array[Double], mean~ : Double) -> Double { if data.length() < 2 {
#| return 0.0
#| }
#| let mut v = 0.0
#| for i in data {
#| let d = i - mean
#| v += d * d
#| }
#| v / (data.length() - 1).to_double() }
),
),
"std_dev": build(
(
#|fn std_dev(variance~ : Double) -> Double { variance.sqrt() }
),
),
"std_dev_pct": build(
(
#|fn std_dev_pct(mean~ : Double, std_dev~ : Double) -> Double { if mean == 0.0 {
#| return 0.0
#| }
#| std_dev / mean * 100.0 }
),
),
"median_abs_dev": build(
(
#|fn median_abs_dev(data : Array[Double], median_~ : Double) -> Double { let abs_devs = data.map(x => (median_ - x).abs())
#| abs_devs.sort()
#| // https://en.wikipedia.org/wiki/Median_absolute_deviation
#| median(sorted_data=abs_devs) * 1.4826 }
),
),
"median_abs_dev_pct": build(
(
#|fn median_abs_dev_pct(median~ : Double, median_abs_dev~ : Double) -> Double { if median == 0.0 {
#| return 0.0
#| }
#| median_abs_dev / median * 100.0 }
),
),
"quartiles": build(
(
#|fn quartiles(sorted_data~ : Array[Double]) -> (Double, Double, Double) { let q1 = percentile(sorted_data~, pct=25.0)
#| let q2 = percentile(sorted_data~, pct=50.0)
#| let q3 = percentile(sorted_data~, pct=75.0)
#| (q1, q2, q3) }
),
),
"iqr": build(
(
#|fn iqr(quartiles~ : (Double, Double, Double)) -> Double { let (q1, _, q3) = quartiles
#| q3 - q1 }
),
),
"percentile": build(
(
#|fn percentile(sorted_data~ : Array[Double], pct~ : Double) -> Double { guard sorted_data.length() > 0
#| guard pct >= 0.0 && pct <= 100.0
#| if sorted_data.length() == 1 {
#| return sorted_data[0]
#| }
#| if pct == 100.0 {
#| return sorted_data[sorted_data.length() - 1]
#| }
#| let length = (sorted_data.length() - 1).to_double()
#| let rank = pct / 100 * length
#| let lrank = rank.floor()
#| let d = rank - lrank
#| let n = lrank.to_int()
#| let lo = sorted_data[n]
#| let hi = sorted_data[n + 1]
#| lo + (hi - lo) * d }
),
),
"winsorize": build(
(
#|fn winsorize(sorted_data~ : Array[Double], pct : Double) -> Unit { let lo = percentile(sorted_data~, pct~)
#| let hi = percentile(sorted_data~, pct=100.0 - pct)
#| for i, samp in sorted_data {
#| if samp > hi {
#| sorted_data[i] = hi
#| } else if samp < lo {
#| sorted_data[i] = lo
#| }
#| } }
),
),
}
},
)
///|
let moonbitlang_core_bigint_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/bigint",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/char": moonbitlang_core_char_module,
"moonbitlang/core/uint": moonbitlang_core_uint_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module,
"moonbitlang/core/string": moonbitlang_core_string_module,
},
fn(_env, build) {
{
"radix_bit_len": (None, Int(32)),
"decimal_ratio": (None, String("0.302 // log10(2)")),
"karatsuba_threshold": (None, Int(50)),
"from_int": build(
(
#|pub fn BigInt::from_int(n : Int) -> BigInt { BigInt::from_int64(n.to_int64()) }
),
),
"from_uint": build(
(
#|pub fn BigInt::from_uint(n : UInt) -> BigInt { BigInt::from_uint64(n.to_uint64()) }
),
),
"from_int64": build(
(
#|pub fn BigInt::from_int64(n : Int64) -> BigInt { if n < 0L {
#| -BigInt::from_uint64((-n).reinterpret_as_uint64())
#| } else {
#| BigInt::from_uint64(n.reinterpret_as_uint64())
#| } }
),
),
"from_uint64": build(
(
#|pub fn BigInt::from_uint64(n : UInt64) -> BigInt { if n == 0UL {
#| return { limbs: FixedArray::make(1, 0), sign: Positive, len: 1 }
#| }
#| let limbs = FixedArray::make(64 / radix_bit_len, 0U)
#| let mut m = n
#| let mut i = 0
#| while m > 0 {
#| limbs[i] = (m % radix).to_uint()
#| m /= radix
#| i += 1
#| }
#| { limbs, sign: Positive, len: i } }
),
),
"grade_school_mul": build(
(
#|fn BigInt::grade_school_mul(self : BigInt, other : BigInt) -> BigInt { let self_len = self.len
#| let other_len = other.len
#| let mut len = self_len + other_len
#| let limbs = FixedArray::make(len, 0U)
#| for i in 0.. BigInt { let half = (max(self.len, other.len) + 1) / 2
#| let (xl, xh) = self.split(half)
#| let (yl, yh) = other.split(half)
#| let p1 = xh * yh
#| let p2 = xl * yl
#| let p3 = (xh + xl) * (yh + yl)
#| (p1 << (radix_bit_len * 2 * half)) +
#| ((p3 - p1 - p2) << (radix_bit_len * half)) +
#| p2 }
),
),
"split": build(
(
#|fn BigInt::split(self : BigInt, half : Int) -> (BigInt, BigInt) { if self.len <= half {
#| return ({ ..self, sign: Positive }, zero)
#| }
#| let lower_len = for i = half - 1; i > 0; i = i - 1 {
#| if self.limbs[i] > 0 {
#| break i + 1
#| }
#| } else {
#| 1
#| }
#| let lower = FixedArray::make(lower_len, 0U)
#| lower.unsafe_blit(0, self.limbs, 0, lower_len)
#| let upper = FixedArray::make(self.len - half, 0U)
#| upper.unsafe_blit(0, self.limbs, half, self.len - half)
#| (
#| { limbs: lower, sign: Positive, len: lower_len },
#| { limbs: upper, sign: Positive, len: self.len - half },
#| ) }
),
),
"grade_school_div": build(
(
#|fn BigInt::grade_school_div(self : BigInt, other : BigInt) -> (BigInt, BigInt) { // Handle edge cases
#| if self < other {
#| return (zero, self)
#| } else if self == other {
#| return (one, zero)
#| }
#| if other.len == 1 {
#| let number = other.limbs[0]
#| let ret = self.copy()
#| if number == 1 {
#| return (ret, zero)
#| }
#| let a = ret.limbs
#| let x = number.to_uint64()
#| let mut y = 0UL
#| for i = self.len - 1; i >= 0; i = i - 1 {
#| y = y << radix_bit_len
#| y += a[i].to_uint64()
#| a[i] = ((y / x) & radix_mask).to_uint()
#| y %= x
#| }
#| if ret.limbs[ret.len - 1] == 0 {
#| return (
#| { ..ret, len: ret.len - 1 },
#| { limbs: FixedArray::make(1, y.to_uint()), sign: Positive, len: 1 },
#| )
#| }
#| return (
#| ret,
#| { limbs: FixedArray::make(1, y.to_uint()), sign: Positive, len: 1 },
#| )
#| }
#| // Cite: TAOCP Vol. 2, 4.3.1
#| let dividend = self
#| let divisor = other
#| // D1. normalize
#| // m = dividend.len - divisor.len
#| // left shift dividend & divisor such that
#| // - b[b.length() - 1] >= radix / 2
#| // - a.length() == self.len + 1
#| // where a and b represent the limbs of the adjusted dividend and divisor
#| let lshift = max(
#| 0,
#| radix_bit_len - (64 - divisor.limbs[divisor.len - 1].to_int64().clz()),
#| )
#| let a_len = dividend.len
#| let dividend = dividend << lshift
#| let divisor = divisor << lshift
#| let b_len = divisor.len
#| let b = FixedArray::make(b_len, 0UL)
#| for i in 0.. i {
#| a[i] = dividend.limbs[i].to_uint64()
#| }
#| }
#| // invariant : divisor.limbs.last() >= radix / 2
#| // if b[b_len - 1] < radix / 2 {
#| // panic()
#| // }
#| let a_len = a_len + 1
#| // a is the adjusted dividend and b is the adjusted divisor
#| let v1 = b[b_len - 1]
#| let v2 = b[b_len - 2]
#| let q = FixedArray::make(a_len - b_len, 0U)
#| // D2 - D7 loop through m to 0
#| for i = q.length() - 1; i >= 0; i = i - 1 {
#| let u0 = a[i + b_len]
#| let u1 = a[i + b_len - 1]
#| let u2 = a[i + b_len - 2]
#| // D3 compute qh
#| let mut qh = (u0 * radix + u1) / v1
#| if qh * v2 > radix * (u0 * radix + u1 - qh * v1) + u2 {
#| qh -= 1
#| }
#| // D4 divident = divident - qh * divisor
#| let mut borrow = 0L
#| let mut carry = 0UL
#| for j in 0..> radix_bit_len
#| carry = carry >> radix_bit_len
#| }
#| borrow = borrow + a[i + b_len].reinterpret_as_int64()
#| borrow -= carry.reinterpret_as_int64()
#| a[i + b_len] = (borrow & radix_mask.reinterpret_as_int64()).reinterpret_as_uint64()
#| borrow = borrow >> radix_bit_len
#| if borrow < 0L {
#| carry = 0UL
#| for j in 0..> radix_bit_len
#| }
#| carry += a[i + b_len]
#| a[i + b_len] = carry & radix_mask
#| carry = carry >> radix_bit_len
#| borrow += carry.reinterpret_as_int64()
#| qh -= 1
#| }
#| q[i] = qh.to_uint()
#| }
#| let len = if q[q.length() - 1] == 0 { q.length() - 1 } else { q.length() }
#| // strip leading zeros
#| let mut i = a.length() - 1
#| while i >= 0 && a[i] == 0 {
#| i -= 1
#| }
#| if i < 0 {
#| i = 1
#| } else {
#| i += 1
#| }
#| let modulo = FixedArray::make(i, 0U)
#| for j in 0..> lshift) }
),
),
"is_zero": build(
(
#|pub fn BigInt::is_zero(self : BigInt) -> Bool { self.len == 1 && self.limbs[0] == 0 }
),
),
"to_string": build(
(
#|pub fn BigInt::to_string(self : BigInt) -> String { // This function first converts the BigInt to a decimal representation, with a radix of 2^(`decimal_radix_bit_len`).
#| // Then it converts the decimal representation to a string slot by slot.
#| if self.is_zero() {
#| return \"0\"
#| }
#| let decimal_radix_bit_len = 19 - 1 - (1 + radix_bit_len) / 3 // < len(9,223,372,036,854,775,807) - len(2^radix_bit_len). len means the number of digits in decimal.
#| let decimal_mask = 10_000_000L // 10^(decimal_radix_bit_len). TODO: compute it when we have power function.
#| // The following value should fit well into an Int without precision loss.
#| // This is an approximation of the number of slots needed to represent the decimal value.
#| let decimal_len = unchecked_double_to_int(
#| (self.len * radix_bit_len).to_double() *
#| decimal_ratio /
#| decimal_radix_bit_len.to_double() +
#| 1,
#| )
#| let s = if self.sign == Negative { \"-\" } else { \"\" }
#| let v = Array::make(decimal_len, 0L)
#| let mut v_idx = 0
#| for i = self.len - 1; i >= 0; i = i - 1 {
#| let mut x = self.limbs[i].to_int64()
#| for j in 0.. 0L {
#| v[v_idx] = x % decimal_mask
#| v_idx += 1
#| x /= decimal_mask
#| }
#| }
#| let mut ret = \"\"
#| for i in 0..<(v_idx - 1) {
#| for j in 0.. 0L {
#| let y = x % 10L
#| x /= 10L
#| ret = y.to_string() + ret
#| }
#| s + ret }
),
),
"from_string": build(
(
#|pub fn BigInt::from_string(input : String) -> BigInt { let len = input.length()
#| if len == 0 {
#| abort(\"empty string\")
#| }
#| let sign : Sign = if input.unsafe_charcode_at(0) == '-' {
#| Negative
#| } else {
#| Positive
#| }
#| let mut b_len = (
#| unchecked_double_to_int(len.to_double() / decimal_ratio) +
#| 1 +
#| radix_bit_len
#| ) /
#| radix_bit_len +
#| 1
#| let b = FixedArray::make(b_len, 0U)
#| for
#| i in (match sign {
#| Negative => 1
#| Positive => 0
#| }).. 9 {
#| abort(\"invalid character\")
#| }
#| let mut carry = x.reinterpret_as_uint().to_uint64()
#| for j in 0.. 1 {
#| b_len -= 1
#| }
#| { limbs: b, sign, len: b_len } }
),
),
"from_hex": build(
(
#|pub fn BigInt::from_hex(input : String) -> BigInt { // WARN: this implementation assumes that `radix_bit_len` is a multiple of 4.
#| fn char_from_hex(x : Int) -> UInt {
#| (match x {
#| '0'..='9' => x - '0'
#| 'A'..='F' => x + (10 - 'A')
#| 'a'..='f' => x + (10 - 'a')
#| _ => abort(\"invalid character\")
#| }).reinterpret_as_uint()
#| }
#| let len = input.length()
#| if len == 0 {
#| abort(\"empty string\")
#| }
#| let (sign, number_len) = if input.unsafe_charcode_at(0) == '-' {
#| (Negative, len - 1)
#| } else {
#| (Positive, len)
#| }
#| let nb_char = radix_bit_len / 4 // number of char per limb
#| let quotient = number_len / nb_char
#| let mod = number_len % nb_char
#| let mut b_len = if mod == 0 { quotient } else { quotient + 1 }
#| let b = FixedArray::make(b_len, 0U)
#| if mod != 0 {
#| let start = len - quotient * nb_char - mod
#| for i in 0.. 1 {
#| b_len -= 1
#| }
#| { limbs: b, sign, len: b_len } }
),
),
"to_hex": build(
(
#|pub fn BigInt::to_hex(self : BigInt, uppercase~ : Bool = true) -> String { if self.is_zero() {
#| return \"0\"
#| }
#| // WARN: this implementation assumes that `radix_bit_len` is a multiple of 4.
#| let digits_per_limb = radix_bit_len / 4
#| let buf = if self.sign is Negative {
#| let builder = StringBuilder::new(size_hint=self.len * digits_per_limb + 2)
#| builder.write_char('-')
#| builder
#| } else {
#| StringBuilder::new(size_hint=self.len * digits_per_limb)
#| }
#| for i = self.len - 1; i >= 0; i = i - 1 { // TODO: reverse iteration would be a bit faster.
#| // split the limb into 4-bit chunks
#| let mut x = self.limbs[i]
#| let digits = FixedArray::make(digits_per_limb, '0')
#| let mut idx = 0
#| while x > 0 {
#| let y = x % 16
#| x /= 16
#| digits[idx] = if y < 10 {
#| (y.reinterpret_as_int() + '0'.to_int()).unsafe_to_char()
#| } else if uppercase {
#| (y.reinterpret_as_int() - 10 + 'A'.to_int()).unsafe_to_char()
#| } else {
#| (y.reinterpret_as_int() - 10 + 'a'.to_int()).unsafe_to_char()
#| }
#| idx += 1
#| }
#| if i != self.len - 1 {
#| idx = digits_per_limb
#| }
#| for j in 0.. BigInt { let new_limbs = FixedArray::make(self.len, 0U)
#| new_limbs.unsafe_blit(0, self.limbs, 0, self.len)
#| { limbs: new_limbs, sign: self.sign, len: self.len } }
),
),
"max": build(
(
#|fn[T : Compare] max(a : T, b : T) -> T { if a > b {
#| a
#| } else {
#| b
#| } }
),
),
"pow": build(
(
#|pub fn BigInt::pow(self : BigInt, exp : BigInt, modulus? : BigInt) -> BigInt { if exp.sign == Negative {
#| abort(\"negative exponent\")
#| }
#| match modulus {
#| None => {
#| let mut result = 1N
#| let mut base = self
#| let mut exp = exp
#| while exp > 0 {
#| if exp % 2 == 1 {
#| result = result * base
#| }
#| base = base * base
#| exp = exp / 2
#| }
#| result
#| }
#| Some(modulus) => {
#| guard !(modulus.is_zero() || modulus.sign == Negative)
#| let mut result = 1N
#| let mut base = self
#| let mut exp = exp
#| while exp > 0 {
#| if exp % 2 == 1 {
#| result = result * base % modulus
#| }
#| base = base * base % modulus
#| exp = exp / 2
#| }
#| result
#| }
#| } }
),
),
"from_octets": build(
(
#|pub fn BigInt::from_octets(input : Bytes, signum~ : Int = 1) -> BigInt { let len = input.length() // number of bytes
#| if signum == 0 {
#| return zero
#| } else if signum < 0 {
#| return -BigInt::from_octets(input)
#| }
#| if len == 0 {
#| abort(\"empty octet string\")
#| }
#| let div = len * 8 / radix_bit_len
#| let mod = len * 8 % radix_bit_len // number of bits in the first limb
#| let limbs_len = if mod == 0 { div } else { div + 1 }
#| let limbs = FixedArray::make(limbs_len, 0U)
#| // head at most significant limb
#| for i in 0..<(mod / 8) {
#| limbs[limbs_len - 1] = (limbs[limbs_len - 1] << 8) | input[i].to_uint()
#| }
#| let byte_per_limb = radix_bit_len / 8
#| // tail
#| for i in 0.. Bytes { let length = match length {
#| None => 1
#| Some(l) => if l <= 0 { abort(\"negative length\") } else { l }
#| }
#| if self.is_zero() {
#| return Bytes::new(max(1, length))
#| }
#| if self.sign == Negative {
#| abort(\"negative BigInt\")
#| }
#| let head_bits = 32 - self.limbs[self.len - 1].reinterpret_as_int().clz()
#| let tail_len = self.len - 1
#| let len = (head_bits + 7) / 8 + tail_len * (radix_bit_len / 8)
#| let len = max(length, len)
#| let result = FixedArray::make(len, Byte::default())
#| for i = 0; i < len && i / 4 < self.len; i = i + 1 {
#| result[len - 1 - i] = ((self.limbs[i / 4] >> (i % 4 * 8)) & 0xffU)
#| .reinterpret_as_int()
#| .to_byte()
#| }
#| unsafe_fixedarray_to_bytes(result) }
),
),
"to_int": build(
(
#|pub fn BigInt::to_int(self : BigInt) -> Int { self.to_uint().reinterpret_as_int() }
),
),
"to_uint": build(
(
#|pub fn BigInt::to_uint(self : BigInt) -> UInt { let value = if self.sign == Negative { (1N << 32) + self } else { self }
#| value.limbs[0] }
),
),
"to_int64": build(
(
#|pub fn BigInt::to_int64(self : BigInt) -> Int64 { self.to_uint64().reinterpret_as_int64() }
),
),
"to_uint64": build(
(
#|pub fn BigInt::to_uint64(self : BigInt) -> UInt64 { let value = if self.sign == Negative { (1N << 64) + self } else { self }
#| let len = 64 / radix_bit_len
#| let len = if value.len < len { value.len } else { len }
#| let mut result = 0UL
#| for i = len - 1; i >= 0; i = i - 1 {
#| result = result << radix_bit_len
#| result = result | (value.limbs[i].to_uint64() & radix_mask)
#| }
#| result }
),
),
"bit_length": build(
(
#|pub fn BigInt::bit_length(self : BigInt) -> Int { if self.len == 0 {
#| return 0
#| }
#| let mut bit_length = (self.len - 1) * radix_bit_len +
#| (radix_bit_len - self.limbs[self.len - 1].clz())
#| if self.sign == Negative {
#| // check if this number is a power of two
#| let mut pow2 = self.limbs[0].popcnt() == 1
#| for i = 1; i < self.len && pow2; i = i + 1 {
#| pow2 = self.limbs[i] == 0
#| }
#| if pow2 {
#| bit_length -= 1
#| }
#| }
#| bit_length }
),
),
"ctz": build(
(
#|pub fn BigInt::ctz(self : BigInt) -> Int { if self.is_zero() {
#| return 0
#| }
#| // Find first non-zero limb
#| let mut i = 0
#| while i < self.len && self.limbs[i] == 0 {
#| i = i + 1
#| }
#| radix_bit_len * i + self.limbs[i].ctz() }
),
),
"can_convert_to_int": build(
(
#|fn can_convert_to_int(x : BigInt) -> Bool { // bigint range from [-(2^32 - 1), 2^32 - 1] has len == 1. But here we only
#| // want bigint from [-2^31, 2^31 - 1]
#| x.len == 1 &&
#| (if x.sign == Negative {
#| x.limbs[0] <= 0x80000000
#| } else {
#| x.limbs[0] < 0x80000000
#| }) }
),
),
"can_convert_to_int64": build(
(
#|fn can_convert_to_int64(x : BigInt) -> Bool { x.len <= 2 &&
#| (if x.sign == Negative {
#| x.limbs[1] < 0x80000000 || (x.limbs[1] == 0x80000000 && x.limbs[0] == 0)
#| } else {
#| x.limbs[1] < 0x80000000
#| }) }
),
),
"is_neg": build(
(
#|fn is_neg(x : BigInt) -> Bool { x.sign == Negative }
),
),
"limbs": build(
(
#|fn BigInt::limbs(self : Self) -> Iter[UInt] { self.limbs.iter().take(self.len) }
),
),
"zero": (None, BigInt(0N)),
"from_string": build(
(
#|pub fn BigInt::from_string(str : String) -> BigInt { if str.length() == 0 {
#| abort(\"empty string\")
#| }
#| BigInt::js_from_string(str) }
),
),
"from_octets": build(
(
#|pub fn BigInt::from_octets(octets : Bytes, signum~ : Int = 1) -> BigInt { if signum < 0 {
#| return -1N * BigInt::from_octets(octets, signum=1)
#| }
#| if signum == 0 {
#| return 0N
#| }
#| let str = StringBuilder::new()
#| str.write_string(\"0x\")
#| for octet in octets {
#| str.write_string(hex2(octet))
#| }
#| BigInt::from_string(str.to_string()) }
),
),
"to_octets": build(
(
#|pub fn BigInt::to_octets(self : BigInt, length? : Int) -> Bytes { if self < 0 {
#| abort(\"negative BigInt\")
#| }
#| if self == 0 {
#| return match length {
#| Some(len) => Bytes::make(len, 0)
#| None => [0]
#| }
#| }
#| let buf = []
#| loop self {
#| v =>
#| if v > 0 {
#| buf.push(v.to_byte())
#| continue v >> 8
#| }
#| }
#| let buf_len = buf.length()
#| match length {
#| Some(len) => {
#| if len <= 0 {
#| abort(\"negative length\")
#| }
#| if len > buf_len {
#| Bytes::makei(len, i => {
#| let padding = len - buf_len
#| if i < padding {
#| 0
#| } else {
#| buf[buf_len - (i - padding) - 1]
#| }
#| })
#| } else {
#| Bytes::makei(buf_len, i => buf[buf_len - i - 1])
#| }
#| }
#| None => Bytes::makei(buf_len, i => buf[buf_len - i - 1])
#| } }
),
),
"to_uint64": build(
(
#|pub fn BigInt::to_uint64(self : BigInt) -> UInt64 { let hi = (self >> 32).to_uint()
#| let lo = self.to_uint()
#| (hi.to_uint64() << 32) | lo.to_uint64() }
),
),
"to_int64": build(
(
#|pub fn BigInt::to_int64(self : BigInt) -> Int64 { let hi = (self >> 32).to_uint()
#| let lo = self.to_uint()
#| (hi.to_int64() << 32) | lo.to_int64() }
),
),
"limbs": build(
(
#|fn BigInt::limbs(self : Self) -> Iter[UInt] { guard !self.is_zero() else { Iter::singleton(0) }
#| Iter::new(yield_ => for n = self * BigInt::from_int(self.signum())
#| n > 0
#| n = n >> 32 {
#| let limb = n.to_uint()
#| guard yield_(limb) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }) }
),
),
"asr": build(
(
#|pub fn BigInt::asr(self : BigInt, n : Int) -> BigInt { self >> n }
),
),
"shl": build(
(
#|pub fn BigInt::shl(self : BigInt, n : Int) -> BigInt { self << n }
),
),
"lsl": build(
(
#|pub fn BigInt::lsl(self : BigInt, n : Int) -> BigInt { self << n }
),
),
"shr": build(
(
#|pub fn BigInt::shr(self : BigInt, n : Int) -> BigInt { self >> n }
),
),
"equal_int": build(
(
#|pub fn BigInt::equal_int(self : BigInt, other : Int) -> Bool { can_convert_to_int(self) && self.to_int() == other }
),
),
"equal_int64": build(
(
#|pub fn BigInt::equal_int64(self : BigInt, other : Int64) -> Bool { can_convert_to_int64(self) && self.to_int64() == other }
),
),
"compare_int": build(
(
#|pub fn BigInt::compare_int(self : BigInt, other : Int) -> Int { guard can_convert_to_int(self) else {
#| return if is_neg(self) { -1 } else { 1 }
#| }
#| let self = self.to_int()
#| Int::compare(self, other) }
),
),
"compare_int64": build(
(
#|pub fn BigInt::compare_int64(self : BigInt, other : Int64) -> Int { guard can_convert_to_int64(self) else {
#| return if is_neg(self) { -1 } else { 1 }
#| }
#| let self = self.to_int64()
#| Int64::compare(self, other) }
),
),
"signum": build(
(
#|fn BigInt::signum(self : Self) -> Int { if self.is_zero() {
#| 0
#| } else if is_neg(self) {
#| -1
#| } else {
#| 1
#| } }
),
),
"to_uint16": build(
(
#|pub fn BigInt::to_uint16(self : BigInt) -> UInt16 { self.to_int().to_uint16() }
),
),
"to_int16": build(
(
#|pub fn BigInt::to_int16(self : BigInt) -> Int16 { self.to_int().to_int16() }
),
),
}
},
)
///|
let moonbitlang_core_bool_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/bool",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
fn(_env, build) {
{
"to_int": build(
(
#|pub fn to_int(self : Bool) -> Int { if self {
#| 1
#| } else {
#| 0
#| } }
),
),
"to_int64": build(
(
#|pub fn to_int64(self : Bool) -> Int64 { if self {
#| 1
#| } else {
#| 0
#| } }
),
),
"to_uint": build(
(
#|pub fn to_uint(self : Bool) -> UInt { if self {
#| 1
#| } else {
#| 0
#| } }
),
),
"to_uint64": build(
(
#|pub fn to_uint64(self : Bool) -> UInt64 { if self {
#| 1
#| } else {
#| 0
#| } }
),
),
"to_uint16": build(
(
#|pub fn to_uint16(self : Bool) -> UInt16 { if self {
#| 1
#| } else {
#| 0
#| } }
),
),
"to_int16": build(
(
#|pub fn to_int16(self : Bool) -> Int16 { if self {
#| 1
#| } else {
#| 0
#| } }
),
),
}
},
)
///|
let moonbitlang_core_buffer_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/buffer",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/bytes": moonbitlang_core_bytes_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/string": moonbitlang_core_string_module,
},
fn(_env, build) {
{
"grow_if_necessary": build(
(
#|fn grow_if_necessary(self : T, required : Int) -> Unit { let start = if self.data.length() <= 0 { 1 } else { self.data.length() }
#| let enough_space = for space = start {
#| if space >= required {
#| break space
#| }
#| continue space * 2
#| }
#| if enough_space != self.data.length() {
#| let new_data = FixedArray::make(enough_space, Byte::default())
#| new_data.unsafe_blit(0, self.data, 0, self.len)
#| self.data = new_data
#| } }
),
),
"length": build(
(
#|pub fn length(self : T) -> Int { self.len }
),
),
"is_empty": build(
(
#|pub fn is_empty(self : T) -> Bool { self.len == 0 }
),
),
"contents": build(
(
#|pub fn contents(self : T) -> Bytes { @bytes.from_fixedarray(self.data, len=self.len) }
),
),
"new": build(
(
#|pub fn new(size_hint~ : Int = 0) -> T { let initial = if size_hint < 1 { 1 } else { size_hint }
#| let data = FixedArray::make(initial, Byte::default())
#| { data, len: 0, initial_data: data } }
),
),
"from_bytes": build(
(
#|pub fn from_bytes(bytes : Bytes) -> T { let val_len = bytes.length()
#| let buf = new(size_hint=val_len)
#| // inline write_bytes, skip grow_if_necessary check
#| // SAFETY: known bytes size
#| buf.data.blit_from_bytes(0, bytes, 0, val_len)
#| buf.len = val_len
#| buf }
),
),
"from_array": build(
(
#|pub fn from_array(arr : Array[Byte]) -> T { let buf = new(size_hint=arr.length())
#| for byte in arr {
#| // inline write_byte, skip grow_if_necessary check
#| // SAFETY: known array size
#| buf.data[buf.len] = byte
#| buf.len += 1
#| }
#| buf }
),
),
"from_iter": build(
(
#|pub fn from_iter(iter : Iter[Byte]) -> T { let buf = new()
#| let mut capacity = buf.data.length()
#| for byte in iter {
#| // inline write_byte and grow_if_necessary
#| // only call grow_if_necessary when necessary
#| if buf.len == capacity {
#| buf.grow_if_necessary(capacity + 1)
#| capacity = buf.data.length()
#| }
#| buf.data[buf.len] = byte
#| buf.len += 1
#| }
#| buf }
),
),
"write_uint64_be": build(
(
#|pub fn write_uint64_be(self : T, value : UInt64) -> Unit { self.write_byte((value >> 56).to_byte())
#| self.write_byte((value >> 48).to_byte())
#| self.write_byte((value >> 40).to_byte())
#| self.write_byte((value >> 32).to_byte())
#| self.write_byte((value >> 24).to_byte())
#| self.write_byte((value >> 16).to_byte())
#| self.write_byte((value >> 8).to_byte())
#| self.write_byte(value.to_byte()) }
),
),
"write_uint64_le": build(
(
#|pub fn write_uint64_le(self : T, value : UInt64) -> Unit { self.write_byte(value.to_byte())
#| self.write_byte((value >> 8).to_byte())
#| self.write_byte((value >> 16).to_byte())
#| self.write_byte((value >> 24).to_byte())
#| self.write_byte((value >> 32).to_byte())
#| self.write_byte((value >> 40).to_byte())
#| self.write_byte((value >> 48).to_byte())
#| self.write_byte((value >> 56).to_byte()) }
),
),
"write_int64_be": build(
(
#|pub fn write_int64_be(self : T, value : Int64) -> Unit { self.write_uint64_be(value.reinterpret_as_uint64()) }
),
),
"write_int64_le": build(
(
#|pub fn write_int64_le(self : T, value : Int64) -> Unit { self.write_uint64_le(value.reinterpret_as_uint64()) }
),
),
"write_uint_be": build(
(
#|pub fn write_uint_be(self : T, value : UInt) -> Unit { self.write_byte((value >> 24).to_byte())
#| self.write_byte((value >> 16).to_byte())
#| self.write_byte((value >> 8).to_byte())
#| self.write_byte(value.to_byte()) }
),
),
"write_uint_le": build(
(
#|pub fn write_uint_le(self : T, value : UInt) -> Unit { self.write_byte(value.to_byte())
#| self.write_byte((value >> 8).to_byte())
#| self.write_byte((value >> 16).to_byte())
#| self.write_byte((value >> 24).to_byte()) }
),
),
"write_int_be": build(
(
#|pub fn write_int_be(self : T, value : Int) -> Unit { self.write_uint_be(value.reinterpret_as_uint()) }
),
),
"write_int_le": build(
(
#|pub fn write_int_le(self : T, value : Int) -> Unit { self.write_uint_le(value.reinterpret_as_uint()) }
),
),
"write_double_be": build(
(
#|pub fn write_double_be(self : T, value : Double) -> Unit { self.write_uint64_be(value.reinterpret_as_uint64()) }
),
),
"write_double_le": build(
(
#|pub fn write_double_le(self : T, value : Double) -> Unit { self.write_uint64_le(value.reinterpret_as_uint64()) }
),
),
"write_float_be": build(
(
#|pub fn write_float_be(self : T, value : Float) -> Unit { self.write_uint_be(value.reinterpret_as_uint()) }
),
),
"write_float_le": build(
(
#|pub fn write_float_le(self : T, value : Float) -> Unit { self.write_uint_le(value.reinterpret_as_uint()) }
),
),
"write_object": build(
(
#|pub fn write_object(self : T, value : &Show) -> Unit { self.write_string(value.to_string()) }
),
),
"write_bytes": build(
(
#|pub fn write_bytes(self : T, value : Bytes) -> Unit { let val_len = value.length()
#| self.grow_if_necessary(self.len + val_len)
#| self.data.blit_from_bytes(self.len, value, 0, val_len)
#| self.len += val_len }
),
),
"write_bytesview": build(
(
#|pub fn write_bytesview(self : T, value : @bytes.View) -> Unit { let val_len = value.length()
#| self.grow_if_necessary(self.len + val_len)
#| self.data.blit_from_bytes(
#| self.len,
#| value.data(),
#| value.start_offset(),
#| value.length(),
#| )
#| self.len += val_len }
),
),
"write_stringview": build(
(
#|pub fn write_stringview(self : T, value : @string.View) -> Unit { let len = value.length()
#| self.grow_if_necessary(self.len + len * 2)
#| for i = 0, j = self.len; i < len; i = i + 1, j = j + 2 {
#| let c = value.unsafe_charcode_at(i).reinterpret_as_uint()
#| self.data[j] = (c & 0xff).to_byte()
#| self.data[j + 1] = (c >> 8).to_byte()
#| }
#| self.len += len * 2 }
),
),
"write_byte": build(
(
#|pub fn write_byte(self : T, value : Byte) -> Unit { self.grow_if_necessary(self.len + 1)
#| self.data[self.len] = value
#| self.len += 1 }
),
),
"write_iter": build(
(
#|pub fn write_iter(self : T, iter : Iter[Byte]) -> Unit { for byte in iter {
#| self.write_byte(byte)
#| } }
),
),
"reset": build(
(
#|pub fn reset(self : T) -> Unit { self.data = self.initial_data
#| self.len = 0 }
),
),
"to_bytes": build(
(
#|pub fn to_bytes(self : T) -> Bytes { @bytes.from_fixedarray(self.data, len=self.len) }
),
),
}
},
)
///|
let moonbitlang_core_builtin_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/builtin",
deps={ "moonbitlang/core/abort": moonbitlang_core_abort_module },
fn(_env, build) {
{
"run": build(
(
#|pub fn[T] Iter::run(self : Iter[T], f : (T) -> IterResult) -> IterResult { self(f) }
),
),
"just_run": build(
(
#|pub fn[T] Iter::just_run(self : Iter[T], f : (T) -> IterResult) -> Unit { self(f) |> ignore }
),
),
"each": build(
(
#|pub fn[T] Iter::each(self : Iter[T], f : (T) -> Unit raise?) -> Unit raise? { for a in self {
#| f(a)
#| } }
),
),
"any": build(
(
#|pub fn[T] Iter::any(self : Iter[T], f : (T) -> Bool) -> Bool { self.run(k => if f(k) { IterEnd } else { IterContinue }) != IterContinue }
),
),
"all": build(
(
#|pub fn[T] Iter::all(self : Iter[T], f : (T) -> Bool) -> Bool { self.run(k => if !f(k) { IterEnd } else { IterContinue }) == IterContinue }
),
),
"count": build(
(
#|pub fn[T] Iter::count(self : Iter[T]) -> Int { self.fold((acc, _) => acc + 1, init=0) }
),
),
"new": build(
(
#|pub fn[T] Iter::new(f : ((T) -> IterResult) -> IterResult) -> Iter[T] { Iter(f) }
),
),
"empty": build(
(
#|pub fn[T] Iter::empty() -> Iter[T] { _ => IterContinue }
),
),
"singleton": build(
(
#|pub fn[T] Iter::singleton(a : T) -> Iter[T] { yield_ => yield_(a) }
),
),
"repeat": build(
(
#|pub fn[T] Iter::repeat(a : T) -> Iter[T] { yield_ => loop yield_(a) {
#| IterContinue => continue yield_(a)
#| IterEnd => IterEnd
#| } }
),
),
"filter": build(
(
#|pub fn[T] Iter::filter(self : Iter[T], f : (T) -> Bool) -> Iter[T] { yield_ => self.run(a => if f(a) { yield_(a) } else { IterContinue }) }
),
),
"map": build(
(
#|pub fn[T, R] Iter::map(self : Iter[T], f : (T) -> R) -> Iter[R] { yield_ => self.run(a => yield_(f(a))) }
),
),
"mapi": build(
(
#|pub fn[T, R] Iter::mapi(self : Iter[T], f : (Int, T) -> R) -> Iter[R] { yield_ => {
#| let mut i = -1
#| self.run(a => {
#| i = i + 1
#| yield_(f(i, a))
#| })
#| } }
),
),
"filter_map": build(
(
#|pub fn[A, B] Iter::filter_map(self : Iter[A], f : (A) -> B?) -> Iter[B] { yield_ => self.run(a => match f(a) {
#| Some(b) => yield_(b)
#| None => IterContinue
#| }) }
),
),
"map_option": build(
(
#|pub fn[A, B] Iter::map_option(self : Iter[A], f : (A) -> B?) -> Iter[B] { self.filter_map(f) }
),
),
"flat_map": build(
(
#|pub fn[T, R] Iter::flat_map(self : Iter[T], f : (T) -> Iter[R]) -> Iter[R] { yield_ => self.run(x => f(x).run(yield_)) }
),
),
"flatten": build(
(
#|pub fn[T] Iter::flatten(self : Iter[Iter[T]]) -> Iter[T] { yield_ => self.run(x => x.run(yield_)) }
),
),
"tap": build(
(
#|pub fn[T] Iter::tap(self : Iter[T], f : (T) -> Unit) -> Iter[T] { self.map(a => {
#| f(a)
#| a
#| }) }
),
),
"take": build(
(
#|pub fn[T] Iter::take(self : Iter[T], n : Int) -> Iter[T] { yield_ => {
#| // [..take(10,seq), next] would continue
#| // even if seq has less than 10 elements
#| // but `for x in [..take(10,seq), next ] { break }` would stop
#| //
#| let mut i = 0
#| let mut r = IterContinue
#| self.just_run(a => if i < n {
#| if yield_(a) == IterContinue {
#| i = i + 1
#| IterContinue
#| } else {
#| r = IterEnd
#| IterEnd
#| }
#| } else {
#| IterEnd
#| })
#| r
#| } }
),
),
"take_while": build(
(
#|pub fn[T] Iter::take_while(self : Iter[T], f : (T) -> Bool) -> Iter[T] { yield_ => {
#| // `r` represents the overall return value.
#| // It is set to `IterEnd` only if `yield_(a)` returns `IterEnd`.
#| // so if `f(a)` returns `false`, it will return `IterEnd`
#| // immediately the iteration of current seq is terminated
#| // but [.. take_while(..), next] would continue
#| // See test \"take_while2\"
#| let mut r : IterResult = IterContinue
#| self.just_run(a => if f(a) {
#| if yield_(a) == IterContinue {
#| IterContinue
#| } else {
#| r = IterEnd
#| IterEnd
#| }
#| } else {
#| IterEnd
#| })
#| r
#| } }
),
),
"map_while": build(
(
#|pub fn[A, B] Iter::map_while(self : Iter[A], f : (A) -> B?) -> Iter[B] { yield_ => {
#| let mut r : IterResult = IterContinue
#| self.just_run(a => match f(a) {
#| Some(b) =>
#| if yield_(b) == IterContinue {
#| IterContinue
#| } else {
#| r = IterEnd
#| IterEnd
#| }
#| None => IterEnd
#| })
#| r
#| } }
),
),
"drop": build(
(
#|pub fn[T] Iter::drop(self : Iter[T], n : Int) -> Iter[T] { yield_ => {
#| let mut i = 0
#| self.run(a => if i < n {
#| i = i + 1
#| IterContinue
#| } else {
#| yield_(a)
#| })
#| } }
),
),
"drop_while": build(
(
#|pub fn[T] Iter::drop_while(self : Iter[T], f : (T) -> Bool) -> Iter[T] { yield_ => {
#| let mut dropping = true
#| self.run(a => if dropping && f(a) {
#| IterContinue
#| } else {
#| dropping = false
#| yield_(a)
#| })
#| } }
),
),
"find_first": build(
(
#|pub fn[T] Iter::find_first(self : Iter[T], f : (T) -> Bool) -> T? { for a in self {
#| if f(a) {
#| break Some(a)
#| }
#| } else {
#| None
#| } }
),
),
"peek": build(
(
#|pub fn[T] Iter::peek(self : Iter[T]) -> T? { let mut first = None
#| self.just_run(a => {
#| first = Some(a)
#| IterEnd
#| })
#| first }
),
),
"prepend": build(
(
#|pub fn[T] Iter::prepend(self : Iter[T], a : T) -> Iter[T] { yield_ => if yield_(a) == IterContinue { self.run(yield_) } else { IterEnd } }
),
),
"append": build(
(
#|pub fn[T] Iter::append(self : Iter[T], a : T) -> Iter[T] { yield_ => if self.run(yield_) == IterContinue { yield_(a) } else { IterEnd } }
),
),
"concat": build(
(
#|pub fn[T] Iter::concat(self : Iter[T], other : Iter[T]) -> Iter[T] { yield_ => if self.run(yield_) == IterContinue {
#| other.run(yield_)
#| } else {
#| IterEnd
#| } }
),
),
"to_array": build(
(
#|pub fn[T] Iter::to_array(self : Iter[T]) -> Array[T] { let result = []
#| for e in self {
#| result.push(e)
#| }
#| result }
),
),
"collect": build(
(
#|pub fn[T] Iter::collect(self : Iter[T]) -> Array[T] { let result = []
#| self.each(e => result.push(e))
#| result }
),
),
"join": build(
(
#|pub fn Iter::join(self : Iter[String], sep : String) -> String { let buf = StringBuilder::new()
#| let mut first = true
#| for str in self {
#| if first {
#| first = false
#| } else {
#| buf.write_string(sep)
#| }
#| buf.write_string(str)
#| }
#| buf.to_string() }
),
),
"iter": build(
(
#|pub fn[T] Iter::iter(self : Iter[T]) -> Iter[T] { self }
),
),
"last": build(
(
#|pub fn[A] Iter::last(self : Iter[A]) -> A? { let mut last = None
#| for a in self {
#| last = Some(a)
#| }
#| last }
),
),
"head": build(
(
#|pub fn[A] Iter::head(self : Iter[A]) -> A? { for i in self {
#| break Some(i)
#| } else {
#| None
#| } }
),
),
"intersperse": build(
(
#|pub fn[A] Iter::intersperse(self : Iter[A], sep : A) -> Iter[A] { yield_ => {
#| let mut first = true
#| self.run(x => if first {
#| first = false
#| yield_(x)
#| } else if yield_(sep) == IterEnd {
#| IterEnd
#| } else {
#| yield_(x)
#| })
#| } }
),
),
"contains": build(
(
#|pub fn[A : Eq] Iter::contains(self : Iter[A], value : A) -> Bool { for v in self {
#| if v == value {
#| break true
#| }
#| } else {
#| false
#| } }
),
),
"nth": build(
(
#|pub fn[T] Iter::nth(self : Iter[T], n : Int) -> T? { self.drop(n).head() }
),
),
"maximum": build(
(
#|pub fn[T : Compare] Iter::maximum(self : Iter[T]) -> T? { let mut res = None
#| for x in self {
#| match res {
#| None => res = Some(x)
#| Some(max) => if x > max { res = Some(x) }
#| }
#| }
#| res }
),
),
"minimum": build(
(
#|pub fn[T : Compare] Iter::minimum(self : Iter[T]) -> T? { let mut res = None
#| for x in self {
#| match res {
#| None => res = Some(x)
#| Some(min) => if x < min { res = Some(x) }
#| }
#| }
#| res }
),
),
"iter2": build(
(
#|pub fn[T] Iter::iter2(self : Iter[T]) -> Iter2[Int, T] { yield_ => {
#| let mut index = -1
#| self.run(i => {
#| index += 1
#| yield_(index, i)
#| })
#| } }
),
),
"length": build(
(
#|pub fn[A] UninitializedArray::length(self : UninitializedArray[A]) -> Int { let UninitializedArray(self) = self
#| self.length() }
),
),
"to_int64": build(
(
#|pub fn Double::to_int64(self : Double) -> Int64 { MyInt64::from_double(self).to_int64() }
),
),
"to_uint64": build(
(
#|pub fn Double::to_uint64(self : Double) -> UInt64 { MyInt64::from_double_unsigned(self).to_uint64() }
),
),
"from_fixed_array": build(
(
#|pub fn[T] Array::from_fixed_array(arr : FixedArray[T]) -> Array[T] { let len = arr.length()
#| let arr2 = Array::make_uninit(len)
#| UninitializedArray::unsafe_blit_fixed(arr2.buffer(), 0, arr, 0, len)
#| arr2 }
),
),
"make": build(
(
#|pub fn[T] Array::make(len : Int, elem : T) -> Array[T] { let arr = Array::make_uninit(len)
#| for i in 0..
Int { self.buffer().0.length() }
),
),
"unsafe_get": build(
(
#|pub fn[T] Array::unsafe_get(self : Array[T], idx : Int) -> T { self.buffer()[idx] }
),
),
"op_get": build(
(
#|pub fn[T] Array::op_get(self : Array[T], index : Int) -> T { let len = self.length()
#| guard index >= 0 && index < len
#| self.buffer()[index] }
),
),
"get": build(
(
#|pub fn[T] Array::get(self : Array[T], index : Int) -> T? { let len = self.length()
#| guard index >= 0 && index < len else { None }
#| Some(self.unsafe_get(index)) }
),
),
"unsafe_set": build(
(
#|fn[T] Array::unsafe_set(self : Array[T], idx : Int, val : T) -> Unit { self.buffer()[idx] = val }
),
),
"op_set": build(
(
#|pub fn[T] Array::op_set(self : Array[T], index : Int, value : T) -> Unit { let len = self.length()
#| guard index >= 0 && index < len
#| self.buffer()[index] = value }
),
),
"append": build(
(
#|pub fn[T] Array::append(self : Array[T], other : Array[T]) -> Unit { other.blit_to(
#| self,
#| len=other.length(),
#| src_offset=0,
#| dst_offset=self.length(),
#| ) }
),
),
"each": build(
(
#|pub fn[T] Array::each(self : Array[T], f : (T) -> Unit raise?) -> Unit raise? { for v in self {
#| f(v)
#| } }
),
),
"rev_each": build(
(
#|pub fn[T] Array::rev_each(self : Array[T], f : (T) -> Unit) -> Unit { let len = self.length()
#| for i in 0.. Unit { self.unsafe_truncate_to_length(0) }
),
),
"is_empty": build(
(
#|pub fn[T] Array::is_empty(self : Array[T]) -> Bool { self.length() == 0 }
),
),
"is_sorted": build(
(
#|pub fn[T : Compare] Array::is_sorted(self : Array[T]) -> Bool { for i = 1 {
#| if i >= self.length() {
#| break true
#| }
#| if self[i - 1] > self[i] {
#| break false
#| }
#| continue i + 1
#| } }
),
),
"rev_inplace": build(
(
#|pub fn[T] Array::rev_inplace(self : Array[T]) -> Unit { let len = self.length()
#| for i in 0..<(len / 2) {
#| let temp = self.unsafe_get(i)
#| self.unsafe_set(i, self.unsafe_get(len - i - 1))
#| self.unsafe_set(len - i - 1, temp)
#| } }
),
),
"rev": build(
(
#|pub fn[T] Array::rev(self : Array[T]) -> Array[T] { let len = self.length()
#| let arr = Array::make_uninit(len)
#| for i in 0.. (Array[T], Array[T]) { if index < 0 || index > self.length() {
#| let len = self.length()
#| abort(
#| \"index out of bounds: the len is from 0 to \\{len} but the index is \\{index}\",
#| )
#| }
#| let v1 = Array::make_uninit(index)
#| let v2 = Array::make_uninit(self.length() - index)
#| UninitializedArray::unsafe_blit(v1.buffer(), 0, self.buffer(), 0, index)
#| if index != self.length() {
#| UninitializedArray::unsafe_blit(
#| v2.buffer(),
#| 0,
#| self.buffer(),
#| index,
#| self.length() - index,
#| )
#| }
#| (v1, v2) }
),
),
"contains": build(
(
#|pub fn[T : Eq] Array::contains(self : Array[T], value : T) -> Bool { for v in self {
#| if v == value {
#| break true
#| }
#| } else {
#| false
#| } }
),
),
"starts_with": build(
(
#|pub fn[T : Eq] Array::starts_with(self : Array[T], prefix : Array[T]) -> Bool { if prefix.length() > self.length() {
#| return false
#| }
#| for i in 0.. Bool { if suffix.length() > self.length() {
#| return false
#| }
#| for i in 0.. Int? { for i, v in self {
#| if v == value {
#| break Some(i)
#| }
#| } else {
#| None
#| } }
),
),
"search_by": build(
(
#|pub fn[T] Array::search_by(self : Array[T], f : (T) -> Bool) -> Int? { for i, v in self {
#| if f(v) {
#| break Some(i)
#| }
#| } else {
#| None
#| } }
),
),
"swap": build(
(
#|pub fn[T] Array::swap(self : Array[T], i : Int, j : Int) -> Unit { if i >= self.length() || j >= self.length() || i < 0 || j < 0 {
#| let len = self.length()
#| abort(
#| \"index out of bounds: the len is from 0 to \\{len} but the index is (\\{i}, \\{j})\",
#| )
#| }
#| let temp = self.unsafe_get(i)
#| self.unsafe_set(i, self.unsafe_get(j))
#| self.unsafe_set(j, temp) }
),
),
"retain": build(
(
#|pub fn[T] Array::retain(self : Array[T], f : (T) -> Bool raise?) -> Unit raise? { let len = self.length()
#| for i = 0, j = 0; i < len; {
#| let item = self.unsafe_get(i)
#| if f(item) {
#| self.unsafe_set(j, item)
#| continue i + 1, j + 1
#| }
#| continue i + 1, j
#| } else {
#| // we use `else` here to capture `j`
#| self.unsafe_truncate_to_length(j)
#| } }
),
),
"resize": build(
(
#|pub fn[T] Array::resize(self : Array[T], new_len : Int, f : T) -> Unit { if new_len < 0 {
#| abort(\"negative new length\")
#| }
#| if new_len < self.length() {
#| self.unsafe_truncate_to_length(new_len)
#| } else {
#| let len = self.length()
#| for _ in len.. Array[T] { let mut len = 0
#| for x in self {
#| len += x.length()
#| }
#| let res = Array::make_uninit(len)
#| let mut i = 0
#| for xs in self {
#| res.unsafe_blit(i, xs, 0, xs.length())
#| i += xs.length()
#| }
#| res }
),
),
"repeat": build(
(
#|pub fn[T] Array::repeat(self : Array[T], times : Int) -> Array[T] { let v = Array::new(capacity=self.length() * times)
#| for i in 0.. Unit { if self.is_empty() {
#| return
#| }
#| let mut w = 1
#| for i in 1.. Bool) -> Array[T] { let v = []
#| let indices = []
#| for i in 0.. ignore
#| }
#| v }
),
),
"chunks": build(
(
#|pub fn[T] Array::chunks(self : Array[T], size : Int) -> Array[Array[T]] { guard size > 0
#| let chunks = []
#| let mut i = 0
#| while i < self.length() {
#| let chunk = Array::new(capacity=size)
#| for j = 0; j < size && i < self.length(); j = j + 1 {
#| chunk.push(self[i])
#| i = i + 1
#| }
#| chunks.push(chunk)
#| }
#| chunks }
),
),
"windows": build(
(
#|pub fn[T] Array::windows(self : Array[T], size : Int) -> Array[ArrayView[T]] { guard size > 0
#| let len = self.length() - size + 1
#| if len < 1 {
#| return []
#| }
#| let windows = Array::new(capacity=len)
#| for i in 0.. Iter[T] { Iter::new(yield_ => for v in self {
#| guard yield_(v) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }) }
),
),
"rev_iter": build(
(
#|pub fn[T] Array::rev_iter(self : Array[T]) -> Iter[T] { Iter::new(yield_ => for i = self.length() - 1; i >= 0; i = i - 1 {
#| guard yield_(self.unsafe_get(i)) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }) }
),
),
"iter2": build(
(
#|pub fn[A] Array::iter2(self : Array[A]) -> Iter2[Int, A] { Iter2::new(yield_ => for i, v in self {
#| guard yield_(i, v) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }) }
),
),
"unsafe_pop_back": build(
(
#|pub fn[A] Array::unsafe_pop_back(self : Array[A]) -> Unit { self.unsafe_pop() |> ignore }
),
),
"truncate": build(
(
#|pub fn[A] Array::truncate(self : Array[A], len : Int) -> Unit { guard len >= 0 && len < self.length() else { return }
#| self.unsafe_truncate_to_length(len) }
),
),
"retain_map": build(
(
#|pub fn[A] Array::retain_map(self : Array[A], f : (A) -> A?) -> Unit { if self.is_empty() {
#| return
#| }
#| let buf = self.buffer()
#| let len = self.length()
#| let mut write_idx = 0
#| for read_idx in 0.. {
#| buf[write_idx] = new_val
#| write_idx += 1
#| }
#| None => ()
#| }
#| }
#| self.unsafe_truncate_to_length(write_idx) }
),
),
"to_string": build(
(
#|pub fn[X : Show] Option::to_string(self : X?) -> String { match self {
#| None => \"None\"
#| Some(x) => \"Some(\" + x.to_string() + \")\"
#| } }
),
),
"unwrap": build(
(
#|pub fn[X] Option::unwrap(self : X?) -> X { match self {
#| None => panic()
#| Some(x) => x
#| } }
),
),
"get": build(
(
#|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)) }
),
),
"iter": build(
(
#|pub fn[T] FixedArray::iter(self : FixedArray[T]) -> Iter[T] { Iter::new(yield_ => for v in self {
#| guard yield_(v) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }) }
),
),
"iter2": build(
(
#|pub fn[T] FixedArray::iter2(self : FixedArray[T]) -> Iter2[Int, T] { Iter2::new(yield_ => for i, v in self {
#| guard yield_(i, v) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }) }
),
),
"fill": build(
(
#|pub fn[T] FixedArray::fill(self : FixedArray[T], value : T) -> Unit { for i in 0.. Bool { self.length() == 0 }
),
),
"each": build(
(
#|pub fn[A, B] Iter2::each(self : Iter2[A, B], f : (A, B) -> Unit) -> Unit { self.run((a, b) => {
#| f(a, b)
#| IterContinue
#| })
#| |> ignore }
),
),
"iter": build(
(
#|pub fn[A, B] Iter2::iter(self : Iter2[A, B]) -> Iter[(A, B)] { Iter::new(yield_ => self.run((a, b) => yield_((a, b)))) }
),
),
"iter2": build(
(
#|pub fn[A, B] Iter2::iter2(self : Iter2[A, B]) -> Iter2[A, B] { // This is a no-op to make sure
#| // `for k,v in map.iter2() { ... }`
#| // still work
#| self }
),
),
"to_array": build(
(
#|pub fn[A, B] Iter2::to_array(self : Iter2[A, B]) -> Array[(A, B)] { let arr = []
#| for k, v in self {
#| arr.push((k, v))
#| }
#| arr }
),
),
"add_hi_lo": build(
(
#|fn MyInt64::add_hi_lo(self : MyInt64, bhi : Int, blo : Int) -> MyInt64 { let { hi: ahi, lo: alo } = self
#| let lo = alo + blo
#| let s = lo >> 31
#| let as_ = alo >> 31
#| let bs = blo >> 31
#| let c = ((as_ & bs) | (s.lnot() & (as_ ^ bs))) & 1
#| let hi = ahi + bhi + c
#| { hi, lo } }
),
),
"div_u": build(
(
#|fn MyInt64::div_u(self : MyInt64, other : MyInt64) -> MyInt64 { let exports = get_int64_wasm_helper()
#| let { hi: ahi, lo: alo } = self
#| let { hi: bhi, lo: blo } = other
#| let lo = (exports.div_u)(alo, ahi, blo, bhi)
#| let hi = (exports.get_high)()
#| { hi, lo } }
),
),
"mod_u": build(
(
#|fn MyInt64::mod_u(self : MyInt64, other : MyInt64) -> MyInt64 { let exports = get_int64_wasm_helper()
#| let { hi: ahi, lo: alo } = self
#| let { hi: bhi, lo: blo } = other
#| let lo = (exports.rem_u)(alo, ahi, blo, bhi)
#| let hi = (exports.get_high)()
#| { hi, lo } }
),
),
"lnot": build(
(
#|fn MyInt64::lnot(self : MyInt64) -> MyInt64 { { hi: self.hi.lnot(), lo: self.lo.lnot() } }
),
),
"land": build(
(
#|fn MyInt64::land(self : MyInt64, other : MyInt64) -> MyInt64 { { hi: self.hi & other.hi, lo: self.lo & other.lo } }
),
),
"lor": build(
(
#|fn MyInt64::lor(self : MyInt64, other : MyInt64) -> MyInt64 { { hi: self.hi | other.hi, lo: self.lo | other.lo } }
),
),
"lxor": build(
(
#|fn MyInt64::lxor(self : MyInt64, other : MyInt64) -> MyInt64 { { hi: self.hi ^ other.hi, lo: self.lo ^ other.lo } }
),
),
"lsl": build(
(
#|fn MyInt64::lsl(self : MyInt64, shift : Int) -> MyInt64 { let shift = shift & 63
#| if shift == 0 {
#| self
#| } else if shift < 32 {
#| let { hi, lo } = self
#| let hi = hi.reinterpret_as_uint()
#| let lo = lo.reinterpret_as_uint()
#| let hi = (hi << shift) | (lo >> (32 - shift))
#| let lo = lo << shift
#| { hi: hi.reinterpret_as_int(), lo: lo.reinterpret_as_int() }
#| } else {
#| { hi: self.lo << (shift - 32), lo: 0 }
#| } }
),
),
"lsr": build(
(
#|fn MyInt64::lsr(self : MyInt64, shift : Int) -> MyInt64 { let shift = shift & 63
#| if shift == 0 {
#| self
#| } else if shift < 32 {
#| {
#| hi: (self.hi.reinterpret_as_uint() >> shift).reinterpret_as_int(),
#| lo: (self.lo.reinterpret_as_uint() >> shift).reinterpret_as_int() |
#| (self.hi << (32 - shift)),
#| }
#| } else {
#| {
#| hi: 0,
#| lo: (self.hi.reinterpret_as_uint() >> (shift - 32)).reinterpret_as_int(),
#| }
#| } }
),
),
"asr": build(
(
#|fn MyInt64::asr(self : MyInt64, shift : Int) -> MyInt64 { let shift = shift & 63
#| if shift == 0 {
#| self
#| } else if shift < 32 {
#| {
#| hi: self.hi >> shift,
#| lo: (self.lo.reinterpret_as_uint() >> shift).reinterpret_as_int() |
#| (self.hi << (32 - shift)),
#| }
#| } else {
#| { hi: self.hi >> 31, lo: self.hi >> (shift - 32) }
#| } }
),
),
"clz": build(
(
#|fn MyInt64::clz(self : MyInt64) -> Int { if self.hi != 0 {
#| self.hi.clz()
#| } else {
#| 32 + self.lo.clz()
#| } }
),
),
"ctz": build(
(
#|fn MyInt64::ctz(self : MyInt64) -> Int { if self.lo != 0 {
#| self.lo.ctz()
#| } else {
#| 32 + self.hi.ctz()
#| } }
),
),
"popcnt": build(
(
#|fn MyInt64::popcnt(self : MyInt64) -> Int { self.hi.popcnt() + self.lo.popcnt() }
),
),
"from_int": build(
(
#|fn MyInt64::from_int(value : Int) -> MyInt64 { { hi: (value >> 31) & -1, lo: value | 0 } }
),
),
"to_int": build(
(
#|fn MyInt64::to_int(self : MyInt64) -> Int { self.lo }
),
),
"to_uint": build(
(
#|fn MyInt64::to_uint(self : MyInt64) -> UInt { self.lo.reinterpret_as_uint() }
),
),
"extend_i32_u": build(
(
#|fn MyInt64::extend_i32_u(value : Int) -> MyInt64 { { hi: 0, lo: value } }
),
),
"lnot": build(
(
#|pub fn Int64::lnot(self : Int64) -> Int64 { MyInt64::from_int64(self).lnot().to_int64() }
),
),
"lsl": build(
(
#|pub fn Int64::lsl(self : Int64, other : Int) -> Int64 { MyInt64::from_int64(self).lsl(other).to_int64() }
),
),
"shl": build(
(
#|pub fn Int64::shl(self : Int64, other : Int) -> Int64 { MyInt64::from_int64(self).lsl(other).to_int64() }
),
),
"lsr": build(
(
#|pub fn Int64::lsr(self : Int64, other : Int) -> Int64 { MyInt64::from_int64(self).lsr(other).to_int64() }
),
),
"shr": build(
(
#|pub fn Int64::shr(self : Int64, other : Int) -> Int64 { MyInt64::from_int64(self).asr(other).to_int64() }
),
),
"asr": build(
(
#|pub fn Int64::asr(self : Int64, other : Int) -> Int64 { MyInt64::from_int64(self).asr(other).to_int64() }
),
),
"ctz": build(
(
#|pub fn Int64::ctz(self : Int64) -> Int { MyInt64::from_int64(self).ctz() }
),
),
"clz": build(
(
#|pub fn Int64::clz(self : Int64) -> Int { MyInt64::from_int64(self).clz() }
),
),
"popcnt": build(
(
#|pub fn Int64::popcnt(self : Int64) -> Int { MyInt64::from_int64(self).popcnt() }
),
),
"to_int": build(
(
#|pub fn Int64::to_int(self : Int64) -> Int { MyInt64::from_int64(self).to_int() }
),
),
"to_double": build(
(
#|pub fn Int64::to_double(self : Int64) -> Double { Double::convert_int64(self) }
),
),
"to_byte": build(
(
#|pub fn Int64::to_byte(self : Int64) -> Byte { MyInt64::from_int64(self).to_int().to_byte() }
),
),
"to_int16": build(
(
#|pub fn Int64::to_int16(self : Int64) -> Int16 { MyInt64::from_int64(self).to_int().to_int16() }
),
),
"to_uint16": build(
(
#|pub fn Int64::to_uint16(self : Int64) -> UInt16 { MyInt64::from_int64(self).to_int().to_uint16() }
),
),
"extend_uint": build(
(
#|pub fn UInt64::extend_uint(value : UInt) -> UInt64 { MyInt64::extend_i32_u(value.reinterpret_as_int()).to_uint64() }
),
),
"reinterpret_as_double": build(
(
#|pub fn Int64::reinterpret_as_double(self : Int64) -> Double { MyInt64::reinterpret_as_double(MyInt64::from_int64(self)) }
),
),
"reinterpret_as_double": build(
(
#|pub fn UInt64::reinterpret_as_double(self : UInt64) -> Double { MyInt64::reinterpret_as_double(MyInt64::from_uint64(self)) }
),
),
"to_int64": build(
(
#|pub fn Int::to_int64(self : Int) -> Int64 { MyInt64::from_int(self).to_int64() }
),
),
"to_int64": build(
(
#|pub fn Int16::to_int64(self : Int16) -> Int64 { MyInt64::from_int(self.to_int()).to_int64() }
),
),
"to_int64": build(
(
#|pub fn UInt16::to_int64(self : UInt16) -> Int64 { MyInt64::from_int(self.to_int()).to_int64() }
),
),
"reinterpret_as_i64": build(
(
#|pub fn Double::reinterpret_as_i64(self : Double) -> Int64 { MyInt64::reinterpret_double(self).to_int64() }
),
),
"reinterpret_as_int64": build(
(
#|pub fn Double::reinterpret_as_int64(self : Double) -> Int64 { MyInt64::reinterpret_double(self).to_int64() }
),
),
"reinterpret_as_u64": build(
(
#|pub fn Double::reinterpret_as_u64(self : Double) -> UInt64 { MyInt64::reinterpret_double(self).to_uint64() }
),
),
"reinterpret_as_uint64": build(
(
#|pub fn Double::reinterpret_as_uint64(self : Double) -> UInt64 { MyInt64::reinterpret_double(self).to_uint64() }
),
),
"convert_uint64": build(
(
#|pub fn Double::convert_uint64(value : UInt64) -> Double { MyInt64::convert_to_double_u(MyInt64::from_uint64(value)) }
),
),
"convert_int64": build(
(
#|fn Double::convert_int64(value : Int64) -> Double { MyInt64::convert_to_double(MyInt64::from_int64(value)) }
),
),
"to_uint": build(
(
#|pub fn UInt64::to_uint(self : UInt64) -> UInt { MyInt64::from_uint64(self).to_uint() }
),
),
"to_int": build(
(
#|pub fn UInt64::to_int(self : UInt64) -> Int { MyInt64::from_uint64(self).to_int() }
),
),
"to_double": build(
(
#|pub fn UInt64::to_double(self : UInt64) -> Double { Double::convert_uint64(self) }
),
),
"trunc_double": build(
(
#|pub fn UInt64::trunc_double(value : Double) -> UInt64 { MyInt64::trunc_double_u(value).to_uint64() }
),
),
"lnot": build(
(
#|pub fn UInt64::lnot(self : UInt64) -> UInt64 { MyInt64::lnot(MyInt64::from_uint64(self)).to_uint64() }
),
),
"lsl": build(
(
#|pub fn UInt64::lsl(self : UInt64, shift : Int) -> UInt64 { MyInt64::lsl(MyInt64::from_uint64(self), shift).to_uint64() }
),
),
"lsr": build(
(
#|pub fn UInt64::lsr(self : UInt64, shift : Int) -> UInt64 { MyInt64::lsr(MyInt64::from_uint64(self), shift).to_uint64() }
),
),
"shl": build(
(
#|pub fn UInt64::shl(self : UInt64, shift : Int) -> UInt64 { MyInt64::lsl(MyInt64::from_uint64(self), shift).to_uint64() }
),
),
"shr": build(
(
#|pub fn UInt64::shr(self : UInt64, shift : Int) -> UInt64 { MyInt64::lsr(MyInt64::from_uint64(self), shift).to_uint64() }
),
),
"clz": build(
(
#|pub fn UInt64::clz(self : UInt64) -> Int { MyInt64::from_uint64(self).clz() }
),
),
"ctz": build(
(
#|pub fn UInt64::ctz(self : UInt64) -> Int { MyInt64::from_uint64(self).ctz() }
),
),
"popcnt": build(
(
#|pub fn UInt64::popcnt(self : UInt64) -> Int { MyInt64::from_uint64(self).popcnt() }
),
),
"to_float": build(
(
#|pub fn Int64::to_float(self : Int64) -> Float { self.to_double().to_float() }
),
),
"to_float": build(
(
#|pub fn UInt64::to_float(self : UInt64) -> Float { Double::convert_uint64(self).to_float() }
),
),
"repr": build(
(
#|pub fn[T : Show] repr(t : T) -> String { let logger = StringBuilder::new()
#| t.output(logger)
#| logger.to_string() }
),
),
"to_hex_digit": build(
(
#|fn to_hex_digit(i : Int) -> Char { if i < 10 {
#| (i + '0').unsafe_to_char()
#| } else {
#| (i + 'a' - 10).unsafe_to_char()
#| } }
),
),
"escape": build(
(
#|pub fn String::escape(self : String) -> String { let buf = StringBuilder::new()
#| Show::output(self, buf)
#| buf.to_string() }
),
),
"lsr": build(
(
#|pub fn Int::lsr(self : Int, other : Int) -> Int { (self.reinterpret_as_uint() >> other).reinterpret_as_int() }
),
),
"to_uint64": build(
(
#|pub fn Int::to_uint64(self : Int) -> UInt64 { self.to_int64().reinterpret_as_uint64() }
),
),
"to_uint": build(
(
#|pub fn Char::to_uint(self : Char) -> UInt { self.to_int().reinterpret_as_uint() }
),
),
"make": build(
(
#|pub fn Bytes::make(len : Int, init : Byte) -> Bytes { if len < 0 {
#| return []
#| }
#| Bytes::unsafe_make(len, init) }
),
),
"new": build(
(
#|pub fn Bytes::new(len : Int) -> Bytes { Bytes::make(len, b'\\x00') }
),
),
"to_char": build(
(
#|pub fn Int::to_char(self : Int) -> Char? { if self is (0..=0xD7FF) || self is (0xE000..=0x10FFFF) {
#| Some(self.unsafe_to_char())
#| } else {
#| None
#| } }
),
),
"to_byte": build(
(
#|pub fn UInt64::to_byte(self : UInt64) -> Byte { self.to_int().to_byte() }
),
),
"to_char": build(
(
#|pub fn Byte::to_char(self : Byte) -> Char { self.to_int().unsafe_to_char() }
),
),
"to_int64": build(
(
#|pub fn Byte::to_int64(self : Byte) -> Int64 { self.to_int().to_int64() }
),
),
"to_uint64": build(
(
#|pub fn UInt::to_uint64(self : UInt) -> UInt64 { UInt64::extend_uint(self) }
),
),
"to_byte": build(
(
#|pub fn UInt::to_byte(self : UInt) -> Byte { self.reinterpret_as_int().to_byte() }
),
),
"to_double": build(
(
#|pub fn Byte::to_double(self : Byte) -> Double { self.to_int().to_double() }
),
),
"Json": build(
(
#|pub enum Json {
#| Null
#| True
#| False
#| Number(Double, repr~ : String?) // 1.0000000000000000000e100
#| String(String)
#| Array(Array[Json])
#| Object(Map[String, Json])
#|}
),
),
"null": build(
(
#|pub fn Json::null() -> Json { return Null }
),
),
"number": build(
(
#|pub fn Json::number(number : Double, repr? : String) -> Json { return Number(number, repr~) }
),
),
"string": build(
(
#|pub fn Json::string(string : String) -> Json { return String(string) }
),
),
"boolean": build(
(
#|pub fn Json::boolean(boolean : Bool) -> Json { if boolean {
#| True
#| } else {
#| False
#| } }
),
),
"array": build(
(
#|pub fn Json::array(array : Array[Json]) -> Json { return Array(array) }
),
),
"object": build(
(
#|pub fn Json::object(object : Map[String, Json]) -> Json { return Object(object) }
),
),
"to_string": build(
(
#|pub fn Int64::to_string(self : Int64, radix~ : Int = 10) -> String { let buf = StringBuilder::new(size_hint=Int64::output_size_hint(radix~))
#| self.output(buf, radix~)
#| buf.to_string() }
),
),
"to_string": build(
(
#|pub fn Int::to_string(self : Int, radix~ : Int = 10) -> String { let buf = StringBuilder::new(size_hint=Int::output_size_hint(radix~))
#| self.output(buf, radix~)
#| buf.to_string() }
),
),
"to_string": build(
(
#|pub fn UInt::to_string(self : UInt, radix~ : Int = 10) -> String { let buf = StringBuilder::new(size_hint=UInt::output_size_hint(radix~))
#| self.output(buf, radix~)
#| buf.to_string() }
),
),
"to_string": build(
(
#|pub fn UInt64::to_string(self : UInt64, radix~ : Int = 10) -> String { let buf = StringBuilder::new(size_hint=UInt64::output_size_hint(radix~))
#| self.output(buf, radix~)
#| buf.to_string() }
),
),
"to_string": build(
(
#|pub fn Int16::to_string(self : Int16, radix~ : Int = 10) -> String { self.to_int().to_string(radix~) }
),
),
"to_string": build(
(
#|pub fn UInt16::to_string(self : UInt16, radix~ : Int = 10) -> String { self.to_int().to_string(radix~) }
),
),
"make_uninit": build(
(
#|fn[T] Array::make_uninit(len : Int) -> Array[T] { { buf: UninitializedArray::make(len), len } }
),
),
"new": build(
(
#|pub fn[T] Array::new(capacity~ : Int = 0) -> Array[T] { if capacity == 0 {
#| []
#| } else {
#| { buf: UninitializedArray::make(capacity), len: 0 }
#| } }
),
),
"length": build(
(
#|pub fn[T] Array::length(self : Array[T]) -> Int { self.len }
),
),
"unsafe_truncate_to_length": build(
(
#|fn[T] Array::unsafe_truncate_to_length(self : Array[T], new_len : Int) -> Unit { let len = self.length()
#| guard new_len <= len
#| for i in new_len.. UninitializedArray[T] { self.buf }
),
),
"resize_buffer": build(
(
#|fn[T] Array::resize_buffer(self : Array[T], new_capacity : Int) -> Unit { let new_buf = UninitializedArray::make(new_capacity)
#| let old_buf = self.buf
#| let old_cap = old_buf.0.length()
#| let copy_len = if old_cap < new_capacity { old_cap } else { new_capacity }
#| UninitializedArray::unsafe_blit(new_buf, 0, old_buf, 0, copy_len)
#| self.buf = new_buf }
),
),
"realloc": build(
(
#|fn[T] Array::realloc(self : Array[T]) -> Unit { let old_cap = self.length()
#| let new_cap = if old_cap == 0 { 8 } else { old_cap * 2 }
#| self.resize_buffer(new_cap) }
),
),
"reserve_capacity": build(
(
#|pub fn[T] Array::reserve_capacity(self : Array[T], capacity : Int) -> Unit { if self.capacity() >= capacity {
#| return
#| }
#| self.resize_buffer(capacity) }
),
),
"shrink_to_fit": build(
(
#|pub fn[T] Array::shrink_to_fit(self : Array[T]) -> Unit { if self.capacity() <= self.length() {
#| return
#| }
#| self.resize_buffer(self.length()) }
),
),
"push": build(
(
#|pub fn[T] Array::push(self : Array[T], value : T) -> Unit { if self.length() == self.buffer().0.length() {
#| self.realloc()
#| }
#| let length = self.length()
#| self.unsafe_set(length, value)
#| self.len = length + 1 }
),
),
"pop": build(
(
#|pub fn[T] Array::pop(self : Array[T]) -> T? { let len = self.length()
#| if len == 0 {
#| None
#| } else {
#| let index = len - 1
#| let v = self.unsafe_get(index)
#| self.buf.set_null(index)
#| self.len = index
#| Some(v)
#| } }
),
),
"unsafe_pop": build(
(
#|pub fn[T] Array::unsafe_pop(self : Array[T]) -> T { let len = self.length()
#| guard len != 0
#| let index = len - 1
#| let v = self.unsafe_get(index)
#| self.buf.set_null(index)
#| self.len = index
#| v }
),
),
"remove": build(
(
#|pub fn[T] Array::remove(self : Array[T], index : Int) -> T { guard index >= 0 && index < self.length() else {
#| abort(
#| \"index out of bounds: the len is from 0 to \\{self.length()} but the index is \\{index}\",
#| )
#| }
#| let value = self.unsafe_get(index)
#| UninitializedArray::unsafe_blit(
#| self.buffer(),
#| index,
#| self.buffer(),
#| index + 1,
#| self.length() - index - 1,
#| )
#| self.unsafe_truncate_to_length(self.length() - 1)
#| value }
),
),
"drain": build(
(
#|pub fn[T] Array::drain(self : Array[T], begin : Int, end : Int) -> Array[T] { guard begin >= 0 && end <= self.length() && begin <= end
#| let num = end - begin
#| let v = Array::make_uninit(num)
#| UninitializedArray::unsafe_blit(v.buffer(), 0, self.buffer(), begin, num)
#| UninitializedArray::unsafe_blit(
#| self.buffer(),
#| begin,
#| self.buffer(),
#| end,
#| self.length() - end,
#| )
#| self.unsafe_truncate_to_length(self.length() - num)
#| v }
),
),
"insert": build(
(
#|pub fn[T] Array::insert(self : Array[T], index : Int, value : T) -> Unit { guard index >= 0 && index <= self.length() else {
#| abort(
#| \"index out of bounds: the len is from 0 to \\{self.length()} but the index is \\{index}\",
#| )
#| }
#| if self.length() == self.buffer().0.length() {
#| self.realloc()
#| }
#| UninitializedArray::unsafe_blit(
#| self.buffer(),
#| index + 1,
#| self.buffer(),
#| index,
#| self.length() - index,
#| )
#| let length = self.length()
#| self.unsafe_set(index, value)
#| self.len = length + 1 }
),
),
"unsafe_grow_to_length": build(
(
#|fn[T] Array::unsafe_grow_to_length(self : Array[T], new_len : Int) -> Unit { guard new_len >= self.length()
#| let new_buf = UninitializedArray::make(new_len)
#| UninitializedArray::unsafe_blit(new_buf, 0, self.buf, 0, self.len)
#| self.len = new_len
#| self.buf = new_buf }
),
),
"new": build(
(
#|pub fn Hasher::new(seed~ : Int = 0) -> Hasher { { acc: seed.reinterpret_as_uint() + GPRIME5 } }
),
),
"combine": build(
(
#|pub fn[T : Hash] Hasher::combine(self : Hasher, value : T) -> Unit { value.hash_combine(self) }
),
),
"combine_unit": build(
(
#|pub fn Hasher::combine_unit(self : Hasher) -> Unit { self.combine_uint(0) }
),
),
"combine_bool": build(
(
#|pub fn Hasher::combine_bool(self : Hasher, value : Bool) -> Unit { self.combine_uint(if value { 1 } else { 0 }) }
),
),
"combine_int": build(
(
#|pub fn Hasher::combine_int(self : Hasher, value : Int) -> Unit { self.combine_uint(value.reinterpret_as_uint()) }
),
),
"combine_int64": build(
(
#|pub fn Hasher::combine_int64(self : Hasher, value : Int64) -> Unit { self.acc += 8
#| self.consume4(value.reinterpret_as_uint64().to_uint())
#| self.consume4((value.reinterpret_as_uint64() >> 32).to_uint()) }
),
),
"combine_uint": build(
(
#|pub fn Hasher::combine_uint(self : Hasher, value : UInt) -> Unit { self.acc += 4
#| self.consume4(value) }
),
),
"combine_uint64": build(
(
#|pub fn Hasher::combine_uint64(self : Hasher, value : UInt64) -> Unit { self.combine_int64(value.reinterpret_as_int64()) }
),
),
"combine_double": build(
(
#|pub fn Hasher::combine_double(self : Hasher, value : Double) -> Unit { self.combine_int64(value.reinterpret_as_int64()) }
),
),
"combine_float": build(
(
#|pub fn Hasher::combine_float(self : Hasher, value : Float) -> Unit { self.combine_uint(value.reinterpret_as_uint()) }
),
),
"combine_byte": build(
(
#|pub fn Hasher::combine_byte(self : Hasher, value : Byte) -> Unit { self.consume1(value) }
),
),
"combine_bytes": build(
(
#|pub fn Hasher::combine_bytes(self : Hasher, value : Bytes) -> Unit { let mut remain = value.length()
#| let mut cur = 0
#| while remain >= 4 {
#| self.consume4(endian32(value, cur))
#| cur += 4
#| remain -= 4
#| }
#| while remain >= 1 {
#| self.consume1(value[cur])
#| cur += 1
#| remain -= 1
#| } }
),
),
"combine_string": build(
(
#|pub fn Hasher::combine_string(self : Hasher, value : String) -> Unit { for i in 0.. Unit { self.combine_uint(value.to_uint()) }
),
),
"finalize": build(
(
#|pub fn Hasher::finalize(self : Hasher) -> Int { self.avalanche().reinterpret_as_int() }
),
),
"avalanche": build(
(
#|fn Hasher::avalanche(self : Hasher) -> UInt { let mut acc = self.acc
#| acc = acc ^ (acc >> 15)
#| acc *= GPRIMES2
#| acc = acc ^ (acc >> 13)
#| acc *= GPRIME3
#| acc = acc ^ (acc >> 16)
#| acc }
),
),
"consume4": build(
(
#|fn Hasher::consume4(self : Hasher, input : UInt) -> Unit { self.acc = rotl(self.acc + input * GPRIME3, 17) * GPRIME4 }
),
),
"consume1": build(
(
#|fn Hasher::consume1(self : Hasher, input : Byte) -> Unit { self.acc = rotl(self.acc + input.to_uint() * GPRIME5, 11) * GPRIME1 }
),
),
"rotl": build(
(
#|fn rotl(x : UInt, r : Int) -> UInt { (x << r) | (x >> (32 - r)) }
),
),
"endian32": build(
(
#|fn endian32(input : Bytes, cur : Int) -> UInt { input[cur + 0].to_uint() |
#| (
#| (input[cur + 1].to_uint() << 8) |
#| (input[cur + 2].to_uint() << 16) |
#| (input[cur + 3].to_uint() << 24)
#| ) }
),
),
"new": build(
(
#|pub fn[T] Array::new(capacity~ : Int = 0) -> Array[T] { ignore(capacity)
#| [] }
),
),
"unsafe_truncate_to_length": build(
(
#|fn[T] Array::unsafe_truncate_to_length(self : Array[T], new_len : Int) -> Unit { JSArray::ofAnyArray(self).set_length(new_len) }
),
),
"reserve_capacity": build(
(
#|pub fn[T] Array::reserve_capacity(self : Array[T], capacity : Int) -> Unit { ignore(self)
#| ignore(capacity) }
),
),
"shrink_to_fit": build(
(
#|pub fn[T] Array::shrink_to_fit(self : Array[T]) -> Unit { ignore(self) }
),
),
"push": build(
(
#|pub fn[T] Array::push(self : Array[T], value : T) -> Unit { JSArray::ofAnyArray(self).push(JSValue::ofAny(value)) }
),
),
"pop": build(
(
#|pub fn[T] Array::pop(self : Array[T]) -> T? { if self.length() == 0 {
#| None
#| } else {
#| let v = self.unsafe_pop()
#| Some(v)
#| } }
),
),
"unsafe_pop": build(
(
#|pub fn[T] Array::unsafe_pop(self : Array[T]) -> T { JSArray::ofAnyArray(self).pop().toAny() }
),
),
"remove": build(
(
#|pub fn[T] Array::remove(self : Array[T], index : Int) -> T { guard index >= 0 && index < self.length() else {
#| abort(
#| \"index out of bounds: the len is from 0 to \\{self.length()} but the index is \\{index}\",
#| )
#| }
#| let value = self.buffer()[index]
#| let _ = JSArray::ofAnyArray(self).splice(index, 1)
#| value }
),
),
"drain": build(
(
#|pub fn[T] Array::drain(self : Array[T], begin : Int, end : Int) -> Array[T] { guard begin >= 0 && end <= self.length() && begin <= end else {
#| abort(
#| \"index out of bounds: the len is \\{self.length()} but the index is (\\{begin}, \\{end})\",
#| )
#| }
#| JSArray::ofAnyArray(self).splice(begin, end - begin).toAnyArray() }
),
),
"insert": build(
(
#|pub fn[T] Array::insert(self : Array[T], index : Int, value : T) -> Unit { guard index >= 0 && index <= self.length() else {
#| abort(
#| \"index out of bounds: the len is from 0 to \\{self.length()} but the index is \\{index}\",
#| )
#| }
#| let _ = JSArray::ofAnyArray(self).splice1(index, 0, JSValue::ofAny(value)) }
),
),
"unsafe_grow_to_length": build(
(
#|fn[T] Array::unsafe_grow_to_length(self : Array[T], new_len : Int) -> Unit { guard new_len >= self.length()
#| JSArray::ofAnyArray(self).set_length(new_len) }
),
),
"length": build(
(
#|pub fn[T] ArrayView::length(self : ArrayView[T]) -> Int { self.len() }
),
),
"op_get": build(
(
#|pub fn[T] ArrayView::op_get(self : ArrayView[T], index : Int) -> T { guard index >= 0 && index < self.len() else {
#| abort(
#| \"index out of bounds: the len is from 0 to \\{self.len()} but the index is \\{index}\",
#| )
#| }
#| self.buf()[self.start() + index] }
),
),
"unsafe_get": build(
(
#|pub fn[T] ArrayView::unsafe_get(self : ArrayView[T], index : Int) -> T { self.buf()[self.start() + index] }
),
),
"swap": build(
(
#|pub fn[T] ArrayView::swap(self : ArrayView[T], i : Int, j : Int) -> Unit { guard i >= 0 && i < self.len() && j >= 0 && j < self.len() else {
#| abort(
#| \"index out of bounds: the len is from 0 to \\{self.len()} but the index is (\\{i}, \\{j})\",
#| )
#| }
#| let temp = self.buf()[self.start() + i]
#| self.buf()[self.start() + i] = self.buf()[self.start() + j]
#| self.buf()[self.start() + j] = temp }
),
),
"upto": build(
(
#|pub fn Int::upto(self : Int, end : Int, inclusive~ : Bool = false) -> Iter[Int] { yield_ => {
#| let mut i = self
#| while i < end || (inclusive && i == end) {
#| if yield_(i) == IterEnd {
#| break IterEnd
#| }
#| if i == end {
#| break IterContinue
#| }
#| i += 1
#| } else {
#| IterContinue
#| }
#| } }
),
),
"find_index": build(
(
#|pub fn[T] Array::find_index(self : Array[T], f : (T) -> Bool) -> Int? { self.search_by(f) }
),
),
"pop_exn": build(
(
#|pub fn[T] Array::pop_exn(self : Array[T]) -> T { self.unsafe_pop() }
),
),
"of_string": build(
(
#|pub fn Bytes::of_string(str : String) -> Bytes { FixedArray::make(str.length() * 2, Byte::default())
#| ..blit_from_string(0, str, 0, str.length())
#| .unsafe_reinterpret_as_bytes() }
),
),
"copy": build(
(
#|pub fn Bytes::copy(self : Bytes) -> Bytes { Bytes::makei(self.length(), i => self[i]) }
),
),
"lsl": build(
(
#|pub fn Byte::lsl(self : Byte, count : Int) -> Byte { (self.to_int() << count).to_byte() }
),
),
"lsr": build(
(
#|pub fn Byte::lsr(self : Byte, count : Int) -> Byte { (self.to_uint() >> count).reinterpret_as_int().to_byte() }
),
),
"dump": build(
(
#|pub fn[T] dump(t : T, name? : String, loc~ : SourceLoc) -> T { let name = match name {
#| Some(name) => name
#| None => \"\"
#| }
#| println(\"dump(\\{name}@\\{loc}) = \\{any_to_string(t)}\")
#| t }
),
),
"codepoint_at": build(
(
#|pub fn String::codepoint_at(self : String, index : Int) -> Char { let charcode_len = self.length()
#| guard index >= 0 && index < charcode_len else { abort(\"index out of bounds\") }
#| for char_count = 0, utf16_offset = 0
#| char_count < charcode_len && utf16_offset < index
#| char_count = char_count + 1, utf16_offset = utf16_offset + 1 {
#| let c1 = self.unsafe_charcode_at(char_count)
#| if c1.is_leading_surrogate() && char_count + 1 < charcode_len {
#| let c2 = self.unsafe_charcode_at(char_count + 1)
#| if c2.is_trailing_surrogate() {
#| continue char_count + 2, utf16_offset + 1
#| } else {
#| abort(\"invalid surrogate pair\")
#| }
#| }
#| } else {
#| guard utf16_offset == index && char_count < charcode_len else {
#| abort(\"index out of bounds\")
#| }
#| let c1 = self.unsafe_charcode_at(char_count)
#| if c1.is_leading_surrogate() && char_count + 1 < charcode_len {
#| let c2 = self.unsafe_charcode_at(char_count + 1)
#| if c2.is_trailing_surrogate() {
#| code_point_of_surrogate_pair(c1, c2)
#| } else {
#| abort(\"invalid surrogate pair\")
#| }
#| } else {
#| c1.unsafe_to_char()
#| }
#| } }
),
),
"charcode_at": build(
(
#|pub fn String::charcode_at(self : String, index : Int) -> Int { self[index] }
),
),
"unsafe_char_at": build(
(
#|pub fn String::unsafe_char_at(self : String, index : Int) -> Char { let c1 = self.unsafe_charcode_at(index)
#| if c1.is_leading_surrogate() {
#| let c2 = self.unsafe_charcode_at(index + 1)
#| code_point_of_surrogate_pair(c1, c2)
#| } else {
#| c1.unsafe_to_char()
#| } }
),
),
"new": build(
(
#|pub fn[K, V] Map::new(capacity~ : Int = 8) -> Map[K, V] { let capacity = capacity.next_power_of_two()
#| {
#| size: 0,
#| capacity,
#| capacity_mask: capacity - 1,
#| grow_at: calc_grow_threshold(capacity),
#| entries: FixedArray::make(capacity, None),
#| head: None,
#| tail: -1,
#| } }
),
),
"from_array": build(
(
#|pub fn[K : Hash + Eq, V] Map::from_array(arr : Array[(K, V)]) -> Map[K, V] { let m = Map::new(capacity=arr.length())
#| arr.each(e => m.set(e.0, e.1))
#| m }
),
),
"set": build(
(
#|pub fn[K : Hash + Eq, V] Map::set(self : Map[K, V], key : K, value : V) -> Unit { if self.size >= self.grow_at {
#| self.grow()
#| }
#| let hash = key.hash()
#| let (idx, psl) = for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries[idx] {
#| None => break (idx, psl)
#| Some(curr_entry) => {
#| if curr_entry.hash == hash && curr_entry.key == key {
#| curr_entry.value = value
#| return
#| }
#| if psl > curr_entry.psl {
#| self.push_away(idx, curr_entry)
#| break (idx, psl)
#| }
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| }
#| }
#| let entry = { prev: self.tail, next: None, psl, key, value, hash }
#| self.add_entry_to_tail(idx, entry) }
),
),
"get": build(
(
#|pub fn[K : Hash + Eq, V] Map::get(self : Map[K, V], key : K) -> V? { let hash = key.hash()
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries[idx] is Some(entry) else { break None }
#| if entry.hash == hash && entry.key == key {
#| break Some(entry.value)
#| }
#| if i > entry.psl {
#| break None
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| } }
),
),
"op_get": build(
(
#|pub fn[K : Hash + Eq, V] Map::op_get(self : Map[K, V], key : K) -> V? { self.get(key) }
),
),
"contains": build(
(
#|pub fn[K : Hash + Eq, V] Map::contains(self : Map[K, V], key : K) -> Bool { // inline Map::get to avoid boxing
#| let hash = key.hash()
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries[idx] is Some(entry) else { break false }
#| if entry.hash == hash && entry.key == key {
#| break true
#| }
#| if i > entry.psl {
#| break false
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| } }
),
),
"remove": build(
(
#|pub fn[K : Hash + Eq, V] Map::remove(self : Map[K, V], key : K) -> Unit { let hash = key.hash()
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries[idx] is Some(entry) else { break }
#| if entry.hash == hash && entry.key == key {
#| self.remove_entry(entry)
#| self.shift_back(idx)
#| self.size -= 1
#| break
#| }
#| if i > entry.psl {
#| break
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| } }
),
),
"remove_entry": build(
(
#|fn[K, V] Map::remove_entry(self : Map[K, V], entry : Entry[K, V]) -> Unit { match entry.prev {
#| -1 => self.head = entry.next
#| idx => self.entries[idx].unwrap().next = entry.next
#| }
#| match entry.next {
#| None => self.tail = entry.prev
#| Some(next) => next.prev = entry.prev
#| } }
),
),
"shift_back": build(
(
#|fn[K, V] Map::shift_back(self : Map[K, V], idx : Int) -> Unit { let next = (idx + 1) & self.capacity_mask
#| match self.entries[next] {
#| None | Some({ psl: 0, .. }) => self.entries[idx] = None
#| Some(entry) => {
#| entry.psl -= 1
#| self.set_entry(entry, idx)
#| self.shift_back(next)
#| }
#| } }
),
),
"grow": build(
(
#|fn[K : Hash + Eq, V] Map::grow(self : Map[K, V]) -> Unit { let old_head = self.head
#| let new_capacity = self.capacity << 1
#| self.entries = FixedArray::make(new_capacity, None)
#| self.capacity = new_capacity
#| self.capacity_mask = new_capacity - 1
#| self.grow_at = calc_grow_threshold(self.capacity)
#| self.size = 0
#| self.head = None
#| self.tail = -1
#| loop old_head {
#| Some({ next, key, value, .. }) => {
#| self.set(key, value)
#| continue next
#| }
#| None => break
#| } }
),
),
"calc_grow_threshold": build(
(
#|fn calc_grow_threshold(capacity : Int) -> Int { capacity * 13 / 16 }
),
),
"size": build(
(
#|pub fn[K, V] Map::size(self : Map[K, V]) -> Int { self.size }
),
),
"capacity": build(
(
#|pub fn[K, V] Map::capacity(self : Map[K, V]) -> Int { self.capacity }
),
),
"is_empty": build(
(
#|pub fn[K, V] Map::is_empty(self : Map[K, V]) -> Bool { self.size == 0 }
),
),
"clear": build(
(
#|pub fn[K, V] Map::clear(self : Map[K, V]) -> Unit { self.entries.fill(None)
#| self.size = 0
#| self.head = None
#| self.tail = -1 }
),
),
"iter": build(
(
#|pub fn[K, V] Map::iter(self : Map[K, V]) -> Iter[(K, V)] { Iter::new(yield_ => loop self.head {
#| Some({ key, value, next, .. }) => {
#| guard yield_((key, value)) is IterContinue else { break IterEnd }
#| continue next
#| }
#| None => break IterContinue
#| }) }
),
),
"iter2": build(
(
#|pub fn[K, V] Map::iter2(self : Map[K, V]) -> Iter2[K, V] { Iter2::new(yield_ => loop self.head {
#| Some({ key, value, next, .. }) => {
#| guard yield_(key, value) is IterContinue else { break IterEnd }
#| continue next
#| }
#| None => IterContinue
#| }) }
),
),
"keys": build(
(
#|pub fn[K, V] Map::keys(self : Map[K, V]) -> Iter[K] { Iter::new(yield_ => loop self.head {
#| Some({ key, next, .. }) => {
#| guard yield_(key) is IterContinue else { break IterEnd }
#| continue next
#| }
#| None => IterContinue
#| }) }
),
),
"values": build(
(
#|pub fn[K, V] Map::values(self : Map[K, V]) -> Iter[V] { Iter::new(yield_ => loop self.head {
#| Some({ value, next, .. }) => {
#| guard yield_(value) is IterContinue else { break IterEnd }
#| continue next
#| }
#| None => IterContinue
#| }) }
),
),
"to_array": build(
(
#|pub fn[K, V] Map::to_array(self : Map[K, V]) -> Array[(K, V)] { let arr = Array::make_uninit(self.size)
#| let mut i = 0
#| loop self.head {
#| Some({ key, value, next, .. }) => {
#| arr.unsafe_set(i, (key, value))
#| i += 1
#| continue next
#| }
#| None => break
#| }
#| arr }
),
),
"of": build(
(
#|pub fn[K : Hash + Eq, V] Map::of(arr : FixedArray[(K, V)]) -> Map[K, V] { let length = arr.length()
#| let m = Map::new(capacity=length)
#| // arr.iter((e) => { m.set(e.0, e.1) })
#| for i in 0.. Map[K, V] { let m = {}
#| for e in iter {
#| m.set(e.0, e.1)
#| }
#| m }
),
),
"map": build(
(
#|pub fn[K, V, V2] Map::map(self : Map[K, V], f : (K, V) -> V2) -> Map[K, V2] { // copy structure
#| let other = {
#| capacity: self.capacity,
#| entries: FixedArray::make(self.capacity, None),
#| size: self.size,
#| capacity_mask: self.capacity_mask,
#| grow_at: self.grow_at,
#| head: None,
#| tail: self.tail,
#| }
#| if self.size == 0 {
#| return other
#| }
#| guard self.entries[self.tail] is Some(last)
#| loop (last, self.tail, None) {
#| ({ prev, psl, hash, key, value, .. }, idx, next) => {
#| let new_value = f(key, value)
#| let new_entry = { prev, next, psl, hash, key, value: new_value }
#| other.entries[idx] = Some(new_entry)
#| if prev != -1 {
#| continue (self.entries[prev].unwrap(), prev, Some(new_entry))
#| } else {
#| other.head = Some(new_entry)
#| }
#| }
#| }
#| other }
),
),
"copy": build(
(
#|pub fn[K, V] Map::copy(self : Map[K, V]) -> Map[K, V] { // copy structure
#| let other = {
#| capacity: self.capacity,
#| entries: FixedArray::make(self.capacity, None),
#| size: self.size,
#| capacity_mask: self.capacity_mask,
#| grow_at: self.grow_at,
#| head: None,
#| tail: self.tail,
#| }
#| if self.size == 0 {
#| return other
#| }
#| guard self.entries[self.tail] is Some(last)
#| loop (last, self.tail, None) {
#| ({ prev, psl, hash, key, value, .. }, idx, next) => {
#| let new_entry = { prev, next, psl, hash, key, value }
#| other.entries[idx] = Some(new_entry)
#| if prev != -1 {
#| continue (self.entries[prev].unwrap(), prev, Some(new_entry))
#| } else {
#| other.head = Some(new_entry)
#| }
#| }
#| }
#| other }
),
),
"new": build(
(
#|pub fn StringBuilder::new(size_hint~ : Int = 0) -> StringBuilder { ignore(size_hint)
#| { val: \"\" } }
),
),
"is_empty": build(
(
#|pub fn StringBuilder::is_empty(self : StringBuilder) -> Bool { self.val == \"\" }
),
),
"char_to_string": build(
(
#|fn char_to_string(char : Char) -> String { [char] }
),
),
"to_string": build(
(
#|pub fn StringBuilder::to_string(self : StringBuilder) -> String { self.val }
),
),
"reset": build(
(
#|pub fn StringBuilder::reset(self : StringBuilder) -> Unit { self.val = \"\" }
),
),
"op_lt": build(
(
#|pub fn[T : Compare] op_lt(self_ : T, other : T) -> Bool { self_.compare(other).is_neg() }
),
),
"op_gt": build(
(
#|pub fn[T : Compare] op_gt(self_ : T, other : T) -> Bool { self_.compare(other).is_pos() }
),
),
"op_le": build(
(
#|pub fn[T : Compare] op_le(self_ : T, other : T) -> Bool { self_.compare(other).is_non_pos() }
),
),
"op_ge": build(
(
#|pub fn[T : Compare] op_ge(self_ : T, other : T) -> Bool { self_.compare(other).is_non_neg() }
),
),
"op_notequal": build(
(
#|pub fn[T : Eq] op_notequal(x : T, y : T) -> Bool { !(x == y) }
),
),
"new": build(
(
#|pub fn StringBuilder::new(size_hint~ : Int = 0) -> StringBuilder { let initial = if size_hint < 1 { 1 } else { size_hint }
#| let data : FixedArray[Byte] = FixedArray::make(initial, 0)
#| { data, len: 0 } }
),
),
"is_empty": build(
(
#|pub fn StringBuilder::is_empty(self : StringBuilder) -> Bool { self.len == 0 }
),
),
"to_string": build(
(
#|pub fn StringBuilder::to_string(self : StringBuilder) -> String { self.data
#| .unsafe_reinterpret_as_bytes()
#| .to_unchecked_string(offset=0, length=self.len) }
),
),
"reset": build(
(
#|pub fn StringBuilder::reset(self : StringBuilder) -> Unit { self.len = 0 }
),
),
"fail": build(
(
#|pub fn[T] fail(msg : String, loc~ : SourceLoc) -> T raise Failure { raise Failure(\"\\{loc} FAILED: \\{msg}\") }
),
),
"make": build(
(
#|pub fn String::make(length : Int, value : Char) -> String { guard length >= 0 else { abort(\"invalid length\") }
#| if value.to_int() <= 0xFFFF {
#| unsafe_make_string(length, value)
#| } else {
#| let buf = StringBuilder::new(size_hint=2 * length)
#| for _ in 0.. Char { ((leading - 0xD800) * 0x400 + trailing - 0xDC00 + 0x10000).unsafe_to_char() }
),
),
"unsafe_substring": build(
(
#|fn unsafe_substring(str : String, start : Int, end : Int) -> String { let len = end - start
#| let bytes = FixedArray::make(len * 2, Byte::default())
#| bytes.blit_from_string(0, str, start, len)
#| bytes.unsafe_reinterpret_as_bytes().to_unchecked_string() }
),
),
"substring": build(
(
#|pub fn String::substring(self : String, start~ : Int = 0, end? : Int) -> String { let len = self.length()
#| let end = match end {
#| Some(end) => end
#| None => len
#| }
#| guard start >= 0 && start <= end && end <= len
#| unsafe_substring(self, start, end) }
),
),
"to_int64": build(
(
#|pub fn Double::to_int64(self : Double) -> Int64 { if self != self {
#| 0
#| } else if self >= 9223372036854775807 {
#| 9223372036854775807L
#| } else if self <= -9223372036854775808 {
#| -9223372036854775808L
#| } else {
#| self.to_unchecked_int64()
#| } }
),
),
"to_uint64": build(
(
#|pub fn Double::to_uint64(self : Double) -> UInt64 { if self != self {
#| 0
#| } else if self >= 9223372036854775807 {
#| 18446744073709551615UL
#| } else if self <= 0 {
#| 0UL
#| } else {
#| self.to_unchecked_uint64()
#| } }
),
),
"to_json": build(
(
#|pub fn ArgsLoc::to_json(self : ArgsLoc) -> String { let buf = StringBuilder::new(size_hint=10)
#| let ArgsLoc(self) = self
#| buf.write_char('[')
#| for i in 0.. buf.write_string(\"null\")
#| Some(loc) => loc.to_string() |> Show::output(buf)
#| }
#| }
#| buf.write_char(']')
#| buf.to_string() }
),
),
"output": build(
(
#|fn Int64::output(self : Int64, logger : &Logger, radix~ : Int = 10) -> Unit { fn abs(n : Int64) -> Int64 {
#| if n < 0L {
#| 0L - n
#| } else {
#| n
#| }
#| }
#| if self < 0L {
#| logger.write_char('-')
#| }
#| let radix : Int64 = radix.to_int64()
#| fn write_digits(num : Int64) {
#| let num2 = num / radix
#| if num2 != 0L {
#| write_digits(num2)
#| }
#| logger.write_char(
#| ALPHABET.charcode_at(abs(num % radix).to_int()).unsafe_to_char(),
#| )
#| }
#| write_digits(abs(self)) }
),
),
"output": build(
(
#|fn Int::output(self : Int, logger : &Logger, radix~ : Int = 10) -> Unit { fn abs(n : Int) -> Int {
#| if n < 0 {
#| 0 - n
#| } else {
#| n
#| }
#| }
#| if self < 0 {
#| logger.write_char('-')
#| }
#| fn write_digits(num : Int) {
#| let num2 = num / radix
#| if num2 != 0 {
#| write_digits(num2)
#| }
#| logger.write_char(ALPHABET.charcode_at(abs(num % radix)).unsafe_to_char())
#| }
#| write_digits(abs(self)) }
),
),
"output": build(
(
#|fn UInt::output(self : UInt, logger : &Logger, radix~ : Int = 10) -> Unit { let radix : UInt = radix.reinterpret_as_uint()
#| fn write_digits(num : UInt) {
#| let num2 = num / radix
#| if num2 != 0U {
#| write_digits(num2)
#| }
#| logger.write_char(
#| ALPHABET.charcode_at((num % radix).reinterpret_as_int()).unsafe_to_char(),
#| )
#| }
#| write_digits(self) }
),
),
"output": build(
(
#|fn UInt64::output(self : UInt64, logger : &Logger, radix~ : Int = 10) -> Unit { let radix : UInt64 = radix.to_uint64()
#| fn write_digits(num : UInt64) {
#| let num2 = num / radix
#| if num2 != 0UL {
#| write_digits(num2)
#| }
#| logger.write_char(
#| ALPHABET.charcode_at((num % radix).to_int()).unsafe_to_char(),
#| )
#| }
#| write_digits(self) }
),
),
"output_size_hint": build(
(
#|fn Int64::output_size_hint(radix~ : Int = 10) -> Int { match radix {
#| 2..<7 => 70 // max length is 64, 70 is enough
#| 8..<15 => 30 // max length is 23, 30 is enough
#| 16..=36 => 20 // max length is 17, 20 is enough
#| _ => abort(\"radix must be between 2 and 36\")
#| } }
),
),
"output_size_hint": build(
(
#|fn Int::output_size_hint(radix~ : Int = 10) -> Int { match radix {
#| 2..<7 => 36 // max length is 32, 36 is enough
#| 8..<15 => 18 // max length is 12, 18 is enough
#| 16..=36 => 10 // max length is 8, 10 is enough
#| _ => abort(\"radix must be between 2 and 36\")
#| } }
),
),
"output_size_hint": build(
(
#|fn UInt::output_size_hint(radix~ : Int = 10) -> Int { Int::output_size_hint(radix~) }
),
),
"output_size_hint": build(
(
#|fn UInt64::output_size_hint(radix~ : Int = 10) -> Int { Int64::output_size_hint(radix~) }
),
),
"to_int": build(
(
#|pub fn Double::to_int(self : Double) -> Int { if self != self {
#| 0
#| } else if self >= 2147483647 {
#| 2147483647
#| } else if self <= -2147483648 {
#| -2147483648
#| } else {
#| self.to_unchecked_int()
#| } }
),
),
"makei": build(
(
#|pub fn Bytes::makei(length : Int, value : (Int) -> Byte raise?) -> Bytes raise? { if length <= 0 {
#| return []
#| }
#| let arr = FixedArray::make(length, value(0))
#| for i in 1.. Int { guard self >= 0
#| if self <= 1 {
#| return 1
#| }
#| // The largest power of 2 that fits in a 32-bit signed integer is 2^30
#| let max_power_of_two = 1073741824 // 2^30
#| if self > max_power_of_two {
#| return max_power_of_two
#| }
#| // 2147483647 is the largest value of an integer
#| (2147483647 >> ((self - 1).clz() - 1)) + 1 }
),
),
"min": build(
(
#|pub fn Int::min(self : Int, other : Int) -> Int { if self < other {
#| self
#| } else {
#| other
#| } }
),
),
"max": build(
(
#|pub fn Int::max(self : Int, other : Int) -> Int { if self > other {
#| self
#| } else {
#| other
#| } }
),
),
"clamp": build(
(
#|pub fn Int::clamp(self : Int, min~ : Int, max~ : Int) -> Int { guard min <= max
#| if self < min {
#| min
#| } else if self > max {
#| max
#| } else {
#| self
#| } }
),
),
"is_leading_surrogate": build(
(
#|pub fn Int::is_leading_surrogate(self : Int) -> Bool { 0xD800 <= self && self <= 0xDBFF }
),
),
"is_trailing_surrogate": build(
(
#|pub fn Int::is_trailing_surrogate(self : Int) -> Bool { 0xDC00 <= self && self <= 0xDFFF }
),
),
"is_surrogate": build(
(
#|pub fn Int::is_surrogate(self : Int) -> Bool { 0xD800 <= self && self <= 0xDFFF }
),
),
"println": build(
(
#|pub fn[T : Show] println(input : T) -> Unit { println_mono(input.to_string()) }
),
),
"base64_encode": build(
(
#|fn base64_encode(data : FixedArray[Byte]) -> String { let base64 = b\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"
#| let buf = StringBuilder::new()
#| let len = data.length()
#| let rem = len % 3
#| for i = 0; i < len - rem; i = i + 3 {
#| let b0 = data[i].to_int()
#| let b1 = data[i + 1].to_int()
#| let b2 = data[i + 2].to_int()
#| let x0 = base64[(b0 & 0xFC) >> 2]
#| let x1 = base64[((b0 & 0x03) << 4) | ((b1 & 0xF0) >> 4)]
#| let x2 = base64[((b1 & 0x0F) << 2) | ((b2 & 0xC0) >> 6)]
#| let x3 = base64[b2 & 0x3F]
#| buf.write_char(x0.to_char())
#| buf.write_char(x1.to_char())
#| buf.write_char(x2.to_char())
#| buf.write_char(x3.to_char())
#| }
#| if rem == 1 {
#| let b0 = data[len - 1].to_int()
#| let x0 = base64[(b0 & 0xFC) >> 2]
#| let x1 = base64[(b0 & 0x03) << 4]
#| buf.write_char(x0.to_char())
#| buf.write_char(x1.to_char())
#| buf.write_char('=')
#| buf.write_char('=')
#| } else if rem == 2 {
#| let b0 = data[len - 2].to_int()
#| let b1 = data[len - 1].to_int()
#| let x0 = base64[(b0 & 0xFC) >> 2]
#| let x1 = base64[((b0 & 0x03) << 4) | ((b1 & 0xF0) >> 4)]
#| let x2 = base64[(b1 & 0x0F) << 2]
#| buf.write_char(x0.to_char())
#| buf.write_char(x1.to_char())
#| buf.write_char(x2.to_char())
#| buf.write_char('=')
#| }
#| buf.to_string() }
),
),
"base64_encode_string_codepoint": build(
(
#|fn base64_encode_string_codepoint(s : String) -> String { // the input string is expected to be valid utf-16 string
#| let codepoint_length = s.char_length()
#| let data : FixedArray[Byte] = FixedArray::make(codepoint_length * 4, 0)
#| for i = 0, utf16_index = 0
#| i < codepoint_length
#| i = i + 1, utf16_index = utf16_index + 1 {
#| let c = s.unsafe_char_at(utf16_index).to_int()
#| if c > 0xFFFF {
#| data[i * 4] = (c & 0xFF).to_byte()
#| data[i * 4 + 1] = ((c >> 8) & 0xFF).to_byte()
#| data[i * 4 + 2] = ((c >> 16) & 0xFF).to_byte()
#| data[i * 4 + 3] = ((c >> 24) & 0xFF).to_byte()
#| continue i + 1, utf16_index + 2
#| } else {
#| data[i * 4] = (c & 0xFF).to_byte()
#| data[i * 4 + 1] = ((c >> 8) & 0xFF).to_byte()
#| data[i * 4 + 2] = 0
#| data[i * 4 + 3] = 0
#| }
#| }
#| base64_encode(data) }
),
),
"debug_string": build(
(
#|fn[T : Show] debug_string(t : T) -> String { let buf = StringBuilder::new(size_hint=50)
#| t.output(buf)
#| buf.to_string() }
),
),
"assert_true": build(
(
#|pub fn assert_true(x : Bool, msg? : String, loc~ : SourceLoc) -> Unit raise { if !x {
#| let fail_msg = match msg {
#| Some(msg) => msg
#| None => \"`\\{x}` is not true\"
#| }
#| fail(fail_msg, loc~)
#| } }
),
),
"assert_false": build(
(
#|pub fn assert_false(x : Bool, msg? : String, loc~ : SourceLoc) -> Unit raise { if x {
#| let fail_msg = match msg {
#| Some(msg) => msg
#| None => \"`\\{x}` is not false\"
#| }
#| fail(fail_msg, loc~)
#| } }
),
),
"alphabet": build(
(
#|fn alphabet(x : Int) -> String { match x {
#| 0 => \"0\"
#| 1 => \"1\"
#| 2 => \"2\"
#| 3 => \"3\"
#| 4 => \"4\"
#| 5 => \"5\"
#| 6 => \"6\"
#| 7 => \"7\"
#| 8 => \"8\"
#| 9 => \"9\"
#| 10 => \"A\"
#| 11 => \"B\"
#| 12 => \"C\"
#| 13 => \"D\"
#| 14 => \"E\"
#| 15 => \"F\"
#| _ => abort(\"impossible\")
#| } }
),
),
"to_string": build(
(
#|pub fn Byte::to_string(self : Byte) -> String { let i = self.to_int()
#| let hi = alphabet(i / 16)
#| let lo = alphabet(i % 16)
#| \"b'\\\\x\\{hi}\\{lo}'\" }
),
),
"lnot": build(
(
#|pub fn Byte::lnot(self : Byte) -> Byte { self.to_int().lnot().to_byte() }
),
),
"to_uint": build(
(
#|pub fn Byte::to_uint(self : Byte) -> UInt { self.to_int().reinterpret_as_uint() }
),
),
}
},
)
///|
let moonbitlang_core_byte_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/byte",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
fn(_env, build) {
{
"to_uint64": build(
(
#|pub fn to_uint64(self : Byte) -> UInt64 { self.to_uint().to_uint64() }
),
),
"popcnt": build(
(
#|pub fn popcnt(self : Byte) -> Int { let mut n = self
#| n = (n & 0x55) + ((n >> 1) & 0x55)
#| n = (n & 0x33) + ((n >> 2) & 0x33)
#| n = (n & 0x0F) + ((n >> 4) & 0x0F)
#| n.to_int() }
),
),
}
},
)
///|
let moonbitlang_core_bytes_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/bytes",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
fn(_env, build) {
{
"gPRIME1": (None, String("0x9E3779B1")),
"gPRIME2": (None, String("0x85EBCA77")),
"gPRIME3": (None, String("0xC2B2AE3D")),
"gPRIME4": (None, String("0x27D4EB2F")),
"gPRIME5": (None, String("0x165667B1")),
"xxhash32": build(
(
#|fn xxhash32(input : Bytes, seed : Int) -> Int { let len = input.length()
#| let h = (if len >= 16 {
#| h16bytes(input, 0, len, seed)
#| } else {
#| seed + gPRIME5
#| }) +
#| len
#| finalize(h, input, len & -16, len & 0xF) }
),
),
"rotl": build(
(
#|fn rotl(x : Int, r : Int) -> Int { (x << r) | (x.reinterpret_as_uint() >> (32 - r)).reinterpret_as_int() }
),
),
"round": build(
(
#|fn round(acc : Int, input : Int) -> Int { rotl(acc + input * gPRIME2, 13) * gPRIME1 }
),
),
"avalanche_step": build(
(
#|fn avalanche_step(h : Int, rshift : Int, prime : Int) -> Int { (h ^ (h.reinterpret_as_uint() >> rshift).reinterpret_as_int()) * prime }
),
),
"avalanche": build(
(
#|fn avalanche(h : Int) -> Int { avalanche_step(
#| avalanche_step(avalanche_step(h, 15, gPRIME2), 13, gPRIME3),
#| 16,
#| 1,
#| ) }
),
),
"endian32": build(
(
#|fn endian32(input : Bytes, cur : Int) -> Int { input[cur + 0].to_int() |
#| (
#| (input[cur + 1].to_int() << 8) |
#| ((input[cur + 2].to_int() << 16) | (input[cur + 3].to_int() << 24))
#| ) }
),
),
"fetch32": build(
(
#|fn fetch32(input : Bytes, cur : Int, v : Int) -> Int { round(v, endian32(input, cur)) }
),
),
"finalize": build(
(
#|fn finalize(h : Int, input : Bytes, cur : Int, remain : Int) -> Int { if remain >= 4 {
#| finalize(
#| rotl(h + endian32(input, cur) * gPRIME3, 17) * gPRIME4,
#| input,
#| cur + 4,
#| remain - 4,
#| )
#| } else if remain > 0 {
#| finalize(
#| rotl(h + input[cur].to_int() * gPRIME5, 11) * gPRIME1,
#| input,
#| cur + 1,
#| remain - 1,
#| )
#| } else {
#| avalanche(h)
#| } }
),
),
"h16bytes": build(
(
#|fn h16bytes(input : Bytes, cur : Int, len : Int, seed : Int) -> Int { _h16bytes(
#| input,
#| cur,
#| len,
#| seed + gPRIME1 + gPRIME2,
#| seed + gPRIME2,
#| seed,
#| seed - gPRIME1,
#| ) }
),
),
"length": build(
(
#|pub fn View::length(self : View) -> Int { self.len() }
),
),
"op_get": build(
(
#|pub fn View::op_get(self : View, index : Int) -> Byte { guard index >= 0 && index < self.len() else {
#| abort(
#| \"index out of bounds: the len is from 0 to \\{self.len()} but the index is \\{index}\",
#| )
#| }
#| self.bytes()[self.start() + index] }
),
),
"get": build(
(
#|pub fn View::get(self : View, index : Int) -> Byte? { guard index >= 0 && index < self.len() else { None }
#| Some(self.bytes().unsafe_get(self.start() + index)) }
),
),
"unsafe_get": build(
(
#|pub fn View::unsafe_get(self : View, index : Int) -> Byte { self.bytes()[self.start() + index] }
),
),
"op_as_view": build(
(
#|pub fn Bytes::op_as_view(self : Bytes, start~ : Int = 0, end? : Int) -> View { let len = self.length()
#| let end = match end {
#| None => len
#| Some(end) => if end < 0 { len + end } else { end }
#| }
#| let start = if start < 0 { len + start } else { start }
#| guard start >= 0 && start <= end && end <= len else {
#| abort(\"Invalid index for View\")
#| }
#| View::make(self, start, end - start) }
),
),
"op_as_view": build(
(
#|pub fn View::op_as_view(self : View, start~ : Int = 0, end? : Int) -> View { let len = self.length()
#| let end = match end {
#| None => len
#| Some(end) => if end < 0 { len + end } else { end }
#| }
#| let start = if start < 0 { len + start } else { start }
#| guard start >= 0 && start <= end && end <= len else {
#| abort(\"Invalid index for View\")
#| }
#| View::make(self.bytes(), self.start() + start, end - start) }
),
),
"iter": build(
(
#|pub fn View::iter(self : View) -> Iter[Byte] { Iter::new(yield_ => for i in 0.. UInt { (self[0].to_uint() << 24) +
#| (self[1].to_uint() << 16) +
#| (self[2].to_uint() << 8) +
#| self[3].to_uint() }
),
),
"to_uint_le": build(
(
#|pub fn View::to_uint_le(self : View) -> UInt { self[0].to_uint() +
#| (self[1].to_uint() << 8) +
#| (self[2].to_uint() << 16) +
#| (self[3].to_uint() << 24) }
),
),
"to_uint64_be": build(
(
#|pub fn View::to_uint64_be(self : View) -> UInt64 { (self[0].to_uint().to_uint64() << 56) +
#| (self[1].to_uint().to_uint64() << 48) +
#| (self[2].to_uint().to_uint64() << 40) +
#| (self[3].to_uint().to_uint64() << 32) +
#| (self[4].to_uint().to_uint64() << 24) +
#| (self[5].to_uint().to_uint64() << 16) +
#| (self[6].to_uint().to_uint64() << 8) +
#| self[7].to_uint().to_uint64() }
),
),
"to_uint64_le": build(
(
#|pub fn View::to_uint64_le(self : View) -> UInt64 { self[0].to_uint().to_uint64() +
#| (self[1].to_uint().to_uint64() << 8) +
#| (self[2].to_uint().to_uint64() << 16) +
#| (self[3].to_uint().to_uint64() << 24) +
#| (self[4].to_uint().to_uint64() << 32) +
#| (self[5].to_uint().to_uint64() << 40) +
#| (self[6].to_uint().to_uint64() << 48) +
#| (self[7].to_uint().to_uint64() << 56) }
),
),
"to_int_be": build(
(
#|pub fn View::to_int_be(self : View) -> Int { self.to_uint_be().reinterpret_as_int() }
),
),
"to_int_le": build(
(
#|pub fn View::to_int_le(self : View) -> Int { self.to_uint_le().reinterpret_as_int() }
),
),
"to_int64_be": build(
(
#|pub fn View::to_int64_be(self : View) -> Int64 { self.to_uint64_be().reinterpret_as_int64() }
),
),
"to_int64_le": build(
(
#|pub fn View::to_int64_le(self : View) -> Int64 { self.to_uint64_le().reinterpret_as_int64() }
),
),
"to_float_be": build(
(
#|pub fn View::to_float_be(self : View) -> Float { self.to_uint_be().reinterpret_as_float() }
),
),
"to_float_le": build(
(
#|pub fn View::to_float_le(self : View) -> Float { self.to_uint_le().reinterpret_as_float() }
),
),
"to_double_be": build(
(
#|pub fn View::to_double_be(self : View) -> Double { self.to_uint64_be().reinterpret_as_double() }
),
),
"to_double_le": build(
(
#|pub fn View::to_double_le(self : View) -> Double { self.to_uint64_le().reinterpret_as_double() }
),
),
"data": build(
(
#|pub fn View::data(self : View) -> Bytes { self.bytes() }
),
),
"start_offset": build(
(
#|pub fn View::start_offset(self : View) -> Int { self.start() }
),
),
"to_bytes": build(
(
#|pub fn View::to_bytes(self : View) -> Bytes { if self.len() == 0 && self.len() == self.bytes().length() {
#| return self.bytes()
#| }
#| let bytes = FixedArray::make(self.len(), (0 : Byte))
#| bytes.blit_from_bytes(0, self.bytes(), self.start_offset(), self.len())
#| unsafe_to_bytes(bytes) }
),
),
"from_array": build(
(
#|pub fn Bytes::from_array(arr : Array[Byte]) -> Bytes { Bytes::makei(arr.length(), i => arr[i]) }
),
),
"from_array": build(
(
#|pub fn from_array(arr : Array[Byte]) -> Bytes { Bytes::makei(arr.length(), i => arr[i]) }
),
),
"from_fixedarray": build(
(
#|pub fn Bytes::from_fixedarray(arr : FixedArray[Byte], len? : Int) -> Bytes { let len = match len {
#| None => arr.length()
#| Some(x) => x
#| }
#| Bytes::makei(len, i => arr[i]) }
),
),
"from_fixedarray": build(
(
#|pub fn from_fixedarray(arr : FixedArray[Byte], len? : Int) -> Bytes { Bytes::from_fixedarray(arr, len?) }
),
),
"to_fixedarray": build(
(
#|pub fn to_fixedarray(self : Bytes, len? : Int) -> FixedArray[Byte] { let len = match len {
#| None => self.length()
#| Some(x) => x
#| }
#| let arr = FixedArray::make(len, Byte::default())
#| for i in 0.. Bytes { from_array(iter.collect()) }
),
),
"from_iter": build(
(
#|pub fn from_iter(iter : Iter[Byte]) -> Bytes { from_array(iter.collect()) }
),
),
"of": build(
(
#|pub fn Bytes::of(arr : FixedArray[Byte]) -> Bytes { Bytes::makei(arr.length(), i => arr[i]) }
),
),
"of": build(
(
#|pub fn of(arr : FixedArray[Byte]) -> Bytes { Bytes::makei(arr.length(), i => arr[i]) }
),
),
"to_array": build(
(
#|pub fn to_array(self : Bytes) -> Array[Byte] { let len = self.length()
#| let rv = Array::make(len, b'0')
#| for i in 0.. Iter[Byte] { Iter::new(yield_ => for i in 0.. Iter2[Int, Byte] { Iter2::new(yield_ => for i in 0.. Byte? { guard index >= 0 && index < self.length() else { None }
#| Some(self[index]) }
),
),
"default": build(
(
#|pub fn default() -> Bytes { b\"\" }
),
),
}
},
)
///|
let moonbitlang_core_char_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/char",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
fn(_env, build) {
{
"is_ascii": build(
(
#|pub fn Char::is_ascii(self : Self) -> Bool { self is ('\\u{00}'..='\\u{7F}') }
),
),
"is_ascii_alphabetic": build(
(
#|pub fn Char::is_ascii_alphabetic(self : Self) -> Bool { self is ('A'..='Z' | 'a'..='z') }
),
),
"is_ascii_control": build(
(
#|pub fn Char::is_ascii_control(self : Self) -> Bool { self is ('\\u{00}'..='\\u{1F}' | '\\u{7F}') }
),
),
"is_ascii_digit": build(
(
#|pub fn Char::is_ascii_digit(self : Self) -> Bool { self is ('0'..='9') }
),
),
"is_ascii_graphic": build(
(
#|pub fn Char::is_ascii_graphic(self : Self) -> Bool { self is ('\\u{21}'..='\\u{7E}') }
),
),
"is_ascii_hexdigit": build(
(
#|pub fn Char::is_ascii_hexdigit(self : Self) -> Bool { self is ('0'..='9' | 'A'..='F' | 'a'..='f') }
),
),
"is_ascii_lowercase": build(
(
#|pub fn Char::is_ascii_lowercase(self : Self) -> Bool { self is ('a'..='z') }
),
),
"is_ascii_octdigit": build(
(
#|pub fn Char::is_ascii_octdigit(self : Self) -> Bool { self is ('0'..='7') }
),
),
"is_ascii_punctuation": build(
(
#|pub fn Char::is_ascii_punctuation(self : Self) -> Bool { self
#| is ('\\u{21}'..='\\u{2F}'
#| | '\\u{3A}'..='\\u{40}'
#| | '\\u{5B}'..='\\u{60}'
#| | '\\u{7B}'..='\\u{7E}') }
),
),
"is_ascii_uppercase": build(
(
#|pub fn Char::is_ascii_uppercase(self : Self) -> Bool { self is ('A'..='Z') }
),
),
"is_ascii_whitespace": build(
(
#|pub fn Char::is_ascii_whitespace(self : Self) -> Bool { self is ('\\u{20}' | '\\u{09}' | '\\u{0A}' | '\\u{0B}' | '\\u{0C}' | '\\u{0D}') }
),
),
"is_control": build(
(
#|pub fn Char::is_control(self : Self) -> Bool { self is ('\\u0000'..='\\u001F' | '\\u007F'..='\\u009F') }
),
),
"is_digit": build(
(
#|pub fn Char::is_digit(self : Self, radix : UInt) -> Bool { let v = self.to_uint()
#| match radix {
#| 2..=10 => v >= 48 && v <= radix + 47
#| 11..=36 =>
#| (v >= 48 && v <= 57) ||
#| (v >= 65 && v <= radix + 54) ||
#| (v >= 97 && v <= radix + 86)
#| _ => panic()
#| } }
),
),
"is_whitespace": build(
(
#|pub fn Char::is_whitespace(self : Self) -> Bool { self
#| is ('\\u0009'..='\\u000D'
#| | '\\u0020'
#| | '\\u0085'
#| | '\\u00A0'
#| | '\\u1680'
#| | '\\u2000'..='\\u200A'
#| | '\\u2028'
#| | '\\u2029'
#| | '\\u202F'
#| | '\\u205F'
#| | '\\u3000') }
),
),
"is_numeric": build(
(
#|pub fn Char::is_numeric(self : Self) -> Bool { self
#| is ('\\u0030'..='\\u0039'
#| | '\\u00B2'
#| | '\\u00B3'
#| | '\\u00B9'
#| | '\\u00BC'
#| | '\\u00BD'
#| | '\\u00BE'
#| | '\\u0660'..='\\u0669'
#| | '\\u06F0'..='\\u06F9'
#| | '\\u07C0'..='\\u07F9'
#| | '\\u0966'..='\\u096F'
#| | '\\u09E6'..='\\u09EF'
#| | '\\u09F4'..='\\u09F9'
#| | '\\u0A66'..='\\u0A6F'
#| | '\\u0AE6'..='\\u0AEF'
#| | '\\u0B66'..='\\u0B6F'
#| | '\\u0B72'..='\\u0B77'
#| | '\\u0BE6'..='\\u0BEF'
#| | '\\u0BF0'..='\\u0BF2'
#| | '\\u0C66'..='\\u0C6F'
#| | '\\u0C78'..='\\u0C7E'
#| | '\\u0CE6'..='\\u0CEF'
#| | '\\u0D58'..='\\u0D5E'
#| | '\\u0D66'..='\\u0D6F'
#| | '\\u0D70'..='\\u0D78'
#| | '\\u0DE6'..='\\u0DEF'
#| | '\\u0E50'..='\\u0E59'
#| | '\\u0ED0'..='\\u0ED9'
#| | '\\u0F20'..='\\u0F33'
#| | '\\u1040'..='\\u1049'
#| | '\\u1090'..='\\u1099'
#| | '\\u1369'..='\\u137C'
#| | '\\u16EE'..='\\u16F0'
#| | '\\u17E0'..='\\u17E9'
#| | '\\u17F0'..='\\u17F9'
#| | '\\u1810'..='\\u1819'
#| | '\\u1946'..='\\u194F'
#| | '\\u19D0'..='\\u19DA'
#| | '\\u1A80'..='\\u1A89'
#| | '\\u1A90'..='\\u1A99'
#| | '\\u1B50'..='\\u1B59'
#| | '\\u1BB0'..='\\u1BB9'
#| | '\\u1C40'..='\\u1C49'
#| | '\\u1C50'..='\\u1C59'
#| | '\\u2070'
#| | '\\u2074'..='\\u2079'
#| | '\\u2080'..='\\u2089'
#| | '\\u2150'..='\\u2189'
#| | '\\u2460'..='\\u249B'
#| | '\\u24EA'..='\\u24FF'
#| | '\\u2776'..='\\u2793'
#| | '\\u2CFD'
#| | '\\u3007'
#| | '\\u3021'..='\\u3029'
#| | '\\u3038'..='\\u303A'
#| | '\\u3192'..='\\u3195'
#| | '\\u3220'..='\\u3229'
#| | '\\u3248'..='\\u324F'
#| | '\\u3251'..='\\u325F'
#| | '\\u3280'..='\\u3289'
#| | '\\u32B1'..='\\u32BF'
#| | '\\uA620'..='\\uA629'
#| | '\\uA6E6'..='\\uA6EF'
#| | '\\uA830'..='\\uA835'
#| | '\\uA8D0'..='\\uA8D9'
#| | '\\uA900'..='\\uA909'
#| | '\\uA9D0'..='\\uA9D9'
#| | '\\uA9F0'..='\\uA9F9'
#| | '\\uAA50'..='\\uAA59'
#| | '\\uABF0'..='\\uABF9'
#| | '\\uFF10'..='\\uFF19'
#| | '\\u{10107}'..='\\u{10133}'
#| | '\\u{10140}'..='\\u{10178}'
#| | '\\u{1018A}'..='\\u{1018B}'
#| | '\\u{102E1}'..='\\u{102FB}'
#| | '\\u{10320}'..='\\u{10323}'
#| | '\\u{10341}'
#| | '\\u{1034A}'
#| | '\\u{103D1}'..='\\u{103D5}'
#| | '\\u{104A0}'..='\\u{104A9}'
#| | '\\u{10858}'..='\\u{1085F}'
#| | '\\u{10879}'..='\\u{1087F}'
#| | '\\u{108A7}'..='\\u{108AF}'
#| | '\\u{108FB}'..='\\u{108FF}'
#| | '\\u{10916}'..='\\u{1091B}'
#| | '\\u{109BC}'..='\\u{109BD}'
#| | '\\u{109C0}'..='\\u{109CF}'
#| | '\\u{10A40}'..='\\u{10A48}'
#| | '\\u{10A7D}'..='\\u{10A7E}'
#| | '\\u{10A9D}'..='\\u{10A9F}'
#| | '\\u{10AEB}'..='\\u{10AEF}'
#| | '\\u{10B58}'..='\\u{10B5F}'
#| | '\\u{10B78}'..='\\u{10B7F}'
#| | '\\u{10BA9}'..='\\u{10BAF}'
#| | '\\u{10CFA}'..='\\u{10CFF}'
#| | '\\u{10D30}'..='\\u{10D39}'
#| | '\\u{10D40}'..='\\u{10D49}'
#| | '\\u{10E60}'..='\\u{10E7E}'
#| | '\\u{10F1D}'..='\\u{10F26}'
#| | '\\u{10F51}'..='\\u{10F54}'
#| | '\\u{10FC5}'..='\\u{10FCB}'
#| | '\\u{11052}'..='\\u{1106F}'
#| | '\\u{110F0}'..='\\u{110F9}'
#| | '\\u{11136}'..='\\u{1113F}'
#| | '\\u{111D0}'..='\\u{111D9}'
#| | '\\u{111E1}'..='\\u{111F4}'
#| | '\\u{112F0}'..='\\u{112F9}'
#| | '\\u{11450}'..='\\u{11459}'
#| | '\\u{114D0}'..='\\u{114D9}'
#| | '\\u{11650}'..='\\u{11659}'
#| | '\\u{116C0}'..='\\u{116C9}'
#| | '\\u{116D0}'..='\\u{116E3}'
#| | '\\u{11730}'..='\\u{1173B}'
#| | '\\u{118E0}'..='\\u{118F2}'
#| | '\\u{11950}'..='\\u{11959}'
#| | '\\u{11BF0}'..='\\u{11BF9}'
#| | '\\u{11C50}'..='\\u{11C6C}'
#| | '\\u{11D50}'..='\\u{11D59}'
#| | '\\u{11DA0}'..='\\u{11DA9}'
#| | '\\u{11F50}'..='\\u{11F59}'
#| | '\\u{11FC0}'..='\\u{11FD4}'
#| | '\\u{12400}'..='\\u{1246E}'
#| | '\\u{16130}'..='\\u{16139}'
#| | '\\u{16A60}'..='\\u{16A69}'
#| | '\\u{16AC0}'..='\\u{16AC9}'
#| | '\\u{16B50}'..='\\u{16B59}'
#| | '\\u{16B5B}'..='\\u{16B61}'
#| | '\\u{16D70}'..='\\u{16D79}'
#| | '\\u{16D80}'..='\\u{16E96}'
#| | '\\u{1CCF0}'..='\\u{1CCF9}'
#| | '\\u{1D2C0}'..='\\u{1D2F3}'
#| | '\\u{1D360}'..='\\u{1D378}'
#| | '\\u{1D7CE}'..='\\u{1D7FF}'
#| | '\\u{1E140}'..='\\u{1E149}'
#| | '\\u{1E2F0}'..='\\u{1E2F9}'
#| | '\\u{1E4F0}'..='\\u{1E4F9}'
#| | '\\u{1E5F1}'..='\\u{1E5FA}'
#| | '\\u{1E8C7}'..='\\u{1E8CF}'
#| | '\\u{1E950}'..='\\u{1E959}'
#| | '\\u{1EC71}'..='\\u{1ECB4}'
#| | '\\u{1ED01}'..='\\u{1ED3D}'
#| | '\\u{1F100}'..='\\u{1F10C}'
#| | '\\u{1FBF0}'..='\\u{1FBF9}') }
),
),
"is_printable": build(
(
#|pub fn Char::is_printable(self : Self) -> Bool { // Check for control characters (Cc)
#| if self.is_control() {
#| return false
#| }
#| let self = self.to_int()
#| // Private use areas (Co)
#| if self is (0xE000..=0xF8FF | 0xF0000..=0xFFFFD | 0x100000..=0x10FFFD) {
#| return false
#| }
#| // Format characters (Cf)
#| if self
#| is ('\\u{00AD}'
#| | '\\u{0600}'..='\\u{0605}'
#| | '\\u{061C}'
#| | '\\u{06DD}'
#| | '\\u{070F}'
#| | '\\u{0890}'..='\\u{0891}'
#| | '\\u{08E2}'
#| | '\\u{180E}'
#| | '\\u{200B}'..='\\u{200F}'
#| | '\\u{202A}'..='\\u{202E}'
#| | '\\u{2060}'..='\\u{2064}'
#| | '\\u{2066}'..='\\u{206F}'
#| | '\\u{feff}'
#| | '\\u{FFF9}'..='\\u{FFFB}'
#| | '\\u{110BD}'
#| | '\\u{110CD}'
#| | '\\u{13430}'..='\\u{1343F}'
#| | '\\u{1BCA0}'..='\\u{1BCA3}'
#| | '\\u{1D173}'..='\\u{1D17A}'
#| | '\\u{E0001}'
#| | '\\u{E0020}'..='\\u{E007F}') {
#| return false
#| }
#| // Surrogate (Cs)
#| if self.is_surrogate() {
#| return false
#| }
#| // Line and paragraph separators (Zl, Zp)
#| if self == '\\u{2028}' || self == '\\u{2029}' {
#| return false
#| }
#| // Noncharacter
#| if self
#| is (0xFDD0..=0xFDEF
#| | 0xFFFE..=0xFFFF
#| | 0x1FFFE..=0x1FFFF
#| | 0x2FFFE..=0x2FFFF
#| | 0x3FFFE..=0x3FFFF
#| | 0x4FFFE..=0x4FFFF
#| | 0x5FFFE..=0x5FFFF
#| | 0x6FFFE..=0x6FFFF
#| | 0x7FFFE..=0x7FFFF
#| | 0x8FFFE..=0x8FFFF
#| | 0x9FFFE..=0x9FFFF
#| | 0xAFFFE..=0xAFFFF
#| | 0xBFFFE..=0xBFFFF
#| | 0xCFFFE..=0xCFFFF
#| | 0xDFFFE..=0xDFFFF
#| | 0xEFFFE..=0xEFFFF
#| | 0xFFFFE..=0xFFFFF
#| | 0x10FFFE..=0x10FFFF) {
#| return false
#| }
#| true }
),
),
"to_ascii_lowercase": build(
(
#|pub fn Char::to_ascii_lowercase(self : Self) -> Char { if self.is_ascii_uppercase() {
#| return (self.to_int() + 32).unsafe_to_char()
#| }
#| self }
),
),
"to_ascii_uppercase": build(
(
#|pub fn Char::to_ascii_uppercase(self : Self) -> Char { if self.is_ascii_lowercase() {
#| return (self.to_int() - 32).unsafe_to_char()
#| }
#| self }
),
),
"char_to_string": build(
(
#|fn char_to_string(char : Char) -> String { [char] }
),
),
"utf16_len": build(
(
#|pub fn Char::utf16_len(self : Self) -> Int { let code = self.to_int()
#| if code <= 0xFFFF {
#| 1
#| } else {
#| 2
#| } }
),
),
"is_bmp": build(
(
#|pub fn Char::is_bmp(self : Self) -> Bool { self.to_int() <= 0xFFFF }
),
),
}
},
)
///|
let moonbitlang_core_cmp_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/cmp",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
fn(_env, build) {
{
"maximum_by_key": build(
(
#|pub fn[T, K : Compare] maximum_by_key(x : T, y : T, f : (T) -> K) -> T { if f(x) > f(y) {
#| x
#| } else {
#| y
#| } }
),
),
"minimum_by_key": build(
(
#|pub fn[T, K : Compare] minimum_by_key(x : T, y : T, f : (T) -> K) -> T { if f(x) > f(y) {
#| y
#| } else {
#| x
#| } }
),
),
"maximum": build(
(
#|pub fn[T : Compare] maximum(x : T, y : T) -> T { if x > y {
#| x
#| } else {
#| y
#| } }
),
),
"minimum": build(
(
#|pub fn[T : Compare] minimum(x : T, y : T) -> T { if x > y {
#| y
#| } else {
#| x
#| } }
),
),
}
},
)
///|
let moonbitlang_core_deque_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/deque",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/string": moonbitlang_core_string_module,
},
fn(_env, build) {
{
"pop_front_exn": build(
(
#|pub fn[A] pop_front_exn(self : T[A]) -> Unit { self.unsafe_pop_front() }
),
),
"pop_back_exn": build(
(
#|pub fn[A] pop_back_exn(self : T[A]) -> Unit { self.unsafe_pop_back() }
),
),
"filter_map_inplace": build(
(
#|pub fn[A] filter_map_inplace(self : T[A], f : (A) -> A?) -> Unit { self.retain_map(f) }
),
),
"new": build(
(
#|pub fn[A] new(capacity~ : Int = 0) -> T[A] { T::{ buf: UninitializedArray::make(capacity), len: 0, head: 0, tail: 0 } }
),
),
"from_array": build(
(
#|pub fn[A] from_array(arr : Array[A]) -> T[A] { let deq = T::{
#| buf: UninitializedArray::make(arr.length()),
#| len: arr.length(),
#| head: 0,
#| tail: arr.length() - 1,
#| }
#| for i in 0.. T[A] { let len = self.len
#| let deq = T::{
#| buf: UninitializedArray::make(len),
#| len,
#| head: 0,
#| tail: len - 1,
#| }
#| for i, x in self {
#| deq.buf[i] = x
#| }
#| deq }
),
),
"of": build(
(
#|pub fn[A] of(arr : FixedArray[A]) -> T[A] { let deq = T::{
#| buf: UninitializedArray::make(arr.length()),
#| len: arr.length(),
#| head: 0,
#| tail: arr.length() - 1,
#| }
#| for i in 0.. Int { self.len }
),
),
"capacity": build(
(
#|pub fn[A] capacity(self : T[A]) -> Int { self.buf.length() }
),
),
"realloc": build(
(
#|fn[A] realloc(self : T[A]) -> Unit { let old_cap = self.len
#| let new_cap = if old_cap == 0 { 8 } else { old_cap * 2 }
#| let new_buf = UninitializedArray::make(new_cap)
#| if old_cap > 0 {
#| if self.tail >= self.head {
#| for i = self.head, j = 0; i <= self.tail; i = i + 1, j = j + 1 {
#| new_buf[j] = self.buf[i]
#| }
#| } else {
#| let mut j = 0
#| for i in self.head.. A? { if self.len == 0 {
#| None
#| } else {
#| Some(self.buf[self.head])
#| } }
),
),
"back": build(
(
#|pub fn[A] back(self : T[A]) -> A? { if self.len == 0 {
#| None
#| } else {
#| Some(self.buf[self.tail])
#| } }
),
),
"push_front": build(
(
#|pub fn[A] push_front(self : T[A], value : A) -> Unit { if self.len == self.buf.length() {
#| self.realloc()
#| }
#| if self.len != 0 {
#| self.head = (self.head + self.buf.length() - 1) % self.buf.length()
#| }
#| self.buf[self.head] = value
#| self.len += 1 }
),
),
"push_back": build(
(
#|pub fn[A] push_back(self : T[A], value : A) -> Unit { if self.len == self.buf.length() {
#| self.realloc()
#| }
#| if self.len != 0 {
#| self.tail = (self.tail + self.buf.length() + 1) % self.buf.length()
#| }
#| self.buf[self.tail] = value
#| self.len += 1 }
),
),
"unsafe_pop_front": build(
(
#|pub fn[A] unsafe_pop_front(self : T[A]) -> Unit { match self.len {
#| 0 => abort(\"The deque is empty!\")
#| 1 => {
#| set_null(self.buf, self.head)
#| self.len -= 1
#| }
#| _ => {
#| set_null(self.buf, self.head)
#| self.head = if self.head < self.buf.length() - 1 {
#| self.head + 1
#| } else {
#| 0
#| }
#| self.len -= 1
#| }
#| } }
),
),
"unsafe_pop_back": build(
(
#|pub fn[A] unsafe_pop_back(self : T[A]) -> Unit { match self.len {
#| 0 => abort(\"The deque is empty!\")
#| 1 => {
#| set_null(self.buf, self.tail)
#| self.len -= 1
#| }
#| _ => {
#| set_null(self.buf, self.tail)
#| self.tail = if self.tail > 0 {
#| self.tail - 1
#| } else {
#| self.buf.length() - 1
#| }
#| self.len -= 1
#| }
#| } }
),
),
"pop_front": build(
(
#|pub fn[A] pop_front(self : T[A]) -> A? { match self.len {
#| 0 => None
#| 1 => {
#| let origin_head = self.buf[self.head]
#| set_null(self.buf, self.head)
#| self.len -= 1
#| Some(origin_head)
#| }
#| _ => {
#| let origin_head = self.buf[self.head]
#| set_null(self.buf, self.head)
#| self.head = if self.head < self.buf.length() - 1 {
#| self.head + 1
#| } else {
#| 0
#| }
#| self.len -= 1
#| Some(origin_head)
#| }
#| } }
),
),
"pop_back": build(
(
#|pub fn[A] pop_back(self : T[A]) -> A? { match self.len {
#| 0 => None
#| 1 => {
#| let origin_back = self.buf[self.tail]
#| set_null(self.buf, self.tail)
#| self.len -= 1
#| Some(origin_back)
#| }
#| _ => {
#| let origin_back = self.buf[self.tail]
#| set_null(self.buf, self.tail)
#| self.tail = if self.tail > 0 {
#| self.tail - 1
#| } else {
#| self.buf.length() - 1
#| }
#| self.len -= 1
#| Some(origin_back)
#| }
#| } }
),
),
"op_get": build(
(
#|pub fn[A] op_get(self : T[A], index : Int) -> A { if index < 0 || index >= self.len {
#| let len = self.len
#| abort(
#| \"index out of bounds: the len is from 0 to \\{len} but the index is \\{index}\",
#| )
#| }
#| if self.head + index < self.buf.length() {
#| self.buf[self.head + index]
#| } else {
#| self.buf[self.head + index - self.buf.length()]
#| } }
),
),
"op_set": build(
(
#|pub fn[A] op_set(self : T[A], index : Int, value : A) -> Unit { if index < 0 || index >= self.len {
#| let len = self.len
#| abort(
#| \"index out of bounds: the len is from 0 to \\{len} but the index is \\{index}\",
#| )
#| }
#| if self.head + index < self.buf.length() {
#| self.buf[self.head + index] = value
#| } else {
#| self.buf[self.head + index - self.buf.length()] = value
#| } }
),
),
"as_views": build(
(
#|pub fn[A] T::as_views(self : T[A]) -> (@array.View[A], @array.View[A]) { guard self.len != 0 else { ([][:], [][:]) }
#| let { buf, head, len, .. } = self
#| let cap = buf.length()
#| let head_len = cap - head
#| if head_len >= len {
#| (buf[head:head + len], [][:])
#| } else {
#| (buf[head:cap], buf[:len - head_len])
#| } }
),
),
"each": build(
(
#|pub fn[A] each(self : T[A], f : (A) -> Unit) -> Unit { for v in self {
#| f(v)
#| } }
),
),
"eachi": build(
(
#|pub fn[A] eachi(self : T[A], f : (Int, A) -> Unit) -> Unit { for i, v in self {
#| f(i, v)
#| } }
),
),
"rev_each": build(
(
#|pub fn[A] rev_each(self : T[A], f : (A) -> Unit) -> Unit { for v in self.rev_iter() {
#| f(v)
#| } }
),
),
"rev_eachi": build(
(
#|pub fn[A] rev_eachi(self : T[A], f : (Int, A) -> Unit) -> Unit { for i, v in self.rev_iter2() {
#| f(i, v)
#| } }
),
),
"clear": build(
(
#|pub fn[A] clear(self : T[A]) -> Unit { let { head, buf, len, .. } = self
#| let cap = buf.length()
#| let head_len = cap - head
#| if head_len >= len {
#| for i in head..<(head + len) {
#| set_null(buf, i)
#| }
#| } else {
#| for i in head.. U) -> T[U] { if self.len == 0 {
#| new()
#| } else {
#| let buf : UninitializedArray[U] = UninitializedArray::make(self.len)
#| for i in 0.. U) -> T[U] { if self.len == 0 {
#| new()
#| } else {
#| let buf : UninitializedArray[U] = UninitializedArray::make(self.len)
#| for i in 0.. Bool { self.len == 0 }
),
),
"search": build(
(
#|pub fn[A : Eq] search(self : T[A], value : A) -> Int? { for i in 0.. Bool { self.iter().contains(value) }
),
),
"reserve_capacity": build(
(
#|pub fn[A] reserve_capacity(self : T[A], capacity : Int) -> Unit { if self.capacity() >= capacity {
#| return
#| }
#| let new_buf : UninitializedArray[A] = UninitializedArray::make(capacity)
#| let { buf, len, head, .. } = self
#| self.buf = new_buf
#| self.head = 0
#| self.tail = 0
#| for i in 0.. Unit { if self.capacity() <= self.length() {
#| return
#| }
#| let { buf, len, head, .. } = self
#| self.buf = UninitializedArray::make(len)
#| self.head = 0
#| self.tail = 0
#| for i in 0.. Unit { guard len >= 0 && len < self.len else { return }
#| if len == 0 {
#| self.clear()
#| return
#| }
#| let { head, buf, .. } = self
#| let (front, back) = self.as_views()
#| if front.length() < len {
#| // `len` is wrapping around the end of the buffer.
#| // Thus, we need to drop the latter part of the back view.
#| self.len = len
#| let start = len - front.length()
#| self.tail = start - 1
#| for i in start.. A?) -> Unit { guard !self.is_empty() else { return }
#| let { head, buf, .. } = self
#| let cap = buf.length()
#| let head_len = cap - head
#| let mut idx = head
#| let (front, back) = self.as_views()
#| for cur in front {
#| if f(cur) is Some(v) {
#| buf[idx] = v
#| idx += 1
#| }
#| }
#| if back.length() == 0 {
#| self.truncate(idx - head)
#| return
#| }
#| for cur in back {
#| if idx == cap {
#| idx = 0
#| }
#| if f(cur) is Some(v) {
#| buf[idx] = v
#| idx += 1
#| }
#| }
#| if idx <= self.len - head_len {
#| self.truncate(idx + head_len)
#| } else {
#| self.truncate(idx - head)
#| } }
),
),
"retain": build(
(
#|pub fn[A] retain(self : T[A], f : (A) -> Bool) -> Unit { guard !self.is_empty() else { return }
#| let { head, buf, .. } = self
#| let cap = buf.length()
#| let head_len = cap - head
#| let mut idx = head
#| let (front, back) = self.as_views()
#| for cur in front {
#| if f(cur) {
#| buf[idx] = cur
#| idx += 1
#| }
#| }
#| if back.length() == 0 {
#| self.truncate(idx - head)
#| return
#| }
#| for cur in back {
#| if idx == cap {
#| idx = 0
#| }
#| if f(cur) {
#| buf[idx] = cur
#| idx += 1
#| }
#| }
#| if idx <= self.len - head_len {
#| self.truncate(idx + head_len)
#| } else {
#| self.truncate(idx - head)
#| } }
),
),
"iter": build(
(
#|pub fn[A] iter(self : T[A]) -> Iter[A] { Iter::new(yield_ => {
#| guard !self.is_empty() else { IterContinue }
#| let { head, buf, len, .. } = self
#| let cap = buf.length()
#| let head_len = cap - head
#| if head_len >= len {
#| for i in head..<(head + len) {
#| guard yield_(buf[i]) is IterContinue else { return IterEnd }
#| }
#| } else {
#| for i in head.. Iter2[Int, A] { Iter2::new(yield_ => {
#| guard !self.is_empty() else { IterContinue }
#| let { head, buf, len, .. } = self
#| let cap = buf.length()
#| let head_len = cap - head
#| let mut j = 0
#| if head_len >= len {
#| for i in head..<(head + len) {
#| guard yield_(j, buf[i]) is IterContinue else { return IterEnd }
#| j += 1
#| }
#| } else {
#| for i in head.. Iter[A] { Iter::new(yield_ => {
#| guard !self.is_empty() else { IterContinue }
#| let { head, buf, len, .. } = self
#| let cap = buf.length()
#| let head_len = cap - head
#| if head_len >= len {
#| for i = head + len - 1; i >= head; i = i - 1 {
#| guard yield_(buf[i]) is IterContinue else { return IterEnd }
#| }
#| } else {
#| for i = len - head_len - 1; i >= 0; i = i - 1 {
#| guard yield_(buf[i]) is IterContinue else { return IterEnd }
#| }
#| for i = cap - 1; i >= head; i = i - 1 {
#| guard yield_(buf[i]) is IterContinue else { return IterEnd }
#| }
#| }
#| IterContinue
#| }) }
),
),
"rev_iter2": build(
(
#|pub fn[A] rev_iter2(self : T[A]) -> Iter2[Int, A] { Iter2::new(yield_ => {
#| guard !self.is_empty() else { IterContinue }
#| let { head, buf, len, .. } = self
#| let cap = buf.length()
#| let head_len = cap - head
#| let mut j = 0
#| if head_len >= len {
#| for i = head + len - 1; i >= head; i = i - 1 {
#| guard yield_(j, buf[i]) is IterContinue else { return IterEnd }
#| j += 1
#| }
#| } else {
#| for i = len - head_len - 1; i >= 0; i = i - 1 {
#| guard yield_(j, buf[i]) is IterContinue else { return IterEnd }
#| j += 1
#| }
#| for i = cap - 1; i >= head; i = i - 1 {
#| guard yield_(j, buf[i]) is IterContinue else { return IterEnd }
#| j += 1
#| }
#| }
#| IterContinue
#| }) }
),
),
"from_iter": build(
(
#|pub fn[A] from_iter(iter : Iter[A]) -> T[A] { let dq = new()
#| iter.each(e => dq.push_back(e))
#| dq }
),
),
"to_array": build(
(
#|pub fn[A] to_array(self : T[A]) -> Array[A] { let len = self.length()
#| if len == 0 {
#| []
#| } else {
#| let xs = Array::make(len, self[0])
#| for i in 0.. String { let str = separator.to_string()
#| self.iter().join(str) }
),
),
"flatten": build(
(
#|pub fn[A] T::flatten(self : T[T[A]]) -> T[A] { let mut len = 0
#| for deque in self {
#| len += deque.length()
#| }
#| let target = T::{
#| buf: UninitializedArray::make(len),
#| len,
#| head: 0,
#| tail: len - 1,
#| }
#| let mut i = 0
#| for deque in self {
#| let cap = deque.buf.length()
#| let head_len = cap - deque.head
#| target.buf.unsafe_blit(i, deque.buf, deque.head, head_len)
#| if head_len < deque.len {
#| target.buf.unsafe_blit(i + head_len, deque.buf, 0, deque.len - head_len)
#| }
#| i += deque.len
#| }
#| target }
),
),
"drain": build(
(
#|pub fn[A] T::drain(self : T[A], start~ : Int, len? : Int) -> T[A] { let len = match len {
#| Some(l) => if l > self.len { self.len } else { l }
#| None => self.len - start
#| }
#| if len == 0 {
#| return new()
#| }
#| let deque = T::{
#| buf: UninitializedArray::make(len),
#| len,
#| head: 0,
#| tail: len - 1,
#| }
#| let cap = self.buf.length()
#| let start_idx = (self.head + start) % cap
#| let start_len = cap - start_idx
#| // copy to deque
#| if start_len < len {
#| deque.buf.unsafe_blit(0, self.buf, start_idx, start_len)
#| deque.buf.unsafe_blit(start_len, self.buf, 0, len - start_len)
#| for i in 0..= 0; i = i - 1 {
#| self.buf[(new_head + i) % cap] = self.buf[(self.head + i) % cap]
#| set_null(self.buf, (self.head + i) % cap)
#| }
#| self.head = new_head % cap
#| self.len -= len
#| deque }
),
),
"binary_search_by": build(
(
#|pub fn[A] binary_search_by(self : T[A], cmp : (A) -> Int) -> Result[Int, Int] { let len = self.len
#| // Functional loop with two evolving bounds `i` (inclusive) and `j` (exclusive).
#| // `continue new_i, new_j` updates the pair for the next iteration, eliminating
#| // the need for mutable variables.
#| for i = 0, j = len; i < j; {
#| let h = i + (j - i) / 2
#| let ord = cmp(self[h])
#| if ord < 0 {
#| // Search the right half
#| continue h + 1, j
#| } else {
#| // ord == 0 (match) or ord > 0 (too large): keep searching left half to
#| // guarantee we land on the left-most occurrence.
#| continue i, h
#| }
#| } else {
#| // When the loop finishes, `i == j`. If the deque is non-empty and the
#| // element at `i` matches, we found the left-most index; otherwise `i` is
#| // the correct insertion point.
#| if i < len && cmp(self[i]) == 0 {
#| Ok(i)
#| } else {
#| Err(i)
#| }
#| } }
),
),
"get": build(
(
#|pub fn[A] get(self : T[A], index : Int) -> A? { if index >= 0 && index < self.len {
#| let physical_index = (self.head + index) % self.buf.length()
#| Some(self.buf[physical_index])
#| } else {
#| None
#| } }
),
),
"binary_search": build(
(
#|pub fn[A : Compare] binary_search(self : T[A], value : A) -> Result[Int, Int] { self.binary_search_by(x => x.compare(value)) }
),
),
"rev_inplace": build(
(
#|pub fn[A] T::rev_inplace(self : T[A]) -> Unit { guard self.len > 0 else { return }
#| let cap = self.buf.length()
#| let mut left = self.head
#| let mut right = self.tail
#| for _ in 0..<(self.len / 2) {
#| let temp = self.buf[left]
#| self.buf[left] = self.buf[right]
#| self.buf[right] = temp
#| left = (left + 1) % cap
#| right = (right - 1 + cap) % cap
#| } }
),
),
"rev": build(
(
#|pub fn[A] T::rev(self : T[A]) -> T[A] { let len = self.len
#| let new_buf = UninitializedArray::make(len)
#| // Copy elements in reverse order
#| for i in 0.. Int) -> Unit { let n = self.len
#| let buf_length = self.buf.length()
#| for i = n - 1; i > 0; i = i - 1 {
#| let j = rand(i + 1)
#| // Calculate circular buffer positions
#| let i_pos = (self.head + i) % buf_length
#| let j_pos = (self.head + j) % buf_length
#| // Swap elements
#| let tmp = self.buf[i_pos]
#| self.buf[i_pos] = self.buf[j_pos]
#| self.buf[j_pos] = tmp
#| } }
),
),
"shuffle": build(
(
#|pub fn[A] shuffle(self : T[A], rand~ : (Int) -> Int) -> T[A] { // Create a copy of the original deque
#| let new_deque = self.copy()
#| // Shuffle the copy in place
#| new_deque.shuffle_in_place(rand~)
#| // Return the shuffled copy
#| new_deque }
),
),
}
},
)
///|
let moonbitlang_core_double_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/double",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/int64": moonbitlang_core_int64_module,
"moonbitlang/core/uint64": moonbitlang_core_uint64_module,
"moonbitlang/core/double/internal/ryu": moonbitlang_core_double_internal_ryu_module,
},
fn(_env, build) {
{
"sinh": build(
(
#|pub fn Double::sinh(self : Double) -> Double { if self.is_nan() || self.is_inf() {
#| return self
#| }
#| let ix = get_high_word(self).reinterpret_as_int() & 0x7fffffff
#| let abs_x = self.abs()
#| let shuge = 1.0e307
#| let h = if self < 0.0 { -0.5 } else { 0.5 }
#| if ix < 0x40360000 {
#| if ix < 0x3e300000 {
#| if shuge + self > 1.0 {
#| return self
#| }
#| }
#| let t = abs_x.expm1()
#| if ix < 0x3ff00000 {
#| return h * (2.0 * t - t * t / (t + 1.0))
#| }
#| return h * (t + t / (t + 1.0))
#| }
#| if ix < 0x40862E42 {
#| return h * abs_x.exp()
#| }
#| if abs_x.reinterpret_as_uint64() < 0x408633ce8fb9f87d {
#| let w = exp(0.5 * abs_x)
#| let t = h * w
#| return t * w
#| }
#| self * shuge }
),
),
"cosh": build(
(
#|pub fn Double::cosh(self : Double) -> Double { if self.is_nan() {
#| return self
#| }
#| if self.is_inf() {
#| return infinity
#| }
#| let ix = get_high_word(self).reinterpret_as_int() & 0x7fffffff
#| if ix < 0x3fd62e43 {
#| let t = self.abs().expm1()
#| let w = 1.0 + t
#| if ix < 0x3c800000 {
#| return w
#| }
#| return 1.0 + t * t / (w + w)
#| }
#| if ix < 0x40360000 {
#| let t = self.abs().exp()
#| return 0.5 * t + 0.5 / t
#| }
#| if ix < 0x40862E42 {
#| return 0.5 * self.abs().exp()
#| }
#| let lx = get_low_word(self).reinterpret_as_int()
#| if ix < 0x408633ce || (ix == 0x408633ce && lx <= 0x8fb9f87d) {
#| let w = exp(0.5 * self.abs())
#| let t = 0.5 * w
#| return t * w
#| }
#| infinity }
),
),
"tanh": build(
(
#|pub fn Double::tanh(self : Double) -> Double { if self.is_nan() {
#| return self
#| }
#| if self.is_pos_inf() {
#| return 1.0
#| }
#| if self.is_neg_inf() {
#| return -1.0
#| }
#| let ix = get_high_word(self).reinterpret_as_int() & 0x7fffffff
#| let tiny = 1.0e-300
#| let z = if ix < 0x40360000 {
#| if ix < 0x3c800000 {
#| self * (1.0 + self)
#| } else if ix >= 0x3ff00000 {
#| let t = (2.0 * self.abs()).expm1()
#| 1.0 - 2.0 / (t + 2.0)
#| } else {
#| let t = (-2.0 * self.abs()).expm1()
#| -t / (t + 2.0)
#| }
#| } else {
#| 1.0 - tiny
#| }
#| if self >= 0.0 {
#| z
#| } else {
#| -z
#| } }
),
),
"asinh": build(
(
#|pub fn Double::asinh(self : Double) -> Double { if self.is_nan() || self.is_inf() {
#| return self
#| }
#| let one : Double = 1.0
#| let ln2 : Double = 6.93147180559945286227e-01
#| let huge : Double = 1.0e300
#| let hx = get_high_word(self).reinterpret_as_int()
#| let ix = hx & 0x7fffffff
#| if ix < 0x3e300000 {
#| if huge + self > one {
#| return self
#| }
#| }
#| let w : Double = if ix > 0x41b00000 {
#| self.abs().ln() + ln2
#| } else if ix > 0x40000000 {
#| let t = self.abs()
#| (2.0 * t + one / ((self * self + one).sqrt() + t)).ln()
#| } else {
#| let t = self * self
#| (self.abs() + t / (one + (one + t).sqrt())).ln_1p()
#| }
#| if hx > 0 {
#| w
#| } else {
#| -w
#| } }
),
),
"acosh": build(
(
#|pub fn Double::acosh(self : Double) -> Double { let one = 1.0
#| let hx = get_high_word(self).reinterpret_as_int()
#| if self < 1.0 || self.is_nan() {
#| return not_a_number
#| } else if self == 1.0 {
#| return 0.0
#| } else if self.is_pos_inf() {
#| return infinity
#| } else if hx >= 0x41b00000 {
#| return self.ln() + ln2
#| } else if hx > 0x40000000 {
#| let t = self * self
#| return (2.0 * self - one / (self + (t - one).sqrt())).ln()
#| } else {
#| let t = self - one
#| return (t + (2.0 * t + t * t).sqrt()).ln_1p()
#| } }
),
),
"atanh": build(
(
#|pub fn Double::atanh(self : Double) -> Double { let hx : Int = get_high_word(self).reinterpret_as_int()
#| let ix = hx & 0x7fffffff
#| if self.abs() > 1.0 {
#| return not_a_number
#| }
#| if self == 1.0 {
#| return infinity
#| }
#| if self == -1.0 {
#| return neg_infinity
#| }
#| if ix < 0x3e300000 && 1.0e300 + self > 0.0 {
#| return self
#| }
#| let self = self.abs()
#| let t = if self <= 0.5 {
#| let t = self + self
#| 0.5 * (t + t * self / (1.0 - self)).ln_1p()
#| } else {
#| 0.5 * ((self + self) / (1.0 - self)).ln_1p()
#| }
#| if hx >= 0 {
#| t
#| } else {
#| -t
#| } }
),
),
"set_low_word": build(
(
#|fn set_low_word(d : Double, v : UInt) -> Double { let bits : UInt64 = d.reinterpret_as_uint64()
#| let bits = bits & 0xFFFF_FFFF_0000_0000
#| let bits = bits | v.to_uint64()
#| bits.reinterpret_as_double() }
),
),
"set_high_word": build(
(
#|fn set_high_word(d : Double, v : UInt) -> Double { let bits : UInt64 = d.reinterpret_as_uint64()
#| let bits = bits & 0x0000_0000_FFFF_FFFF
#| let bits = bits | (v.to_uint64() << 32)
#| bits.reinterpret_as_double() }
),
),
"get_high_word": build(
(
#|fn get_high_word(x : Double) -> UInt { (x.reinterpret_as_uint64() >> 32).to_uint() }
),
),
"get_low_word": build(
(
#|fn get_low_word(x : Double) -> UInt { x.reinterpret_as_uint64().to_uint() }
),
),
"rem_pio2": build(
(
#|fn rem_pio2(x : Double, y : Array[Double]) -> Int { let hx = get_high_word(x).reinterpret_as_int()
#| let ix : Int = hx & 0x7fffffff
#| let mut z = 0.0
#| if ix <= 0x3fe921fb {
#| // |x| <= pi/4, no reduction needed
#| y[0] = x
#| y[1] = 0.0
#| return 0
#| }
#| if ix < 0x4002d97c {
#| // |x| < 3pi/4, special case with n = +-1
#| if hx > 0 {
#| z = x - PIO2_1
#| if ix != 0x3ff921fb {
#| // 33+53 bit pi is good enough
#| y[0] = z - PIO2_1T
#| y[1] = z - y[0] - PIO2_1T
#| } else {
#| // Near pi/2, use 33+33+53 bit pi
#| z = z - PIO2_2
#| y[0] = z - PIO2_2T
#| y[1] = z - y[0] - PIO2_2T
#| }
#| return 1
#| } else {
#| // Negative x
#| z = x + PIO2_1
#| if ix != 0x3ff921fb {
#| // 33+53 bit pi is good enough
#| y[0] = z + PIO2_1T
#| y[1] = z - y[0] + PIO2_1T
#| } else {
#| // Near pi/2, use 33+33+53 bit pi
#| let z = z + PIO2_2
#| y[0] = z + PIO2_2T
#| y[1] = z - y[0] + PIO2_2T
#| }
#| return -1
#| }
#| }
#| if ix <= 0x413921fb {
#| // |x| <= 2^19 * (pi/2), medium size
#| let t = x.abs()
#| let n = (t * INV_PIO2 + HALF).to_int()
#| let fn_ = n.to_double()
#| let mut r = t - fn_ * PIO2_1
#| let mut w = fn_ * PIO2_1T
#| if n < 32 && ix != npio2_hw[n - 1] {
#| y[0] = r - w
#| } else {
#| let j = ix >> 20
#| y[0] = r - w
#| let i = j - ((get_high_word(y[0]) >> 20).reinterpret_as_int() & 0x7ff)
#| if i > 16 {
#| // 2nd iteration needed, good to 118 bits
#| let t = r
#| w = fn_ * PIO2_2
#| r = t - w
#| w = fn_ * PIO2_2T - (t - r - w)
#| y[0] = r - w
#| let i = j - ((get_high_word(y[0]) >> 20).reinterpret_as_int() & 0x7ff)
#| if i > 49 {
#| // 3rd iteration needed, 151 bits accuracy
#| let t = r
#| w = fn_ * PIO2_3
#| r = t - w
#| w = fn_ * PIO2_3T - (t - r - w)
#| y[0] = r - w
#| }
#| }
#| }
#| y[1] = r - y[0] - w
#| if hx > 0 {
#| return n
#| } else {
#| y[0] = -y[0]
#| y[1] = -y[1]
#| return -n
#| }
#| }
#| // All other (large) arguments
#| if ix >= 0x7ff00000 {
#| // x is inf or NaN
#| y[0] = x - x
#| y[1] = y[0]
#| return 0
#| }
#| // Set z = scalbn(|x|, ilogb(x) - 23)
#| z = set_low_word(z, get_low_word(x))
#| let e0 = (ix >> 20) - 1046 // e0 = ilogb(z) - 23
#| z = set_high_word(z, (ix - (e0 << 20)).reinterpret_as_uint())
#| let tx = [0.0, 0.0, 0.0]
#| for i in 0..<2 {
#| tx[i] = z.to_int().to_double()
#| z = (z - tx[i]) * TWO24
#| }
#| tx[2] = z
#| let mut nx = 3
#| while tx[nx - 1] == 0.0 {
#| nx -= 1
#| }
#| let n = __kernel_rem_pio2(tx, y, e0, nx, 2)
#| if hx > 0 {
#| n
#| } else {
#| y[0] = -y[0]
#| y[1] = -y[1]
#| -n
#| } }
),
),
"__kernel_sin": build(
(
#|fn __kernel_sin(x : Double, y : Double, iy : Int) -> Double { let s1 = -1.66666666666666324348e-01
#| let s2 = 8.33333333332248946124e-03
#| let s3 = -1.98412698298579493134e-04
#| let s4 = 2.75573137070700676789e-06
#| let s5 = -2.50507602534068634195e-08
#| let s6 = 1.58969099521155010221e-10
#| let mut z = 0.0
#| let mut r = 0.0
#| let mut v = 0.0
#| let ix = get_high_word(x) & 0x7fffffff
#| if ix < 0x3e400000 {
#| if x.to_int() == 0 {
#| return x
#| }
#| }
#| z = x * x
#| v = z * x
#| r = s2 + z * (s3 + z * (s4 + z * (s5 + z * s6)))
#| if iy == 0 {
#| x + v * (s1 + z * r)
#| } else {
#| x - (z * (0.5 * y - v * r) - y - v * s1)
#| } }
),
),
"__kernel_cos": build(
(
#|fn __kernel_cos(x : Double, y : Double) -> Double { let one = 1.00000000000000000000e+00
#| let c1 = 4.16666666666666019037e-02
#| let c2 = -1.38888888888741095749e-03
#| let c3 = 2.48015872894767294178e-05
#| let c4 = -2.75573143513906633035e-07
#| let c5 = 2.08757232129817482790e-09
#| let c6 = -1.13596475577881948265e-11
#| let mut a = 0.0
#| let mut hz = 0.0
#| let mut z = 0.0
#| let mut r = 0.0
#| let mut qx = 0.0
#| let ix = get_high_word(x) & 0x7fffffff
#| if ix < 0x3e400000 {
#| if x.to_int() == 0 {
#| return one
#| }
#| }
#| z = x * x
#| r = z * (c1 + z * (c2 + z * (c3 + z * (c4 + z * (c5 + z * c6)))))
#| if ix < 0x3fd33333 {
#| return one - (0.5 * z - (z * r - x * y))
#| } else {
#| if ix > 0x3fe90000 {
#| qx = 0.28125
#| } else {
#| qx = ((ix - 0x00200000).to_uint64() << 32).reinterpret_as_double()
#| }
#| hz = 0.5 * z - qx
#| a = one - qx
#| return a - (hz - (z * r - x * y))
#| } }
),
),
"__kernal_tan": build(
(
#|fn __kernal_tan(x : Double, y : Double, iy : Int) -> Double { let one = 1.0
#| let pio4 = 7.85398163397448278999e-01
#| let pio4lo = 3.06161699786838301793e-17
#| let mut x = x
#| let mut y = y
#| let mut z = 0.0
#| let mut r = 0.0
#| let mut v = 0.0
#| let mut w = 0.0
#| let mut s = 0.0
#| let t = [
#| 3.33333333333334091986e-01, // 3FD55555, 55555563 */
#| 1.33333333333201242699e-01, // 3FC11111, 1110FE7A */
#| 5.39682539762260521377e-02, // 3FABA1BA, 1BB341FE */
#| 2.18694882948595424599e-02, // 3F9664F4, 8406D637 */
#| 8.86323982359930005737e-03, // 3F8226E3, E96E8493 */
#| 3.59207910759131235356e-03, // 3F6D6D22, C9560328 */
#| 1.45620945432529025516e-03, // 3F57DBC8, FEE08315 */
#| 5.88041240820264096874e-04, // 3F4344D8, F2F26501 */
#| 2.46463134818469906812e-04, // 3F3026F7, 1A8D1068 */
#| 7.81794442939557092300e-05, // 3F147E88, A03792A6 */
#| 7.14072491382608190305e-05, // 3F12B80F, 32F0A7E9 */
#| -1.85586374855275456654e-05, // BEF375CB, DB605373 */
#| 2.59073051863633712884e-05, // 3EFB2A70, 74BF7AD4 */
#| 1.00000000000000000000e+00, // 3FF00000, 00000000 (one) */
#| 7.85398163397448278999e-01, // 3FE921FB, 54442D18 (pio4) */
#| 3.06161699786838301793e-17, // 3C81A626, 33145C07 (pio4lo) */
#| ]
#| let hx = get_high_word(x).reinterpret_as_int()
#| let ix = hx & 0x7fffffff
#| if ix < 0x3e300000 {
#| if x.to_int() == 0 {
#| if (ix | get_low_word(x).reinterpret_as_int() | (iy + 1)) == 0 {
#| return one / x.abs()
#| } else if iy == 1 {
#| return x
#| } else {
#| w = x + y
#| z = w
#| z = set_low_word(z, 0)
#| v = y - (z - x)
#| let a = -one / w
#| let mut t = a
#| t = set_low_word(t, 0)
#| s = one + t * z
#| return t + a * (s + t * v)
#| }
#| }
#| }
#| if ix >= 0x3fe59428 {
#| if hx < 0 {
#| x = -x
#| y = -y
#| }
#| z = pio4 - x
#| w = pio4lo - y
#| x = z + w
#| y = 0.0
#| }
#| z = x * x
#| w = z * z
#| r = t[1] + w * (t[3] + w * (t[5] + w * (t[7] + w * (t[9] + w * t[11]))))
#| v = z *
#| (t[2] + w * (t[4] + w * (t[6] + w * (t[8] + w * (t[10] + w * t[12])))))
#| s = z * x
#| r = y + z * (s * (r + v) + y)
#| r += t[0] * s
#| w = x + r
#| if ix >= 0x3fe59428 {
#| v = iy.to_double()
#| return (1 - ((hx >> 30) & 2)).to_double() *
#| (v - 2.0 * (x - (w * w / (w + v) - r)))
#| }
#| if iy == 1 {
#| w
#| } else {
#| z = w
#| z = set_low_word(z, 0)
#| v = r - (z - x)
#| let a = -1.0 / w
#| let mut t = a
#| t = set_low_word(t, 0)
#| s = 1.0 + t * z
#| t + a * (s + t * v)
#| } }
),
),
"sin": build(
(
#|pub fn Double::sin(self : Double) -> Double { if self.is_inf() || self.is_nan() {
#| return not_a_number
#| }
#| let y = [0.0, 0.0]
#| let z = 0.0
#| if self.abs() <= PI_OVER_4 {
#| return __kernel_sin(self, z, 0)
#| } else {
#| let n = rem_pio2(self, y)
#| match n & 3 {
#| 0 => __kernel_sin(y[0], y[1], 1)
#| 1 => __kernel_cos(y[0], y[1])
#| 2 => -__kernel_sin(y[0], y[1], 1)
#| _ => -__kernel_cos(y[0], y[1])
#| }
#| } }
),
),
"cos": build(
(
#|pub fn Double::cos(self : Double) -> Double { if self.is_inf() || self.is_nan() {
#| return not_a_number
#| }
#| let y = [0.0, 0.0]
#| let z = 0.0
#| if self.abs() <= PI_OVER_4 {
#| return __kernel_cos(self, z)
#| } else {
#| let n = rem_pio2(self, y)
#| match n & 3 {
#| 0 => __kernel_cos(y[0], y[1])
#| 1 => -__kernel_sin(y[0], y[1], 1)
#| 2 => -__kernel_cos(y[0], y[1])
#| _ => __kernel_sin(y[0], y[1], 1)
#| }
#| } }
),
),
"tan": build(
(
#|pub fn Double::tan(self : Double) -> Double { if self.is_inf() || self.is_nan() {
#| return not_a_number
#| }
#| let y = Array::make(2, 0.0)
#| let z = 0.0
#| if self.abs() <= PI_OVER_4 {
#| __kernal_tan(self, z, 1)
#| } else {
#| let n = rem_pio2(self, y)
#| __kernal_tan(y[0], y[1], 1 - ((n & 1) << 1))
#| } }
),
),
"asin": build(
(
#|pub fn Double::asin(self : Double) -> Double { let huge = 1.0e+300
#| let pio4_hi = 7.85398163397448278999e-01
#| let pio2_hi = 1.57079632679489655800
#| let pio2_lo = 6.12323399573676603587e-17
#| let ps0 = 1.66666666666666657415e-01
#| let ps1 = -3.25565818622400915405e-01
#| let ps2 = 2.01212532134862925881e-01
#| let ps3 = -4.00555345006794114027e-02
#| let ps4 = 7.91534994289814532176e-04
#| let ps5 = 3.47933107596021167570e-05
#| let qs1 = -2.40339491173441421878e+00
#| let qs2 = 2.02094576023350569471e+00
#| let qs3 = -6.88283971605453293030e-01
#| let qs4 = 7.70381505559019352791e-02
#| let ix = get_high_word(self).reinterpret_as_int() & 0x7fffffff
#| let absx = self.abs()
#| if absx >= 1.0 {
#| if absx == 1.0 {
#| return self * pio2_hi + self * pio2_lo
#| } else {
#| return not_a_number
#| }
#| } else if absx < 0.5 {
#| if ix < 0x3e400000 {
#| if huge + self > 1.0 {
#| return self
#| }
#| } else {
#| let t = self * self
#| let p = t *
#| (ps0 + t * (ps1 + t * (ps2 + t * (ps3 + t * (ps4 + t * ps5)))))
#| let q = 1.0 + t * (qs1 + t * (qs2 + t * (qs3 + t * qs4)))
#| let w = p / q
#| return self + self * w
#| }
#| }
#| let w = 1.0 - absx
#| let t = w * 0.5
#| let p = t * (ps0 + t * (ps1 + t * (ps2 + t * (ps3 + t * (ps4 + t * ps5)))))
#| let q = 1.0 + t * (qs1 + t * (qs2 + t * (qs3 + t * qs4)))
#| let s = t.sqrt()
#| if ix >= 0x3FEF3333 {
#| let w = p / q
#| let t = pio2_hi - (2.0 * (s + s * w) - pio2_lo)
#| return if self > 0.0 { t } else { -t }
#| } else {
#| let mut w = s
#| w = set_low_word(w, 0)
#| let c = (t - w * w) / (s + w)
#| let r = p / q
#| let p = 2.0 * s * r - (pio2_lo - 2.0 * c)
#| let q = pio4_hi - 2.0 * w
#| let t = pio4_hi - (p - q)
#| return if self > 0.0 { t } else { -t }
#| } }
),
),
"acos": build(
(
#|pub fn Double::acos(self : Double) -> Double { let one : Double = 1.0
#| let pi : Double = 3.14159265358979311600
#| let pio2_hi : Double = 1.57079632679489655800
#| let pio2_lo : Double = 6.12323399573676603587e-17
#| let ps0 : Double = 1.66666666666666657415e-01
#| let ps1 : Double = -3.25565818622400915405e-01
#| let ps2 : Double = 2.01212532134862925881e-01
#| let ps3 : Double = -4.00555345006794114027e-02
#| let ps4 : Double = 7.91534994289814532176e-04
#| let ps5 : Double = 3.47933107596021167570e-05
#| let qs1 : Double = -2.40339491173441421878e+00
#| let qs2 : Double = 2.02094576023350569471e+00
#| let qs3 : Double = -6.88283971605453293030e-01
#| let qs4 : Double = 7.70381505559019352791e-02
#| let ix = get_high_word(self).reinterpret_as_int() & 0x7fffffff
#| let absx = self.abs()
#| if absx >= 1.0 {
#| if absx == 1.0 {
#| if self > 0 {
#| return 0.0
#| } else {
#| return pi + 2.0 * pio2_lo
#| }
#| }
#| return not_a_number
#| }
#| if absx < 0.5 {
#| if ix <= 0x3c600000 {
#| return pio2_hi + pio2_lo
#| }
#| let z = self * self
#| let p = z * (ps0 + z * (ps1 + z * (ps2 + z * (ps3 + z * (ps4 + z * ps5)))))
#| let q = one + z * (qs1 + z * (qs2 + z * (qs3 + z * qs4)))
#| let r = p / q
#| pio2_hi - (self - (pio2_lo - self * r))
#| } else if self < 0 {
#| let z = (one + self) * 0.5
#| let p = z * (ps0 + z * (ps1 + z * (ps2 + z * (ps3 + z * (ps4 + z * ps5)))))
#| let q = one + z * (qs1 + z * (qs2 + z * (qs3 + z * qs4)))
#| let s = z.sqrt()
#| let r = p / q
#| let w = r * s - pio2_lo
#| pi - 2.0 * (s + w)
#| } else {
#| let z = (one - self) * 0.5
#| let s = z.sqrt()
#| let df = s
#| let c = (z - df * df) / (s + df)
#| let p = z * (ps0 + z * (ps1 + z * (ps2 + z * (ps3 + z * (ps4 + z * ps5)))))
#| let q = one + z * (qs1 + z * (qs2 + z * (qs3 + z * qs4)))
#| let r = p / q
#| let w = r * s + c
#| 2.0 * (df + w)
#| } }
),
),
"atan": build(
(
#|pub fn Double::atan(self : Double) -> Double { if self.is_nan() || self == 0.0 {
#| return self
#| }
#| let atan_hi = [
#| 4.63647609000806093515e-01, 7.85398163397448278999e-01, 9.82793723247329054082e-01,
#| 1.57079632679489655800e+00,
#| ]
#| let atan_lo = [
#| 2.26987774529616870924e-17, 3.06161699786838301793e-17, 1.39033110312309984516e-17,
#| 6.12323399573676603587e-17,
#| ]
#| let a_t = [
#| 3.33333333333329318027e-01, -1.99999999998764832476e-01, 1.42857142725034663711e-01,
#| -1.11111104054623557880e-01, 9.09088713343650656196e-02, -7.69187620504482999495e-02,
#| 6.66107313738753120669e-02, -5.83357013379057348645e-02, 4.97687799461593236017e-02,
#| -3.65315727442169155270e-02, 1.62858201153657823623e-02,
#| ]
#| let one = 1.0
#| let huge = 1.0e300
#| let ix = get_high_word(self).reinterpret_as_int() & 0x7fffffff
#| let mut id = 0
#| let mut z = 0.0
#| let mut w = 0.0
#| let mut self = self
#| let x_is_neg = self < 0.0
#| if ix >= 0x44100000 {
#| if self > 0 {
#| return atan_hi[3] + atan_lo[3]
#| } else {
#| return -atan_hi[3] - atan_lo[3]
#| }
#| }
#| if ix < 0x3fdc0000 {
#| if ix < 0x3e200000 {
#| if huge + self > one {
#| return self
#| }
#| }
#| id = -1
#| } else {
#| self = self.abs()
#| if ix < 0x3ff30000 {
#| if ix < 0x3fe60000 {
#| id = 0
#| self = (2.0 * self - one) / (2.0 + self)
#| } else {
#| id = 1
#| self = (self - one) / (self + one)
#| }
#| } else if ix < 0x40038000 {
#| id = 2
#| self = (self - 1.5) / (one + 1.5 * self)
#| } else {
#| id = 3
#| self = -1.0 / self
#| }
#| }
#| z = self * self
#| w = z * z
#| let s1 = z *
#| (
#| a_t[0] +
#| w * (a_t[2] + w * (a_t[4] + w * (a_t[6] + w * (a_t[8] + w * a_t[10]))))
#| )
#| let s2 = w *
#| (a_t[1] + w * (a_t[3] + w * (a_t[5] + w * (a_t[7] + w * a_t[9]))))
#| if id < 0 {
#| self - self * (s1 + s2)
#| } else {
#| z = atan_hi[id] - (self * (s1 + s2) - atan_lo[id] - self)
#| if x_is_neg {
#| -z
#| } else {
#| z
#| }
#| } }
),
),
"atan2": build(
(
#|pub fn Double::atan2(self : Double, x : Double) -> Double { if x.is_nan() || self.is_nan() {
#| return not_a_number
#| }
#| let tiny = 1.0e-300
#| let zero = 0.0
#| let pi_o_4 = 7.8539816339744827900E-01
#| let pi_o_2 = 1.5707963267948965580E+00
#| let pi = 3.1415926535897931160E+00
#| let pi_lo = 1.2246467991473531772E-16
#| let hx = get_high_word(x).reinterpret_as_int()
#| let hy = get_high_word(self).reinterpret_as_int()
#| let ix = hx & 0x7fffffff
#| let iy = hy & 0x7fffffff
#| if x == 1.0 {
#| return self.atan()
#| }
#| let m = ((hy >> 31) & 1) | ((hx >> 30) & 2)
#| if self == 0 {
#| match m {
#| 0 | 1 => return self
#| 2 => return pi + tiny
#| _ => return -pi - tiny
#| }
#| }
#| if x == 0 {
#| return if hy < 0 { -pi_o_2 - tiny } else { pi_o_2 + tiny }
#| }
#| if x.is_inf() {
#| if self.is_inf() {
#| match m {
#| 0 => return pi_o_4 + tiny
#| 1 => return -pi_o_4 - tiny
#| 2 => return 3.0 * pi_o_4 + tiny
#| _ => return -3.0 * pi_o_4 - tiny
#| }
#| } else {
#| match m {
#| 0 => return zero
#| 1 => return -zero
#| 2 => return pi + tiny
#| _ => return -pi - tiny
#| }
#| }
#| }
#| if self.is_inf() {
#| return if hy < 0 { -pi_o_2 - tiny } else { pi_o_2 + tiny }
#| }
#| let k = (iy - ix) >> 20
#| let z = if k > 60 {
#| pi_o_2 + 0.5 * pi_lo
#| } else if hx < 0 && k < -60 {
#| 0.0
#| } else {
#| (self / x).abs().atan()
#| }
#| match m {
#| 0 => z
#| 1 => -z
#| 2 => pi - (z - pi_lo)
#| _ => z - pi_lo - pi
#| } }
),
),
"exp_bias": (None, Int(1023)),
"exp_bits": (None, Int(11)),
"frac_bits": (None, Int(52)),
"trunc": build(
(
#|pub fn Double::trunc(self : Double) -> Double { let u64 = self.reinterpret_as_uint64()
#| let biased_exp = ((u64 >> frac_bits) & ((0x1UL << exp_bits) - 1)).to_int()
#| if biased_exp < exp_bias {
#| return (u64 & sign_mask).reinterpret_as_double()
#| } else if biased_exp >= exp_bias + frac_bits {
#| return self
#| }
#| let mask_shift = biased_exp - exp_bias + exp_bits
#| let trunc_mask = (sign_mask.reinterpret_as_int64() >> mask_shift).reinterpret_as_uint64()
#| return (u64 & trunc_mask).reinterpret_as_double() }
),
),
"ceil": build(
(
#|pub fn Double::ceil(self : Double) -> Double { let trunced = self.trunc()
#| if self > trunced {
#| return trunced + 1.0
#| } else {
#| return trunced
#| } }
),
),
"floor": build(
(
#|pub fn Double::floor(self : Double) -> Double { let trunced = self.trunc()
#| if self < trunced {
#| return trunced - 1.0
#| } else {
#| return trunced
#| } }
),
),
"round": build(
(
#|pub fn Double::round(self : Double) -> Double { floor(self + 0.5) }
),
),
"pow": build(
(
#|pub fn Double::pow(self : Double, other : Double) -> Double { fn set_low_word(d : Double, v : UInt) -> Double {
#| let bits : UInt64 = d.reinterpret_as_uint64()
#| let bits = bits & 0xFFFF_FFFF_0000_0000
#| let bits = bits | v.to_uint64()
#| bits.reinterpret_as_double()
#| }
#| fn set_high_word(d : Double, v : UInt) -> Double {
#| let bits : UInt64 = d.reinterpret_as_uint64()
#| let bits = bits & 0x0000_0000_FFFF_FFFF
#| let bits = bits | (v.to_uint64() << 32)
#| bits.reinterpret_as_double()
#| }
#| fn get_high_word(x : Double) -> UInt {
#| (x.reinterpret_as_uint64() >> 32).to_uint()
#| }
#| fn get_low_word(x : Double) -> UInt {
#| x.reinterpret_as_uint64().to_uint()
#| }
#| let x = self
#| let y = other
#| // double z, ax, z_h, z_l, p_h, p_l;
#| let mut z : Double = 0.0
#| let mut ax : Double = 0.0
#| let mut z_h : Double = 0.0
#| let mut z_l : Double = 0.0
#| let mut p_h : Double = 0.0
#| let mut p_l : Double = 0.0
#| // double y1, t1, t2, r, s, t, u, v, w
#| let mut y1 : Double = 0.0
#| let mut t1 : Double = 0.0
#| let mut t2 : Double = 0.0
#| let mut r : Double = 0.0
#| let mut s : Double = 0.0
#| let mut t : Double = 0.0
#| let mut u : Double = 0.0
#| let mut v : Double = 0.0
#| let mut w : Double = 0.0
#| // int i, j, k, yisint, n
#| let mut i : Int = 0
#| let mut j : Int = 0
#| let mut k : Int = 0
#| let mut yisint : Int = 0
#| let mut n : Int = 0
#| // int hx, hy, ix, iy;
#| // unsigned lx, ly;
#| //
#| // EXTRACT_WORDS(hx, lx, x);
#| // EXTRACT_WORDS(hy, ly, y);
#| // ix = hx & 0x7fffffff;
#| // iy = hy & 0x7fffffff;
#| let hx : Int = (x.reinterpret_as_uint64() >> 32).to_int()
#| let lx : UInt = (x.reinterpret_as_uint64() & 0xFFFFFFFF).to_uint()
#| let hy : Int = (y.reinterpret_as_uint64() >> 32).to_int()
#| let ly : UInt = (y.reinterpret_as_uint64() & 0xFFFFFFFF).to_uint()
#| let mut ix : Int = hx & 0x7FFFFFFF
#| let iy : Int = hy & 0x7FFFFFFF
#| // y==zero: x**0 = 1
#| if (iy.reinterpret_as_uint() | ly) == 0 {
#| return ONE
#| }
#| // +-NaN return x+y
#| if ix > 0x7FF00000 ||
#| (ix == 0x7FF00000 && lx != 0) ||
#| iy > 0x7FF00000 ||
#| (iy == 0x7FF00000 && ly != 0) {
#| return x + y
#| }
#| // determine if y is an odd int when x < 0
#| // yisint = 0 ... y is not an integer
#| // yisint = 1 ... y is an odd int
#| // yisint = 2 ... y is an even int
#| if hx < 0 {
#| if iy >= 0x43400000 {
#| yisint = 2 // even integer y
#| } else if iy >= 0x3ff00000 {
#| k = (iy >> 20) - 0x3ff // exponent
#| if k > 20 {
#| j = (ly >> (52 - k)).reinterpret_as_int()
#| if j << (52 - k) == ly.reinterpret_as_int() {
#| yisint = 2 - (j & 1)
#| }
#| } else if ly == 0 {
#| j = iy >> (20 - k)
#| if j << (20 - k) == iy {
#| yisint = 2 - (j & 1)
#| }
#| }
#| }
#| }
#| // special value of y
#| if ly == 0 {
#| if iy == 0x7ff00000 { // y is +-inf
#| if ((ix.reinterpret_as_uint() - 0x3ff00000) | lx) == 0 {
#| return y - y // inf**+-1 is NaN
#| } else if ix >= 0x3ff00000 { // (|x|>1)**+-inf = inf,0
#| return if hy >= 0 { y } else { ZERO }
#| } else { // (|x|<1)**-,+inf = inf,0
#| return if hy < 0 { -y } else { ZERO }
#| }
#| }
#| if iy == 0x3ff00000 { // y is +-1
#| if hy < 0 {
#| return ONE / x
#| } else {
#| return x
#| }
#| }
#| if hy == 0x40000000 { // y is 2
#| return x * x
#| }
#| if hy == 0x3fe00000 { // y is 0.5
#| if hx >= 0 { // x >= +0
#| return x.sqrt()
#| }
#| }
#| }
#| ax = x.abs()
#| // special value of x
#| if lx == 0 {
#| if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 {
#| z = ax // x is +-0,+-inf,+-1 */
#| if hy < 0 {
#| z = ONE / z // z = (1/|x|)
#| }
#| if hx < 0 {
#| if ((ix - 0x3ff00000) | yisint) == 0 {
#| // (-1)**non-int is NaN
#| z = not_a_number
#| } else if yisint == 1 {
#| z = -z // (x<0)**odd = -(|x|**odd)
#| }
#| }
#| return z
#| }
#| }
#| n = (hx >> 31) + 1
#| // (x<0)**(non-int) is NaN
#| if (n | yisint) == 0 {
#| return not_a_number
#| }
#| s = ONE // s (sign of result -ve**odd) = -1 else = 1
#| if (n | (yisint - 1)) == 0 {
#| s = -ONE // (-ve)**(odd int)
#| }
#| // |y| is huge
#| if iy > 0x41e00000 { // if |y| > 2**31 */
#| if iy > 0x43f00000 { // if |y| > 2**64, must o/uflow */
#| if ix <= 0x3fefffff {
#| return if hy < 0 { POW_huge * POW_huge } else { POW_tiny * POW_tiny }
#| }
#| if ix >= 0x3ff00000 {
#| return if hy > 0 { POW_huge * POW_huge } else { POW_tiny * POW_tiny }
#| }
#| }
#| // over/underflow if x is not close to one */
#| if ix < 0x3fefffff {
#| return if hy < 0 {
#| s * POW_huge * POW_huge
#| } else {
#| s * POW_tiny * POW_tiny
#| }
#| }
#| if ix > 0x3ff00000 {
#| return if hy > 0 {
#| s * POW_huge * POW_huge
#| } else {
#| s * POW_tiny * POW_tiny
#| }
#| }
#| // now |1-x| is tiny <= 2**-20, suffice to compute
#| // log(x) by x-x^2/2+x^3/3-x^4/4 */
#| t = ax - ONE // t has 20 trailing zeros */
#| w = t * t * (0.5 - t * (0.3333333333333333333333 - t * 0.25))
#| u = POW_ivln2_h * t // POW_ivln2_h has 21 sig. bits */
#| v = t * POW_ivln2_l - w * POW_ivln2
#| t1 = u + v
#| t1 = set_low_word(t1, 0)
#| t2 = v - (t1 - u)
#| } else {
#| n = 0
#| // take care subnormal number
#| if ix < 0x00100000 {
#| ax *= POW_two53
#| n -= 53
#| ix = get_high_word(ax).reinterpret_as_int()
#| }
#| n += (ix >> 20) - 0x3ff
#| j = ix & 0x000fffff
#| // determine interval
#| ix = j | 0x3ff00000 // normalize ix
#| if j <= 0x3988E {
#| k = 0 // |x|> 1) | 0x20000000) +
#| 0x00080000 +
#| (k.reinterpret_as_uint() << 18),
#| )
#| let mut t_l : Double = ax - (t_h - pow_bp[k])
#| let s_l : Double = v * (u - s_h * t_h - s_h * t_l)
#| // compute log(ax)
#| let mut s2 : Double = ss * ss
#| r = s2 *
#| s2 *
#| (
#| POW_L1 +
#| s2 *
#| (POW_L2 + s2 * (POW_L3 + s2 * (POW_L4 + s2 * (POW_L5 + s2 * POW_L6))))
#| )
#| r += s_l * (s_h + ss)
#| s2 = s_h * s_h
#| t_h = 3.0 + s2 + r
#| t_h = set_low_word(t_h, 0)
#| t_l = r - (t_h - 3.0 - s2)
#| // u+v = ss*(1+...)
#| u = s_h * t_h
#| v = s_l * t_h + t_l * ss
#| // 2/(3log2)*(ss+...)
#| p_h = u + v
#| p_h = set_low_word(p_h, 0)
#| p_l = v - (p_h - u)
#| z_h = POW_cp_h * p_h // cp_h+cp_l = 2/(3*log2)
#| z_l = POW_cp_l * p_h + p_l * POW_cp + pow_dp_l[k]
#| // log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l
#| t = n.to_double()
#| t1 = z_h + z_l + pow_dp_h[k] + t
#| t1 = set_low_word(t1, 0)
#| t2 = z_l - (t1 - t - pow_dp_h[k] - z_h)
#| }
#| // split up y into y1+y2 and compute (y1+y2)*(t1+t2)
#| y1 = y
#| y1 = set_low_word(y1, 0)
#| p_l = (y - y1) * t1 + y * t2
#| p_h = y1 * t1
#| z = p_l + p_h
#| j = get_high_word(z).reinterpret_as_int()
#| i = get_low_word(z).reinterpret_as_int()
#| if j >= 0x40900000 { // z >= 1024
#| if ((j - 0x40900000) | i) != 0 { // if z > 1024
#| return s * POW_huge * POW_huge // overflow
#| } else if p_l + POW_ovt > z - p_h {
#| return s * POW_huge * POW_huge // overflow
#| }
#| } else if (j & 0x7fffffff) >= 0x4090cc00 { // z <= -1075
#| if ((j - 0xc090cc00) | i) != 0 { // z < -1075
#| return s * POW_tiny * POW_tiny // underflow
#| } else if p_l <= z - p_h {
#| return s * POW_tiny * POW_tiny // underflow
#| }
#| }
#| //
#| // compute 2**(p_h+p_l)
#| //
#| i = j & 0x7fffffff
#| k = (i >> 20) - 0x3ff
#| n = 0
#| if i > 0x3fe00000 { // if |z| > 0.5, set n = [z+0.5]
#| n = j + (0x00100000 >> (k + 1))
#| k = ((n & 0x7fffffff) >> 20) - 0x3ff // new k for n
#| t = ZERO
#| t = set_high_word(t, (n & (0x000fffff >> k).lnot()).reinterpret_as_uint())
#| n = ((n & 0x000fffff) | 0x00100000) >> (20 - k)
#| if j < 0 {
#| n = -n
#| }
#| p_h -= t
#| }
#| t = p_l + p_h
#| t = set_low_word(t, 0)
#| u = t * POW_lg2_h
#| v = (p_l - (t - p_h)) * POW_lg2 + t * POW_lg2_l
#| z = u + v
#| w = v - (z - u)
#| t = z * z
#| t1 = z -
#| t * (POW_P1 + t * (POW_P2 + t * (POW_P3 + t * (POW_P4 + t * POW_P5))))
#| r = z * t1 / (t1 - TWO - (w + z * w))
#| z = ONE - (r - z)
#| j = get_high_word(z).reinterpret_as_int()
#| j += (n.reinterpret_as_uint() << 20).reinterpret_as_int()
#| if j >> 20 <= 0 {
#| z = scalbn(z, n)
#| } else { // subnormal output */
#| let tmp = get_high_word(z).reinterpret_as_int()
#| z = set_high_word(
#| z,
#| (tmp + (n.reinterpret_as_uint() << 20).reinterpret_as_int()).reinterpret_as_uint(),
#| )
#| }
#| return s * z }
),
),
"from_int": build(
(
#|pub fn Double::from_int(i : Int) -> Double { i.to_double() }
),
),
"from_int": build(
(
#|pub fn from_int(i : Int) -> Double { i.to_double() }
),
),
"signum": build(
(
#|pub fn signum(self : Double) -> Double { if self < 0.0 {
#| -1.0
#| } else if self > 0.0 {
#| 1.0
#| } else {
#| self // handles 0.0, -0.0, NaN
#| } }
),
),
"is_nan": build(
(
#|pub fn is_nan(self : Double) -> Bool { // only NaNs satisfy f != f.
#| self != self }
),
),
"is_inf": build(
(
#|pub fn is_inf(self : Double) -> Bool { self > max_value || self < min_value }
),
),
"is_pos_inf": build(
(
#|pub fn is_pos_inf(self : Double) -> Bool { self > max_value }
),
),
"is_neg_inf": build(
(
#|pub fn is_neg_inf(self : Double) -> Bool { self < min_value }
),
),
"to_string": build(
(
#|pub fn to_string(self : Double) -> String { @ryu.ryu_to_string(self) }
),
),
"to_be_bytes": build(
(
#|pub fn to_be_bytes(self : Double) -> Bytes { self.reinterpret_as_uint64().to_be_bytes() }
),
),
"to_le_bytes": build(
(
#|pub fn to_le_bytes(self : Double) -> Bytes { self.reinterpret_as_uint64().to_le_bytes() }
),
),
"hypot": build(
(
#|pub fn Double::hypot(self : Double, y : Double) -> Double { if self.is_nan() || y.is_nan() {
#| return not_a_number
#| }
#| if self.is_inf() || y.is_inf() {
#| return infinity
#| }
#| let x = self.abs()
#| let y = y.abs()
#| let double_epsilon : Double = 0x0.0000000000001P-1022
#| let (x, y) = if y > x { (y, x) } else { (x, y) }
#| if x * double_epsilon >= y {
#| return x
#| }
#| let r = y / x
#| x * (1.0 + r * r).sqrt() }
),
),
"nan": build(
(
#|pub fn Double::nan() -> Double { not_a_number }
),
),
"inf": build(
(
#|pub fn Double::inf(sign : Int) -> Double { if sign >= 0 {
#| infinity
#| } else {
#| neg_infinity
#| } }
),
),
"min_normal": build(
(
#|pub fn Double::min_normal() -> Double { min_positive }
),
),
"exp": build(
(
#|pub fn Double::exp(self : Double) -> Double { fn get_high_word(x : Double) -> UInt {
#| (x.reinterpret_as_uint64() >> 32).to_uint()
#| }
#| fn get_low_word(x : Double) -> UInt {
#| x.reinterpret_as_uint64().to_uint()
#| }
#| fn insert_words(ix0 : UInt64, ix1 : UInt64) -> Double {
#| let mut bits : UInt64 = 0
#| bits = bits | (ix0 << 32)
#| bits = bits | ix1
#| bits.reinterpret_as_double()
#| }
#| let mut x = self
#| let one = 1.0
#| let halF = [0.5, -0.5]
#| let o_threshold = 7.09782712893383973096e+02
#| let u_threshold = -7.45133219101941108420e+02
#| let ln2HI = [6.93147180369123816490e-01, -6.93147180369123816490e-01]
#| let ln2LO = [1.90821492927058770002e-10, -1.90821492927058770002e-10]
#| let invln2 = 1.44269504088896338700e+00
#| let p1 = 1.66666666666666019037e-01
#| let p2 = -2.77777777770155933842e-03
#| let p3 = 6.61375632143793436117e-05
#| let p4 = -1.65339022054652515390e-06
#| let p5 = 4.13813679705723846039e-08
#| let e = 2.718281828459045
#| let mut hi = 0.0
#| let mut lo = 0.0
#| let huge = 1.0e+300
#| let twom1000 = 9.33263618503218878990e-302
#| let two1023 = 8.988465674311579539e307
#| let mut k : Int = 0
#| let mut hx : UInt = get_high_word(self)
#| let xsb : Int = ((hx >> 31) & 1).reinterpret_as_int()
#| hx = hx & 0x7FFFFFFF
#| if hx >= 0x40862E42 {
#| if hx >= 0x7FF00000 {
#| let lx : UInt = get_low_word(self)
#| if ((hx & 0xFFFFF) | lx) != 0 {
#| return self + self
#| } else if xsb == 0 {
#| return self
#| } else {
#| return 0.0
#| }
#| }
#| if self > o_threshold {
#| return huge * huge
#| }
#| if self < u_threshold {
#| return twom1000 * twom1000
#| }
#| }
#| if hx > 0x3FD62E42 {
#| if hx < 0x3FF0A2B2 {
#| if self == 1.0 {
#| return e
#| }
#| hi = self - ln2HI[xsb]
#| lo = ln2LO[xsb]
#| k = 1 - xsb - xsb
#| } else {
#| k = (invln2 * self + halF[xsb]).to_int()
#| let t = k.to_double()
#| hi = self - t * ln2HI[0]
#| lo = t * ln2LO[0]
#| }
#| x = hi - lo
#| } else if hx < 0x3E300000 {
#| if huge + x > one {
#| return one + x
#| }
#| } else {
#| k = 0
#| }
#| let t = x * x
#| let twopk = if k >= -1021 {
#| insert_words(
#| (0x3FF00000 + (k.reinterpret_as_uint() << 20).reinterpret_as_int())
#| .to_int64()
#| .reinterpret_as_uint64(),
#| 0,
#| )
#| } else {
#| insert_words(
#| 0x3FF00000UL + ((k + 1000).reinterpret_as_uint() << 20).to_uint64(),
#| 0,
#| )
#| }
#| let c = x - t * (p1 + t * (p2 + t * (p3 + t * (p4 + t * p5))))
#| if k == 0 {
#| return one - (x * c / (c - 2.0) - x)
#| }
#| let y = one - (lo - x * c / (2.0 - c) - hi)
#| if k >= -1021 {
#| if k == 1024 {
#| return y * 2.0 * two1023
#| } else {
#| return y * twopk
#| }
#| } else {
#| return y * twopk * twom1000
#| } }
),
),
"expm1": build(
(
#|pub fn Double::expm1(self : Double) -> Double { if self.is_nan() {
#| return not_a_number
#| }
#| let o_threshold = 7.09782712893383973096e+02
#| if self > o_threshold {
#| return infinity
#| }
#| if self.is_inf() {
#| return -1.0
#| }
#| let huge = 1.0e+300
#| let tiny = 1.0e-300
#| let ln2_hi = 6.93147180369123816490e-01
#| let ln2_lo = 1.90821492927058770002e-10
#| let invln2 = 1.44269504088896338700e+00
#| let q1 = -3.33333333333331316428e-02
#| let q2 = 1.58730158725481460165e-03
#| let q3 = -7.93650757867487942473e-05
#| let q4 = 4.00821782732936239552e-06
#| let q5 = -2.01099218183624371326e-07
#| let mut x = self
#| let mut hx = get_high_word(x)
#| let xsb : Int = (hx & 0x80000000).reinterpret_as_int()
#| let mut y : Double = if xsb == 0 { x } else { -x }
#| hx = hx & 0x7fffffff
#| if hx >= 0x4043687A {
#| if xsb != 0 {
#| if x + tiny < 0.0 {
#| return tiny - 1.0
#| }
#| }
#| }
#| let mut hi = 0.0
#| let mut lo = 0.0
#| let mut k = 0
#| let mut c = 0.0
#| let mut t = 0.0
#| if hx > 0x3fd62e42 {
#| if hx < 0x3FF0A2B2 {
#| hi = if xsb == 0 { x - ln2_hi } else { x + ln2_hi }
#| lo = if xsb == 0 { ln2_lo } else { -ln2_lo }
#| k = if xsb == 0 { 1 } else { -1 }
#| } else {
#| k = (invln2 * x + (if xsb == 0 { 0.5 } else { -0.5 })).to_int()
#| t = k.to_double()
#| hi = x - t * ln2_hi
#| lo = t * ln2_lo
#| }
#| x = hi - lo
#| c = hi - x - lo
#| } else if hx < 0x3c900000 {
#| t = huge + x
#| return x - (t - (huge + x))
#| } else {
#| k = 0
#| }
#| let hfx : Double = 0.5 * x
#| let hxs : Double = x * hfx
#| let r1 : Double = 1.0 +
#| hxs * (q1 + hxs * (q2 + hxs * (q3 + hxs * (q4 + hxs * q5))))
#| let t : Double = 3.0 - r1 * hfx
#| let e : Double = hxs * ((r1 - t) / (6.0 - x * t))
#| if k == 0 {
#| return x - (x * e - hxs)
#| } else {
#| let e : Double = x * (e - c) - c
#| let e : Double = e - hxs
#| if k == -1 {
#| return 0.5 * (x - e) - 0.5
#| }
#| if k == 1 {
#| return if x < -0.25 {
#| -2.0 * (e - (x + 0.5))
#| } else {
#| 1.0 + 2.0 * (x - e)
#| }
#| }
#| if k <= -2 || k > 56 {
#| y = 1.0 - (e - x)
#| y = set_high_word(y, get_high_word(y) + (k << 20).reinterpret_as_uint())
#| return y - 1.0
#| }
#| let mut t : Double = 1.0
#| if k < 20 {
#| t = set_high_word(0, (0x3ff00000 - (0x200000 >> k)).reinterpret_as_uint())
#| y = t - (e - x)
#| y = set_high_word(y, get_high_word(y) + (k << 20).reinterpret_as_uint())
#| } else {
#| t = set_high_word(0, ((0x3ff - k) << 20).reinterpret_as_uint())
#| y = x - (e + t) + 1.0
#| y = set_high_word(y, get_high_word(y) + (k << 20).reinterpret_as_uint())
#| }
#| }
#| y }
),
),
"round": build(
(
#|pub fn Double::round(self : Double) -> Double { floor(self + 0.5) }
),
),
"to_uint": build(
(
#|pub fn to_uint(self : Double) -> UInt { if self != self {
#| 0
#| } else if self >= 4294967295.0 {
#| 4294967295U
#| } else if self <= 0 {
#| 0
#| } else {
#| UInt::trunc_double(self)
#| } }
),
),
"scalbn": build(
(
#|fn scalbn(x : Double, exp : Int) -> Double { let mut n = exp
#| let mut y : Double = x
#| if n > 1023 {
#| y *= 0x1.0p1023
#| n -= 1023
#| if n > 1023 {
#| y *= 0x1.0p1023
#| n -= 1023
#| if n > 1023 {
#| n = 1023
#| }
#| }
#| } else if n < -1022 {
#| // make sure final n < -53 to avoid double
#| // rounding in the subnormal range
#| y *= 0x1.0p-1022 * 0x1.0p53
#| n += 1022 - 53
#| if n < -1022 {
#| y *= 0x1.0p-1022 * 0x1.0p53
#| n += 1022 - 53
#| if n < -1022 {
#| n = -1022
#| }
#| }
#| }
#| let ui = (0x3ff + n).to_uint64() << 52
#| return y * ui.reinterpret_as_double() }
),
),
"sqrt2": (
None,
String(
"1.41421356237309504880168872420969807856967187537694807317667974",
),
),
"ln2": (
None,
String(
"0.693147180559945309417232121458176568075500134360255254120680009",
),
),
"ln2_hi": (
None,
String("6.93147180369123816490e-01 // 3fe62e42 fee00000"),
),
"ln2_lo": (
None,
String("1.90821492927058770002e-10 // 3dea39ef 35793c76"),
),
"l1": (None, String("6.666666666666735130e-01 // 3FE55555 55555593")),
"l2": (None, String("3.999999999940941908e-01 // 3FD99999 9997FA04")),
"l3": (None, String("2.857142874366239149e-01 // 3FD24924 94229359")),
"l4": (None, String("2.222219843214978396e-01 // 3FCC71C5 1D8E78AF")),
"l5": (None, String("1.818357216161805012e-01 // 3FC74664 96CB03DE")),
"l6": (None, String("1.531383769920937332e-01 // 3FC39A09 D078C69F")),
"l7": (None, String("1.479819860511658591e-01 // 3FC2F112 DF3E5244")),
"normalize": build(
(
#|fn normalize(f : Double) -> (Double, Int) { if f.abs() < min_positive {
#| return (f * (1L << 52).to_double(), -52)
#| }
#| (f, 0) }
),
),
"frexp": build(
(
#|fn frexp(f : Double) -> (Double, Int) { if f == 0.0 || f.is_inf() || f.is_nan() {
#| return (f, 0)
#| }
#| let (norm_f, exp) = normalize(f)
#| let u = norm_f.reinterpret_as_uint64()
#| let exp = exp + ((u >> 52) & 0x7FF).to_int() - 1022
#| let frac = ((u & (0x7FFUL << 52).lnot()) | (1022UL << 52)).reinterpret_as_double()
#| return (frac, exp) }
),
),
"ln": build(
(
#|pub fn Double::ln(self : Double) -> Double { if self < 0.0 {
#| return not_a_number
#| } else if self.is_nan() || self.is_inf() {
#| return self
#| } else if self == 0.0 {
#| return neg_infinity
#| }
#| let (f1, ki) = frexp(self)
#| let (f, k) = if f1 < sqrt2 / 2.0 {
#| (f1 * 2.0 - 1.0, (ki - 1).to_double())
#| } else {
#| (f1 - 1.0, ki.to_double())
#| }
#| let s = f / (2.0 + f)
#| let s2 = s * s
#| let s4 = s2 * s2
#| let t1 = s2 * (l1 + s4 * (l3 + s4 * (l5 + s4 * l7)))
#| let t2 = s4 * (l2 + s4 * (l4 + s4 * l6))
#| let r = t1 + t2
#| let hfsq = 0.5 * f * f
#| k * ln2_hi - (hfsq - (s * (hfsq + r) + k * ln2_lo) - f) }
),
),
"log2": build(
(
#|pub fn Double::log2(self : Double) -> Double { let (f, e) = frexp(self)
#| if f == 0.5 {
#| return e.to_double() - 1.0
#| }
#| ln(f) / ln2 + e.to_double() }
),
),
"log10": build(
(
#|pub fn Double::log10(self : Double) -> Double { if self < 0.0 {
#| return not_a_number
#| } else if self.is_nan() || self.is_inf() {
#| return self
#| } else if self == 0.0 {
#| return neg_infinity
#| }
#| let ivln10 = 4.34294481903251816668e-01
#| let log10_2hi = 3.01029995663611771306e-01
#| let log10_2lo = 3.69423907715893078616e-13
#| let (f, e) = frexp(self)
#| let (f, e) = if e >= 1 {
#| (f * 2.0, (e - 1).to_double())
#| } else {
#| (f, e.to_double())
#| }
#| let z = e * log10_2lo + ivln10 * f.ln()
#| z + e * log10_2hi }
),
),
"ln_1p": build(
(
#|pub fn Double::ln_1p(self : Double) -> Double { if self < -1.0 || self.is_nan() {
#| return not_a_number
#| }
#| if self == -1.0 {
#| return neg_infinity
#| }
#| if self.is_inf() {
#| return infinity
#| }
#| let ln2_hi = 6.93147180369123816490e-01
#| let ln2_lo = 1.90821492927058770002e-10
#| let two54 = 1.80143985094819840000e+16
#| let lp1 = 6.666666666666735130e-01
#| let lp2 = 3.999999999940941908e-01
#| let lp3 = 2.857142874366239149e-01
#| let lp4 = 2.222219843214978396e-01
#| let lp5 = 1.818357216161805012e-01
#| let lp6 = 1.531383769920937332e-01
#| let zero = 0.0
#| let lp7 = 1.479819860511658591e-01
#| let hx = get_high_word(self).reinterpret_as_int()
#| let ax = hx & 0x7fffffff
#| let mut f = 0.0
#| let mut c = 0.0
#| let mut s = 0.0
#| let mut z = 0.0
#| let mut r = 0.0
#| let mut u = 0.0
#| let mut hu = 0
#| let mut k = 1
#| if hx < 0x3FDA827A {
#| if ax < 0x3e200000 {
#| if two54 + self > zero && ax < 0x3c900000 {
#| return self
#| } else {
#| return self - self * self * 0.5
#| }
#| }
#| if hx > 0 || hx <= 0xbfd2bec3 {
#| k = 0
#| f = self
#| hu = 1
#| }
#| }
#| if k != 0 {
#| if hx < 0x43400000 {
#| u = 1.0 + self
#| hu = get_high_word(u).reinterpret_as_int()
#| k = (hu >> 20) - 1023
#| c = if k > 0 { 1.0 - (u - self) } else { self - (u - 1.0) }
#| c /= u
#| } else {
#| u = self
#| hu = get_high_word(u).reinterpret_as_int()
#| k = (hu >> 20) - 1023
#| c = 0.0
#| }
#| hu = hu & 0x000fffff
#| if hu < 0x6a09e {
#| u = set_high_word(u, hu.reinterpret_as_uint() | 0x3ff00000)
#| } else {
#| k += 1
#| u = set_high_word(u, hu.reinterpret_as_uint() | 0x3fe00000)
#| hu = (0x00100000 - hu) >> 2
#| }
#| f = u - 1.0
#| }
#| let hfsq = 0.5 * f * f
#| if hu == 0 {
#| if f == zero {
#| if k == 0 {
#| return zero
#| } else {
#| c += k.to_double() * ln2_lo
#| return k.to_double() * ln2_hi + c
#| }
#| }
#| r = hfsq * (1.0 - 0.66666666666666666 * f)
#| if k == 0 {
#| return f - r
#| } else {
#| return k.to_double() * ln2_hi - (r - (k.to_double() * ln2_lo + c) - f)
#| }
#| }
#| s = f / (2.0 + f)
#| z = s * s
#| r = z *
#| (lp1 + z * (lp2 + z * (lp3 + z * (lp4 + z * (lp5 + z * (lp6 + z * lp7))))))
#| if k == 0 {
#| return f - (hfsq - s * (hfsq + r))
#| } else {
#| return k.to_double() * ln2_hi -
#| (hfsq - (s * (hfsq + r) + (k.to_double() * ln2_lo + c)) - f)
#| } }
),
),
"cbrt": build(
(
#|pub fn Double::cbrt(self : Double) -> Double { if self.is_inf() || self.is_nan() || self == 0.0 {
#| return self
#| }
#| let b1 : UInt = 715094163 // B1 = (682-0.03306235651)*2**20
#| let b2 : UInt = 696219795 // B2 = (664-0.03306235651)*2**20
#| let c = 5.42857142857142815906e-01 // 19/35 = 0x3FE15F15, 0xF15F15F1
#| let d = -7.05306122448979611050e-01 // -864/1225 = 0xBFE691DE, 0x2532C834
#| let e = 1.41428571428571436819e+00 // 99/70 = 0x3FF6A0EA, 0x0EA0EA0F
#| let f = 1.60714285714285720630e+00 // 45/28 = 0x3FF9B6DB, 0x6DB6DB6E
#| let g = 3.57142857142857150787e-01 // 5/14 = 0x3FD6DB6D, 0xB6DB6DB7
#| let hx = get_high_word(self).reinterpret_as_int()
#| let sign = if self < 0.0 { true } else { false }
#| let self = abs(self)
#| let t = if hx < 0x00100000 {
#| let t : UInt64 = 0x43500000_00000000
#| let t : Double = t.reinterpret_as_double()
#| let t = t * self
#| set_high_word(0, get_high_word(t) / 3 + b2)
#| } else {
#| set_high_word(0, hx.reinterpret_as_uint() / 3 + b1)
#| }
#| let r = t * t / self
#| let s = c + r * t
#| let t = t * (g + f / (s + e + d / s))
#| let t = set_high_word(0, get_high_word(t) + 0x00000001)
#| let s = t * t
#| let r = self / s
#| let w = t + t
#| let r = (r - t) / (w + r)
#| let t = t + t * r
#| if sign {
#| -t
#| } else {
#| t
#| } }
),
),
}
},
)
///|
let moonbitlang_core_double_internal_ryu_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/double/internal/ryu",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/bool": moonbitlang_core_bool_module,
},
fn(_env, build) {
{
"string_from_bytes": build(
(
#|fn string_from_bytes(bytes : FixedArray[Byte], from : Int, to : Int) -> String { let buf = StringBuilder::new(size_hint=bytes.length())
#| for i in from.. (UInt64, UInt64) { let aLo = a & 0xffffffff
#| let aHi = a >> 32
#| let bLo = b & 0xffffffff
#| let bHi = b >> 32
#| let x = aLo * bLo
#| let y = aHi * bLo + (x >> 32)
#| let z = aLo * bHi + (y & 0xffffffff)
#| let w = aHi * bHi + (y >> 32) + (z >> 32)
#| let lo = a * b
#| let hi = w
#| (lo, hi) }
),
),
"shiftright128": build(
(
#|fn shiftright128(lo : UInt64, hi : UInt64, dist : Int) -> UInt64 { (hi << (64 - dist)) | (lo >> dist) }
),
),
"pow5Factor": build(
(
#|fn pow5Factor(value : UInt64) -> Int { // We want to find the largest power of 5 that divides value.
#| if value % 5UL != 0UL {
#| return 0
#| }
#| if value % 25UL != 0UL {
#| return 1
#| }
#| if value % 125UL != 0UL {
#| return 2
#| }
#| if value % 625UL != 0UL {
#| return 3
#| }
#| let mut count = 4
#| let mut value = value / 625UL
#| while value > 0UL {
#| if value % 5UL != 0UL {
#| return count
#| }
#| value = value / 5UL
#| count = count + 1
#| }
#| abort(\"IllegalArgumentException \\{value}\") }
),
),
"multipleOfPowerOf5": build(
(
#|fn multipleOfPowerOf5(value : UInt64, p : Int) -> Bool { pow5Factor(value) >= p }
),
),
"multipleOfPowerOf2": build(
(
#|fn multipleOfPowerOf2(value : UInt64, p : Int) -> Bool { (value & ((1UL << p) - 1UL)) == 0UL }
),
),
"gPOW5_TABLE_SIZE": (None, Int(26)),
"double_computePow5": build(
(
#|fn double_computePow5(i : Int) -> (UInt64, UInt64) { let base = i / gPOW5_TABLE_SIZE
#| let base2 = base * gPOW5_TABLE_SIZE
#| let offset = i - base2
#| let mul0 = gDOUBLE_POW5_SPLIT2[base * 2]
#| let mul1 = gDOUBLE_POW5_SPLIT2[base * 2 + 1]
#| if offset == 0 {
#| return (mul0, mul1)
#| }
#| let m : UInt64 = gDOUBLE_POW5_TABLE[offset]
#| let (low1, high1) = umul128(m, mul1)
#| let (low0, high0) = umul128(m, mul0)
#| let sum : UInt64 = high0 + low1
#| let mut high1 = high1
#| if sum < high0 {
#| high1 = high1 + 1UL
#| }
#| let delta : Int = pow5bits(i) - pow5bits(base2)
#| let a = shiftright128(low0, sum, delta) +
#| ((gPOW5_OFFSETS[i / 16] >> ((i % 16) << 1)) & 3).to_uint64()
#| let b = shiftright128(sum, high1, delta)
#| (a, b) }
),
),
"double_computeInvPow5": build(
(
#|fn double_computeInvPow5(i : Int) -> (UInt64, UInt64) { let base = (i + gPOW5_TABLE_SIZE - 1) / gPOW5_TABLE_SIZE
#| let base2 = base * gPOW5_TABLE_SIZE
#| let offset = base2 - i
#| let mul0 = gDOUBLE_POW5_INV_SPLIT2[base * 2]
#| let mul1 = gDOUBLE_POW5_INV_SPLIT2[base * 2 + 1]
#| if offset == 0 {
#| return (mul0, mul1)
#| }
#| let m = gDOUBLE_POW5_TABLE[offset]
#| let (low1, high1) = umul128(m, mul1)
#| let (low0, high0) = umul128(m, mul0)
#| let sum = high0 + low1
#| let mut high1 = high1
#| if sum < high0 {
#| high1 = high1 + 1
#| }
#| let delta : Int = pow5bits(base2) - pow5bits(i)
#| let a = shiftright128(low0, sum, delta) +
#| 1 +
#| ((gPOW5_INV_OFFSETS[i / 16] >> ((i % 16) << 1)) & 3).to_uint64()
#| let b = shiftright128(sum, high1, delta)
#| (a, b) }
),
),
"decimal_length17": build(
(
#|fn decimal_length17(v : UInt64) -> Int { // This is slightly faster than a loop.
#| // The average output length is 16.38 digits, so we check high-to-low.
#| // Function precondition: v is not an 18, 19, or 20-digit number.
#| // (17 digits are sufficient for round-tripping.)
#| if v >= 10000000000000000 {
#| return 17
#| }
#| if v >= 1000000000000000 {
#| return 16
#| }
#| if v >= 100000000000000 {
#| return 15
#| }
#| if v >= 10000000000000 {
#| return 14
#| }
#| if v >= 1000000000000 {
#| return 13
#| }
#| if v >= 100000000000 {
#| return 12
#| }
#| if v >= 10000000000 {
#| return 11
#| }
#| if v >= 1000000000 {
#| return 10
#| }
#| if v >= 100000000 {
#| return 9
#| }
#| if v >= 10000000 {
#| return 8
#| }
#| if v >= 1000000 {
#| return 7
#| }
#| if v >= 100000 {
#| return 6
#| }
#| if v >= 10000 {
#| return 5
#| }
#| if v >= 1000 {
#| return 4
#| }
#| if v >= 100 {
#| return 3
#| }
#| if v >= 10 {
#| return 2
#| }
#| return 1 }
),
),
"d2d": build(
(
#|fn d2d(ieeeMantissa : UInt64, ieeeExponent : UInt) -> FloatingDecimal64 { let mut e2 : Int = 0
#| let mut m2 : UInt64 = 0
#| if ieeeExponent == 0 {
#| // Denormal number - no implicit leading 1, and the exponent is 1, not 0.
#| e2 = 1 - gDOUBLE_BIAS - gDOUBLE_MANTISSA_BITS - 2
#| m2 = ieeeMantissa
#| } else {
#| // Add implicit leading 1.
#| e2 = ieeeExponent.reinterpret_as_int() -
#| gDOUBLE_BIAS -
#| gDOUBLE_MANTISSA_BITS -
#| 2
#| m2 = (1UL << gDOUBLE_MANTISSA_BITS) | ieeeMantissa
#| }
#| let even = (m2 & 1UL) == 0UL
#| let mv = 4UL *
#| // Step 2: Determine the interval of valid decimal representations.
#| m2
#| // Implicit bool -> int conversion. True is 1, false is 0.
#| let mmShift = ieeeMantissa != 0UL || ieeeExponent <= 1
#| // We would compute mp and mm like this:
#| // uint64_t mp = 4 * m2 + 2;
#| // uint64_t mm = mv - 1 - mmShift;
#| // Step 3: Convert to a decimal power base using 128-bit arithmetic.
#| let mut vr = 0UL
#| let mut vp = 0UL
#| let mut vm = 0UL
#| let mut e10 : Int = 0
#| let mut vmIsTrailingZeros = false
#| let mut vrIsTrailingZeros = false
#| if e2 >= 0 {
#| // I tried special-casing q == 0, but there was no effect on performance.
#| // This expression is slightly faster than max(0, log10Pow2(e2) - 1).
#| let q : Int = log10Pow2(e2) - (e2 > 3).to_int()
#| e10 = q
#| let k = gDOUBLE_POW5_INV_BITCOUNT + pow5bits(q) - 1
#| let i = -e2 + q + k
#| let pow5 = double_computeInvPow5(q)
#| let vs = mulShiftAll64(m2, pow5, i, mmShift)
#| vr = vs.0
#| vp = vs.1
#| vm = vs.2
#| if q <= 21 {
#| // This should use q <= 22, but I think 21 is also safe. Smaller values
#| // may still be safe, but it's more difficult to reason about them.
#| // Only one of mp, mv, and mm can be a multiple of 5, if any.
#| let mvMod5 : Int = mv.to_int() - 5 * (mv / 5UL).to_int()
#| if mvMod5 == 0 {
#| vrIsTrailingZeros = multipleOfPowerOf5(mv, q)
#| } else if even {
#| // Same as min(e2 + (~mm & 1), pow5Factor(mm)) >= q
#| // <=> e2 + (~mm & 1) >= q && pow5Factor(mm) >= q
#| // <=> true && pow5Factor(mm) >= q, since e2 >= q.
#| vmIsTrailingZeros = multipleOfPowerOf5(
#| mv - 1UL - mmShift.to_uint64(),
#| q,
#| )
#| } else {
#| vp = vp - multipleOfPowerOf5(mv + 2UL, q).to_uint64()
#| }
#| }
#| } else {
#| // This expression is slightly faster than max(0, log10Pow5(-e2) - 1).
#| let q : Int = log10Pow5(-e2) - (-e2 > 1).to_int()
#| e10 = q + e2
#| let i : Int = -e2 - q
#| let k = pow5bits(i) - gDOUBLE_POW5_BITCOUNT
#| let j = q - k
#| let pow5 = double_computePow5(i)
#| let vs = mulShiftAll64(m2, pow5, j, mmShift)
#| vr = vs.0
#| vp = vs.1
#| vm = vs.2
#| if q <= 1 {
#| // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits.
#| // mv = 4 * m2, so it always has at least two trailing 0 bits.
#| vrIsTrailingZeros = true
#| if even {
#| vmIsTrailingZeros = mmShift.to_int() == 1
#| } else {
#| vp = vp - 1
#| }
#| } else if q < 63 {
#| vrIsTrailingZeros = multipleOfPowerOf2(mv, q)
#| }
#| }
#| // Step 4: Find the shortest decimal representation in the interval of valid representations.
#| let mut removed : Int = 0
#| let mut lastRemovedDigit : Int = 0
#| let mut output : UInt64 = 0UL
#| // On average, we remove ~2 digits.
#| if vmIsTrailingZeros || vrIsTrailingZeros {
#| // General case, which happens rarely (~0.7%).
#| while true {
#| let vpDiv10 = vp / 10
#| let vmDiv10 = vm / 10
#| if vpDiv10 <= vmDiv10 {
#| break
#| }
#| let vmMod10 : Int = vm.to_int() - 10 * vmDiv10.to_int()
#| let vrDiv10 = vr / 10
#| let vrMod10 : Int = vr.to_int() - 10 * vrDiv10.to_int()
#| vmIsTrailingZeros = vmIsTrailingZeros && vmMod10 == 0
#| vrIsTrailingZeros = vrIsTrailingZeros && lastRemovedDigit == 0
#| lastRemovedDigit = vrMod10
#| vr = vrDiv10
#| vp = vpDiv10
#| vm = vmDiv10
#| removed = removed + 1
#| }
#| if vmIsTrailingZeros {
#| while true {
#| let vmDiv10 = vm / 10
#| let vmMod10 : Int = vm.to_int() - 10 * vmDiv10.to_int()
#| if vmMod10 != 0 {
#| break
#| }
#| let vpDiv10 = vp / 10
#| let vrDiv10 = vr / 10
#| let vrMod10 : Int = vr.to_int() - 10 * vrDiv10.to_int()
#| vrIsTrailingZeros = vrIsTrailingZeros && lastRemovedDigit == 0
#| lastRemovedDigit = vrMod10
#| vr = vrDiv10
#| vp = vpDiv10
#| vm = vmDiv10
#| removed = removed + 1
#| }
#| }
#| if vrIsTrailingZeros && lastRemovedDigit == 5 && vr % 2 == 0 {
#| lastRemovedDigit = 4
#| }
#| output = vr +
#| ((vr == vm && (!even || !vmIsTrailingZeros)) || lastRemovedDigit >= 5)
#| .to_int64()
#| .reinterpret_as_uint64()
#| } else {
#| // Specialized for the common case (~99.3%). Percentages below are relative to this.
#| let mut roundUp = false
#| let vpDiv100 = vp / 100
#| let vmDiv100 = vm / 100
#| if vpDiv100 > vmDiv100 {
#| let vrDiv100 = vr / 100
#| let vrMod100 : Int = vr.to_int() - 100 * vrDiv100.to_int()
#| roundUp = vrMod100 >= 50
#| vr = vrDiv100
#| vp = vpDiv100
#| vm = vmDiv100
#| removed = removed + 2
#| }
#| // Loop iterations below (approximately), without optimization above:
#| // 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02%
#| // Loop iterations below (approximately), with optimization above:
#| // 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02%
#| while true {
#| let vpDiv10 = vp / 10
#| let vmDiv10 = vm / 10
#| if vpDiv10 <= vmDiv10 {
#| break
#| }
#| let vrDiv10 = vr / 10
#| let vrMod10 : Int = vr.to_int() - 10 * vrDiv10.to_int()
#| roundUp = vrMod10 >= 5
#| vr = vrDiv10
#| vp = vpDiv10
#| vm = vmDiv10
#| removed = removed + 1
#| }
#| output = vr + (vr == vm || roundUp).to_uint64()
#| }
#| let exp : Int = e10 + removed
#| let fd : FloatingDecimal64 = { mantissa: output, exponent: exp }
#| fd }
),
),
"to_chars": build(
(
#|fn to_chars(v : FloatingDecimal64, sign : Bool) -> String { // Step 5: Print the decimal representation.
#| let result = FixedArray::make(25, Byte::default())
#| let mut index : Int = 0
#| if sign {
#| result[index] = b'-'
#| index += 1
#| }
#| let mut output = v.mantissa
#| let olength = decimal_length17(output)
#| let mut exp : Int = v.exponent + olength - 1
#| let scientificNotation = !(exp >= -6 && exp < 21)
#| if scientificNotation {
#| // Print the decimal digits.
#| for i in 0..<(olength - 1) {
#| let c = output % 10
#| output /= 10
#| // 48 is ASCII '0', the same applies below.
#| result[index + olength - i] = (48 + c.to_int()).to_byte()
#| }
#| result[index] = (48 + output.to_int() % 10).to_byte()
#| if olength > 1 {
#| result[index + 1] = b'.'
#| } else {
#| // If there are no decimals, suppress .0
#| index -= 1
#| }
#| index += olength + 1
#| // Print the exponent.
#| result[index] = b'e'
#| index += 1
#| if exp < 0 {
#| result[index] = b'-'
#| index += 1
#| exp = -exp
#| } else {
#| result[index] = b'+'
#| index += 1
#| }
#| if exp >= 100 {
#| let a = exp / 100
#| let b = exp / 10 % 10
#| let c = exp % 10
#| result[index + 0] = (48 + a).to_byte()
#| result[index + 1] = (48 + b).to_byte()
#| result[index + 2] = (48 + c).to_byte()
#| index += 3
#| } else if exp >= 10 {
#| let a = exp / 10
#| let b = exp % 10
#| result[index + 0] = (48 + a).to_byte()
#| result[index + 1] = (48 + b).to_byte()
#| index += 2
#| } else {
#| result[index] = (48 + exp).to_byte()
#| index += 1
#| }
#| string_from_bytes(result, 0, index)
#| } else {
#| // Otherwise follow the ECMAScript spec.
#| if exp < 0 {
#| // Decimal dot is before any of the digits.
#| result[index] = b'0'
#| index += 1
#| result[index] = b'.'
#| index += 1
#| for i = -1; i > exp; i = i - 1 {
#| result[index] = b'0'
#| index += 1
#| }
#| let current = index
#| for i in 0..= olength {
#| // Decimal dot is after any of the digits.
#| for i in 0.. String { if val == 0.0 {
#| return \"0\"
#| }
#| // Step 1: Decode the floating-point number, and unify normalized and subnormal cases.
#| let bits : UInt64 = val.reinterpret_as_uint64()
#| // Decode bits into sign, mantissa, and exponent.
#| let ieeeSign = (
#| (bits >> (gDOUBLE_MANTISSA_BITS + gDOUBLE_EXPONENT_BITS)) & 1UL
#| ) !=
#| 0UL
#| let ieeeMantissa : UInt64 = bits & ((1UL << gDOUBLE_MANTISSA_BITS) - 1UL)
#| let ieeeExponent : Int = ((bits >> gDOUBLE_MANTISSA_BITS) &
#| ((1UL << gDOUBLE_EXPONENT_BITS) - 1UL)).to_int()
#| if ieeeExponent == (1 << gDOUBLE_EXPONENT_BITS) - 1 ||
#| (ieeeExponent == 0 && ieeeMantissa == 0UL) {
#| return copy_special_str(ieeeSign, ieeeExponent != 0, ieeeMantissa != 0UL)
#| }
#| let mut v : FloatingDecimal64 = { mantissa: 0UL, exponent: 0 }
#| let small = d2d_small_int(ieeeMantissa, ieeeExponent)
#| match small {
#| Some(f) => {
#| let mut x = f
#| while true {
#| let q : UInt64 = x.mantissa / 10
#| let r = x.mantissa - 10UL * q
#| if r != 0 {
#| break
#| }
#| x = { mantissa: q, exponent: x.exponent + 1 }
#| }
#| v = x
#| }
#| None => v = d2d(ieeeMantissa, ieeeExponent.reinterpret_as_uint())
#| }
#| to_chars(v, ieeeSign) }
),
),
"pow5bits": build(
(
#|fn pow5bits(e : Int) -> Int { ((e * 1217359).reinterpret_as_uint() >> 19).reinterpret_as_int() + 1 }
),
),
"copy_special_str": build(
(
#|fn copy_special_str(sign : Bool, exponent : Bool, mantissa : Bool) -> String { if mantissa {
#| return \"NaN\"
#| }
#| let s = if sign { \"-\" } else { \"\" }
#| if exponent {
#| return s + \"Infinity\"
#| }
#| return s + \"0.0\" }
),
),
"log10Pow5": build(
(
#|fn log10Pow5(e : Int) -> Int { ((e * 732923).reinterpret_as_uint() >> 20).reinterpret_as_int() }
),
),
"log10Pow2": build(
(
#|fn log10Pow2(e : Int) -> Int { ((e * 78913).reinterpret_as_uint() >> 18).reinterpret_as_int() }
),
),
}
},
)
///|
let moonbitlang_core_env_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/env",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
fn(_env, build) {
{
"args": build(
(
#|pub fn args() -> Array[String] { get_cli_args_internal() }
),
),
"now": build(
(
#|pub fn now() -> UInt64 { now_internal() }
),
),
"current_dir": build(
(
#|pub fn current_dir() -> String? { current_dir_internal() }
),
),
"string_from_extern": build(
(
#|fn string_from_extern(e : XExternString) -> String { let buf = StringBuilder::new()
#| let handle = begin_read_string(e)
#| while true {
#| let ch = string_read_char(handle)
#| if ch == -1 {
#| break
#| } else {
#| buf.write_char(ch.unsafe_to_char())
#| }
#| }
#| finish_read_string(handle)
#| buf.to_string() }
),
),
"string_array_from_extern": build(
(
#|fn string_array_from_extern(e : XExternStringArray) -> Array[String] { let buf = Array::new()
#| let handle = begin_read_string_array(e)
#| while true {
#| let extern_str = string_array_read_string(handle)
#| let str = string_from_extern(extern_str)
#| // keep \"ffi_end_of_/string_array\" same with moonrun
#| if str == \"ffi_end_of_/string_array\" {
#| break
#| } else {
#| buf.push(str)
#| }
#| }
#| finish_read_string_array(handle)
#| buf }
),
),
"get_cli_args_internal": build(
(
#|fn get_cli_args_internal() -> Array[String] { let args = get_cli_args_ffi()
#| string_array_from_extern(args) }
),
),
"current_dir_internal": build(
(
#|fn current_dir_internal() -> String? { let dir = current_dir_ffi()
#| let dir = string_from_extern(dir)
#| if dir == \"\" {
#| None
#| } else {
#| Some(dir)
#| } }
),
),
"get_cli_args_internal": build(
(
#|fn get_cli_args_internal() -> Array[String] { let tmp = get_cli_args_ffi()
#| let res = Array::new(capacity=tmp.length())
#| for i in 0.. String { let res = StringBuilder::new()
#| let len = bytes.length()
#| let mut i = 0
#| while i < len {
#| let mut c = bytes[i].to_int()
#| // zero byte indicates end of string
#| if c == 0 {
#| break
#| } else if c < 0x80 {
#| res.write_char(c.unsafe_to_char())
#| i += 1
#| } else if c < 0xE0 {
#| if i + 1 >= len {
#| break
#| }
#| c = ((c & 0x1F) << 6) | (bytes[i + 1].to_int() & 0x3F)
#| res.write_char(c.unsafe_to_char())
#| i += 2
#| } else if c < 0xF0 {
#| if i + 2 >= len {
#| break
#| }
#| c = ((c & 0x0F) << 12) |
#| ((bytes[i + 1].to_int() & 0x3F) << 6) |
#| (bytes[i + 2].to_int() & 0x3F)
#| res.write_char(c.unsafe_to_char())
#| i += 3
#| } else {
#| if i + 3 >= len {
#| break
#| }
#| c = ((c & 0x07) << 18) |
#| ((bytes[i + 1].to_int() & 0x3F) << 12) |
#| ((bytes[i + 2].to_int() & 0x3F) << 6) |
#| (bytes[i + 3].to_int() & 0x3F)
#| c -= 0x10000
#| res.write_char(((c >> 10) + 0xD800).unsafe_to_char())
#| res.write_char(((c & 0x3FF) + 0xDC00).unsafe_to_char())
#| i += 4
#| }
#| }
#| res.to_string() }
),
),
"now_internal": build(
(
#|fn now_internal() -> UInt64 { // time returns seconds since 1970-01-01 00:00:00 UTC
#| // to be consistent with other backends, we convert to milliseconds
#| time(0) * 1000 }
),
),
"current_dir_internal": build(
(
#|fn current_dir_internal() -> String? { // TODO: On Windows getcwd may fail if the path is too long(Windows allows paths up to 32k characters)
#| let buf = Bytes::new(4096)
#| let res = getcwd(buf, buf.length())
#| if res == 0 {
#| None
#| } else {
#| Some(utf8_bytes_to_mbt_string(buf))
#| } }
),
),
}
},
)
///|
let moonbitlang_core_float_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/float",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/double": moonbitlang_core_double_module,
"moonbitlang/core/uint": moonbitlang_core_uint_module,
},
fn(_env, build) {
{
"exp_bias": (None, Int(127)),
"exp_bits": (None, Int(8)),
"frac_bits": (None, Int(23)),
"trunc": build(
(
#|pub fn Float::trunc(self : Float) -> Float { let u32 = self.reinterpret_as_uint()
#| let biased_exp = ((u32 >> frac_bits) & ((0x1U << exp_bits) - 1)).reinterpret_as_int()
#| if biased_exp < exp_bias {
#| return (u32 & sign_mask).reinterpret_as_float()
#| } else if biased_exp >= exp_bias + frac_bits {
#| return self
#| }
#| let mask_shift = biased_exp - exp_bias + exp_bits
#| let trunc_mask = (sign_mask.reinterpret_as_int() >> mask_shift).reinterpret_as_uint()
#| return (u32 & trunc_mask).reinterpret_as_float() }
),
),
"ceil": build(
(
#|pub fn Float::ceil(self : Float) -> Float { let trunced = self.trunc()
#| if self > trunced {
#| return trunced + 1.0
#| } else {
#| return trunced
#| } }
),
),
"floor": build(
(
#|pub fn Float::floor(self : Float) -> Float { let trunced = self.trunc()
#| if self < trunced {
#| return trunced - 1.0
#| } else {
#| return trunced
#| } }
),
),
"round": build(
(
#|pub fn Float::round(self : Float) -> Float { floor(self + 0.5) }
),
),
"default": build(
(
#|pub fn default() -> Float { 0.0 }
),
),
"to_be_bytes": build(
(
#|pub fn to_be_bytes(self : Float) -> Bytes { self.reinterpret_as_uint().to_be_bytes() }
),
),
"to_le_bytes": build(
(
#|pub fn to_le_bytes(self : Float) -> Bytes { self.reinterpret_as_uint().to_le_bytes() }
),
),
"is_inf": build(
(
#|pub fn is_inf(self : Float) -> Bool { self.is_pos_inf() || self.is_neg_inf() }
),
),
"is_pos_inf": build(
(
#|pub fn is_pos_inf(self : Float) -> Bool { self > max_value }
),
),
"is_neg_inf": build(
(
#|pub fn is_neg_inf(self : Float) -> Bool { self < min_value }
),
),
"is_nan": build(
(
#|pub fn is_nan(self : Float) -> Bool { self != self }
),
),
"cbrt": build(
(
#|pub fn Float::cbrt(self : Float) -> Float { let b1 : UInt = 709958130 // B1 = (127-127.0/3-0.03306235651)*2**23 */
#| let b2 : UInt = 642849266 // B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */
#| let mut ui : UInt = self.reinterpret_as_uint()
#| let mut hx : UInt = ui & 0x7fffffff
#| if hx >= 0x7f800000 {
#| // cbrt(NaN,INF) is itx
#| return self + self
#| }
#| // rough cbrt to 5 bits
#| if hx < 0x00800000 {
#| // zero or subnormal?
#| if hx == 0 {
#| return self
#| } // cbrt(+-0) is itx
#| ui = (self * (0x1.0p24 : Float)).reinterpret_as_uint()
#| hx = ui & 0x7fffffff
#| hx = hx / 3 + b2
#| } else {
#| hx = hx / 3 + b1
#| }
#| ui = ui & 0x80000000
#| ui = ui | hx
#| //
#| // First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In
#| // double precision so that its terms can be arranged for efficiency
#| // without causing overflow or underflow.
#| //
#| let dx = self.to_double()
#| let t = ui.reinterpret_as_float().to_double()
#| let r = t * t * t
#| let t = t * (dx + dx + r) / (dx + r + r)
#| //
#| // Second step Newton iteration to 47 bits. In double precision for
#| // efficiency and accuracy.
#| //
#| let r = t * t * t
#| let t = t * (dx + dx + r) / (dx + r + r)
#| // rounding to 24 bits is perfect in round-to-nearest mode
#| t.to_float() }
),
),
"hypot": build(
(
#|pub fn Float::hypot(self : Float, y : Float) -> Float { let epsilon : Float = 1.1920928955078125e-7
#| let x = self.abs()
#| let y = y.abs()
#| if self.is_inf() || y.is_inf() {
#| return infinity
#| }
#| let (x, y) = if y > x { (y, x) } else { (x, y) }
#| if x * epsilon >= y {
#| return x
#| }
#| let rat = y / x
#| x * (rat * rat + 1.0).sqrt() }
),
),
"exp": build(
(
#|pub fn Float::exp(self : Float) -> Float { let xd = self.to_double()
#| let abstop = top12(self) & 0x7ff
#| if abstop >= top12(88.0) {
#| if self.reinterpret_as_uint() == neg_infinity.reinterpret_as_uint() {
#| return 0.0
#| }
#| if abstop >= top12(infinity) {
#| return self + self
#| }
#| if self > 0x1.62e42ep6 {
#| return __math_oflowf(0)
#| }
#| if self < -0x1.9fe368p6 {
#| return __math_uflowf(0)
#| }
#| }
#| let z = exp2f_data.invln2_scaled * xd
#| let kd = z + exp2f_data.shift
#| let ki = kd.reinterpret_as_uint64()
#| let kd = kd - exp2f_data.shift
#| let r = z - kd
#| let t = exp2f_data.tab[(ki % expf_n).to_int()]
#| let t = t + (ki << (52 - exp2f_table_bits))
#| let s = t.reinterpret_as_double()
#| let z = exp2f_data.poly_scaled[0] * r + exp2f_data.poly_scaled[1]
#| let r2 = r * r
#| let y = exp2f_data.poly_scaled[2] * r + 1
#| let y = z * r2 + y
#| let y = y * s
#| y.to_float() }
),
),
"expm1": build(
(
#|pub fn Float::expm1(self : Float) -> Float { let float_ln2_hi : Float = 6.9314575195e-01 // 0x3f317200
#| let float_ln2_lo : Float = 1.4286067653e-06 // 0x35bfbe8e
#| let inv_ln2 : Float = 1.4426950216e+00 // 0x3fb8aa3b
#| let mut x = self
#| let q1 : Float = -3.3333212137e-2 // -0x888868.0p-28
#| let q2 : Float = 1.5807170421e-3 // 0xcf3010.0p-33
#| let mut hx = x.reinterpret_as_uint()
#| let sign = hx >> 31 != 0
#| hx = hx & 0x7fffffff
#| // filter out huge and non-finite argument
#| if hx >= 0x4195b844 {
#| // if |x|>=27*ln2
#| if hx > 0x7f800000 {
#| // NaN
#| return x
#| }
#| if sign {
#| return -1.0
#| }
#| if hx > 0x42b17217 {
#| x *= (0x1.0p127 : Float)
#| return x
#| }
#| }
#| let mut k : Int = 0
#| let mut hi : Float = 0
#| let mut lo : Float = 0
#| let mut c : Float = 0
#| // argument reduction
#| if hx > 0x3eb17218 {
#| // if |x| > 0.5 ln2
#| if hx < 0x3F851592 {
#| // and |x| < 1.5 ln2
#| if !sign {
#| hi = x - float_ln2_hi
#| lo = float_ln2_lo
#| k = 1
#| } else {
#| hi = x + float_ln2_hi
#| lo = -float_ln2_lo
#| k = -1
#| }
#| } else {
#| k = (inv_ln2 * x + (if sign { -0.5 } else { 0.5 })).to_int()
#| let t = k.to_float()
#| hi = x - t * float_ln2_hi // t*ln2_hi is exact here
#| lo = t * float_ln2_lo
#| }
#| x = hi - lo
#| c = hi - x - lo
#| } else if hx < 0x33000000 {
#| // when |x|<2**-25, return x
#| //if hx < 0x00800000 {
#| // force_eval(x * x);
#| //}
#| return x
#| } else {
#| k = 0
#| }
#| // x is now in primary range
#| let hfx = (0.5 : Float) * x
#| let hxs = x * hfx
#| let r1 = (1.0 : Float) + hxs * (q1 + hxs * q2)
#| let t = (3.0 : Float) - r1 * hfx
#| let mut e = hxs * ((r1 - t) / ((6.0 : Float) - x * t))
#| if k == 0 {
#| // c is 0
#| return x - (x * e - hxs)
#| }
#| e = x * (e - c) - c
#| e -= hxs
#| // exp(x) ~ 2^k (x_reduced - e + 1)
#| if k == -1 {
#| return (0.5 : Float) * (x - e) - 0.5
#| }
#| if k == 1 {
#| if x < -0.25 {
#| return -(2.0 : Float) * (e - (x + 0.5))
#| }
#| return (1.0 : Float) + (2.0 : Float) * (x - e)
#| }
#| let twopk = ((0x7f + k) << 23).reinterpret_as_float() // 2^k
#| if !(k is (0..=56)) {
#| // suffice to return exp(x)-1
#| let mut y = x - e + 1.0
#| if k == 128 {
#| y = y * 2.0 * (0x1.0p127 : Float)
#| } else {
#| y = y * twopk
#| }
#| return y - 1.0
#| }
#| let uf = ((0x7f - k) << 23).reinterpret_as_float() // 2^-k
#| if k < 23 {
#| (x - e + ((1.0 : Float) - uf)) * twopk
#| } else {
#| (x - (e + uf) + 1.0) * twopk
#| } }
),
),
"sinh": build(
(
#|pub fn Float::sinh(self : Float) -> Float { let x = self
#| let mut h : Float = 0.5
#| let mut ix = x.reinterpret_as_uint()
#| if ix >> 31 != 0 {
#| h = -h
#| }
#| // |x|
#| ix = ix & 0x7fffffff
#| let absx = ix.reinterpret_as_float()
#| let w = ix
#| // |self| < log(FLT_MAX)
#| if w < 0x42b17217 {
#| let t = absx.expm1()
#| if w < 0x3f800000 {
#| if w < 0x3f800000U - (12U << 23) {
#| return x
#| }
#| return h * ((2.0 : Float) * t - t * t / (t + 1.0))
#| }
#| return h * (t + t / (t + 1.0))
#| }
#| // |self| > logf(FLT_MAX) or nan
#| h * k_expo2f(absx) * 2.0 }
),
),
"cosh": build(
(
#|pub fn Float::cosh(self : Float) -> Float { let mut x = self
#| let mut ix = x.reinterpret_as_uint()
#| ix = ix & 0x7fffffff
#| x = ix.reinterpret_as_float()
#| let w = ix
#| // |x| < log(2)
#| if w < 0x3f317217 {
#| if w < 0x3f800000U - (12U << 23) {
#| return 1.0
#| }
#| let t = x.expm1()
#| return (1.0 : Float) + t * t / ((2.0 : Float) * (t + 1.0))
#| }
#| // |x| < log(FLT_MAX)
#| if w < 0x42b17217 {
#| let t = x.exp()
#| return (t + (1.0 : Float) / t) * 0.5
#| }
#| // |x| > log(FLT_MAX) or nan
#| k_expo2f(x) }
),
),
"tanh": build(
(
#|pub fn Float::tanh(self : Float) -> Float { let x = self
#| let mut ix = x.reinterpret_as_uint()
#| let sign = ix >> 31 != 0
#| ix = ix & 0x7fffffff
#| let x = ix.reinterpret_as_float()
#| let w = ix
#| let tt = if w > 0x3f0c9f54 {
#| // |x| > log(3)/2 ~= 0.5493 or nan
#| if w > 0x41200000 {
#| // |x| > 10
#| (1.0 : Float) + (0.0 : Float) / x
#| } else {
#| let t = (x * 2.0).expm1()
#| (1.0 : Float) - (2.0 : Float) / (t + 2.0)
#| }
#| } else if w > 0x3e82c578 {
#| // |x| > log(5/3)/2 ~= 0.2554
#| let t = (x * 2.0).expm1()
#| t / (t + 2.0)
#| } else if w >= 0x00800000 {
#| // |x| >= 0x1p-126
#| let t = (x * -2.0).expm1()
#| -t / (t + 2.0)
#| } else {
#| // |x| is subnormal
#| x
#| }
#| if sign {
#| -tt
#| } else {
#| tt
#| } }
),
),
"asinh": build(
(
#|pub fn Float::asinh(self : Float) -> Float { let x = self
#| let u = x.reinterpret_as_uint()
#| let i = u & 0x7fffffff
#| let sign = u >> 31 != 0
#| let ln2 : Float = 0.693147180559945309417232121458176568
#| let x = i.reinterpret_as_float()
#| let x = if i >= 0x3f800000U + (12U << 23) {
#| // |x| >= 0x1p12 or inf or nan
#| x.ln() + ln2
#| } else if i >= 0x3f800000U + (1U << 23) {
#| // |x| >= 2
#| (x * 2.0 + (1.0 : Float) / ((x * x + 1.0).sqrt() + x)).ln()
#| } else if i >= 0x3f800000U - (12U << 23) {
#| // |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5]
#| (x + x * x / ((x * x + 1.0).sqrt() + 1.0)).ln_1p()
#| } else {
#| // |x| < 0x1p-12, raise inexact if x!=0
#| // x + 0x1.0p120
#| x
#| }
#| if sign {
#| -x
#| } else {
#| x
#| } }
),
),
"acosh": build(
(
#|pub fn Float::acosh(self : Float) -> Float { let x = self
#| let ln2 : Float = 693147180559945309417232121458176568
#| let u = x.reinterpret_as_uint()
#| let a = u & 0x7fffffffU
#| if a < 0x3f800000U + (1U << 23) {
#| // |x| < 2, invalid if x < 1 or nan
#| // up to 2ulp error in [1,1.125]
#| return (x - 1.0 + ((x - 1.0) * (x - 1.0) + (2.0 : Float) * (x - 1.0)).sqrt()).ln_1p()
#| }
#| if a < 0x3f800000U + (12U << 23) {
#| // |x| < 0x1p12
#| return (x * 2.0 - (1.0 : Float) / (x + (x * x - 1.0).sqrt())).ln()
#| }
#| // x >= 0x1p12
#| return x.ln() + ln2 }
),
),
"atanh": build(
(
#|pub fn Float::atanh(self : Float) -> Float { let x = self
#| let u = x.reinterpret_as_uint()
#| let sign = u >> 31 != 0
#| let u = u & 0x7fffffff
#| let x = u.reinterpret_as_float()
#| let x = if u < 0x3f800000U - (1U << 23) {
#| if u < 0x3f800000U - (32U << 23) {
#| x
#| } else {
#| // |x| < 0.5, up to 1.7ulp error
#| (x * 2.0 + x * 2.0 * x / ((1.0 : Float) - x)).ln_1p() * 0.5
#| }
#| } else {
#| // avoid overflow
#| (x / ((1.0 : Float) - x) * 2.0).ln_1p() * 0.5
#| }
#| if sign {
#| -x
#| } else {
#| x
#| } }
),
),
"ln": build(
(
#|pub fn Float::ln(self : Float) -> Float { let mut ix : UInt = self.reinterpret_as_uint()
#| if ix == 0x3f800000U {
#| return 0.0
#| }
#| if ix - 0x00800000U >= 0x7f800000U - 0x00800000U {
#| if ix * 2 == 0 {
#| return neg_infinity
#| }
#| if ix == 0x7f800000U {
#| return self
#| }
#| if (ix & 0x80000000U) != 0 || ix * 2 >= 0xff000000U {
#| return not_a_number
#| }
#| ix = (self * 0x1.0p23).reinterpret_as_uint()
#| ix -= (23 << 23).reinterpret_as_uint()
#| }
#| let tmp = ix - logf_off
#| let i = ((tmp >> (23 - logf_table_bits)) % logf_n).reinterpret_as_int()
#| let k = tmp.reinterpret_as_int() >> 23
#| let iz = ix - (tmp & 0xff800000U)
#| let invc = logf_data.invc[i]
#| let logc = logf_data.logc[i]
#| let z = iz.reinterpret_as_float().to_double()
#| let r = z * invc - 1
#| let y0 = logc + k.to_double() * logf_data.ln2
#| let r2 = r * r
#| let y = logf_data.poly[1] * r + logf_data.poly[2]
#| let y = logf_data.poly[0] * r2 + y
#| let y = y * r2 + (y0 + r)
#| y.to_float() }
),
),
"ln_1p": build(
(
#|pub fn Float::ln_1p(self : Float) -> Float { let lg1_f : Float = 0.66666662693
#| let lg2_f : Float = 0.40000972152
#| let lg3_f : Float = 0.28498786688
#| let lg4_f : Float = 0.24279078841
#| let float_ln2_hi : Float = 6.9314575195e-01 // 0x3f317200
#| let float_ln2_lo : Float = 1.4286067653e-06 // 0x35bfbe8e
#| let mut ui : UInt = self.reinterpret_as_uint()
#| let mut f : Float = 0
#| let mut c : Float = 0
#| let mut iu : UInt = 0
#| let one : Float = 1.0
#| let mut k = 1
#| if ui < 0x3ed413d0 || ui >> 31 > 0 {
#| if ui >= 0xbf800000 {
#| if self == -1.0 {
#| return self / 0.0
#| }
#| return (self - self) / 0.0
#| }
#| if ui << 1 < 0x33800000U << 1 {
#| return self
#| }
#| if ui <= 0xbe95f619 {
#| k = 0
#| c = 0.0
#| f = self
#| }
#| } else if ui >= 0x7f800000 {
#| return self
#| }
#| if k > 0 {
#| ui = (one + self).reinterpret_as_uint()
#| iu = ui
#| iu += 0x3f800000U - 0x3f3504f3U
#| k = (iu >> 23).reinterpret_as_int() - 0x7f
#| if k < 25 {
#| let fui = ui.reinterpret_as_float()
#| c = if k >= 2 { one - (fui - self) } else { self - (fui - 1.0) }
#| c /= ui.reinterpret_as_float()
#| } else {
#| c = 0.0
#| }
#| iu = (iu & 0x007fffff) + 0x3f3504f3
#| ui = iu
#| f = ui.reinterpret_as_float() - 1.0
#| }
#| let s = f / (f + 2.0)
#| let z = s * s
#| let w = z * z
#| let t1 = w * (lg2_f + w * lg4_f)
#| let t2 = z * (lg1_f + w * lg3_f)
#| let r = t2 + t1
#| let hfsq = f * f * 0.5
#| let dk = k.to_float()
#| s * (hfsq + r) + (dk * float_ln2_lo + c) - hfsq + f + dk * float_ln2_hi }
),
),
"sin": build(
(
#|pub fn Float::sin(self : Float) -> Float { let x = self
#| if x.is_nan() || x.is_inf() {
#| return not_a_number
#| }
#| if x == 0.0 {
#| return x
#| }
#| let (x, q) = trig_reduce(x, SIN_SWITCHOVER)
#| sin_cos_core(x, q) }
),
),
"cos": build(
(
#|pub fn Float::cos(self : Float) -> Float { let x = self
#| if x.is_nan() || x.is_inf() {
#| return not_a_number
#| }
#| if x == 0.0 {
#| return 1.0
#| }
#| let (x, q) = trig_reduce(x, COS_SWITCHOVER)
#| sin_cos_core(x, q + 1) }
),
),
"tan": build(
(
#|pub fn Float::tan(self : Float) -> Float { let x = self
#| if x.is_nan() || x.is_inf() {
#| return not_a_number
#| }
#| if x == 0.0 {
#| return x
#| }
#| let (x, q) = trig_reduce(x, COS_SWITCHOVER)
#| tanf_poly(x, (q & 1) != 0) }
),
),
"asin": build(
(
#|pub fn Float::asin(self : Float) -> Float { let x = self
#| let x1p120 = 0x3870000000000000UL.reinterpret_as_double()
#| let pio2 : Double = 1.570796326794896558e+00
#| // coefficients for R(x^2)
#| let ps0 : Float = 1.6666586697e-01
#| let ps1 : Float = -4.2743422091e-02
#| let ps2 : Float = -8.6563630030e-03
#| let qs2 : Float = -7.0662963390e-01
#| fn r(z : Float) -> Float {
#| let p = z * (ps0 + z * (ps1 + z * ps2))
#| let q = z * qs2 + 1.0
#| p / q
#| }
#| let hx = x.reinterpret_as_uint()
#| let ix = hx & 0x7fffffff
#| if ix >= 0x3f800000 {
#| if ix == 0x3f800000 {
#| return (x.to_double() * pio2 + x1p120).to_float()
#| }
#| return not_a_number // asin(|x|>1) is NaN
#| }
#| if ix < 0x3f000000 {
#| if ix is (0x00800000..=0x39800000) {
#| return x
#| }
#| return x + x * r(x * x)
#| }
#| let z = ((1.0 : Float) - x.abs()) * 0.5
#| let s = z.to_double().sqrt()
#| let x = (pio2 - 2.0 * (s + s * r(z).to_double())).to_float()
#| if hx >> 31 != 0 {
#| -x
#| } else {
#| x
#| } }
),
),
"acos": build(
(
#|pub fn Float::acos(self : Float) -> Float { let x = self
#| let pio2_hi : Float = 1.5707962513
#| let pio2_lo : Float = 7.5497894159e-08
#| let ps0 : Float = 1.6666586697e-01
#| let ps1 : Float = -4.2743422091e-02
#| let ps2 : Float = -8.6563630030e-03
#| let qs1 : Float = -7.0662963390e-01
#| let one : Float = 1.0
#| let two : Float = 2.0
#| fn r(z : Float) -> Float {
#| let p = z * (ps0 + z * (ps1 + z * ps2))
#| let q = z * qs1 + 1.0
#| p / q
#| }
#| let hx = x.reinterpret_as_int()
#| let ix = hx & 0x7fffffff
#| if ix >= 0x3f800000 {
#| if ix == 0x3f800000 {
#| if hx >> 31 != 0 {
#| return two * pio2_hi + 0x1.0p-120
#| }
#| return 0.0
#| }
#| return not_a_number
#| }
#| if ix < 0x3f000000 {
#| if ix <= 0x32800000 {
#| return pio2_hi + 0x1.0p-120
#| }
#| return pio2_hi - (x - (pio2_lo - x * r(x * x)))
#| }
#| if hx >> 31 != 0 {
#| let z = (x + 1.0) * 0.5
#| let s = z.sqrt()
#| let w = r(z) * s - pio2_lo
#| return two * (pio2_hi - (s + w))
#| }
#| let z = (one - x) * 0.5
#| let s = z.sqrt()
#| let df = s
#| let c = (z - df * df) / (s + df)
#| let w = r(z) * s + c
#| two * (df + w) }
),
),
"atan": build(
(
#|pub fn Float::atan(self : Float) -> Float { let x = self
#| let atanhi : Array[Float] = [
#| 4.6364760399e-01, 7.8539812565e-01, 9.8279368877e-01, 1.5707962513e+00,
#| ]
#| let atanlo : Array[Float] = [
#| 5.0121582440e-09, 3.7748947079e-08, 3.4473217170e-08, 7.5497894159e-08,
#| ]
#| let a_t : Array[Float] = [
#| 3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02,
#| ]
#| let ix = x.reinterpret_as_int()
#| let sign = ix >> 31
#| let ix = ix & 0x7fffffff
#| let mut id = 0
#| let mut x = x
#| let one : Float = 1.0
#| let two : Float = 2.0
#| if ix >= 0x4c800000 {
#| if x.is_nan() {
#| return x
#| }
#| let z = atanhi[3] + 0x1.0p-120
#| let z = if sign != 0 { -z } else { z }
#| return z
#| }
#| if ix < 0x3ee00000 {
#| if ix < 0x39800000 {
#| return x
#| }
#| id = -1
#| } else {
#| x = x.abs()
#| if ix < 0x3f980000 {
#| if ix < 0x3f300000 {
#| id = 0
#| x = (two * x - one) / (two + x)
#| } else {
#| id = 1
#| x = (x - one) / (x + one)
#| }
#| } else if ix < 0x401c0000 {
#| id = 2
#| x = (x - 1.5) / (one + x * 1.5)
#| } else {
#| id = 3
#| x = -one / x
#| }
#| }
#| let z = x * x
#| let w = z * z
#| let s1 = z * (a_t[0] + w * (a_t[2] + w * a_t[4]))
#| let s2 = w * (a_t[1] + w * a_t[3])
#| if id < 0 {
#| return x - x * (s1 + s2)
#| }
#| let z = atanhi[id] - (x * (s1 + s2) - atanlo[id] - x)
#| if sign != 0 {
#| -z
#| } else {
#| z
#| } }
),
),
"atan2": build(
(
#|pub fn Float::atan2(self : Float, other : Float) -> Float { let (y, x) = (self, other)
#| if x.is_nan() || y.is_nan() {
#| return not_a_number
#| }
#| let pi : Float = 3.1415927410e+00
#| let pi_lo : Float = -8.7422776573e-08
#| let zero : Float = 0.0
#| let ix = x.reinterpret_as_uint()
#| let iy = y.reinterpret_as_uint()
#| if ix == 0x3f800000 {
#| return y.atan()
#| }
#| let m = ((iy >> 31) & 1) | ((ix >> 30) & 2)
#| let ix = ix & 0x7fffffff
#| let iy = iy & 0x7fffffff
#| if iy == 0 {
#| match m {
#| 0 | 1 => return y
#| 2 => return pi
#| _ => return -pi
#| }
#| }
#| if ix == 0 {
#| let res = if (m & 1) != 0 { -pi / 2 } else { pi / 2 }
#| return res
#| }
#| if ix == 0x7f800000 {
#| if iy == 0x7f800000 {
#| match m {
#| 0 => return pi / 4
#| 1 => return -pi / 4
#| 2 => return pi * 3.0 / 4
#| _ => return -pi * 3.0 / 4
#| }
#| } else {
#| match m {
#| 0 => return 0.0
#| 1 => return -0.0
#| 2 => return pi
#| _ => return -pi
#| }
#| }
#| }
#| if ix + (26U << 23) < iy || iy == 0x7f800000 {
#| let res = if (m & 1) != 0 { -pi / 2 } else { pi / 2 }
#| return res
#| }
#| let z = if (m & 2) != 0 && iy + (26U << 23) < ix {
#| zero
#| } else {
#| (y / x).atan()
#| }
#| match m {
#| 0 => z
#| 1 => -z
#| 2 => pi - (z - pi_lo)
#| _ => z - pi_lo - pi
#| } }
),
),
"logf_off": (None, UInt(0x3f330000U)),
"logf_table_bits": (None, Int(4)),
"k_expo2f": build(
(
#|fn k_expo2f(x : Float) -> Float { let k = 235
#| let k_ln2 = (0x4322e3bc).reinterpret_as_float()
#| // note that k is odd and scale*scale overflows */
#| let scale = ((0x7f + k / 2) << 23).reinterpret_as_float()
#| // exp(x - k ln2) * 2**(k-1) */
#| (x - k_ln2).exp() * scale * scale }
),
),
"round": build(
(
#|pub fn Float::round(self : Float) -> Float { floor(self + 0.5) }
),
),
"mulh": build(
(
#|fn mulh(a : UInt, b : UInt) -> UInt { let a = a.to_uint64()
#| let b = b.to_uint64()
#| let res = a * b
#| (res >> 32).to_uint() }
),
),
"mul": build(
(
#|fn mul(a : UInt, b : UInt) -> (UInt, UInt) { let a = a.to_uint64()
#| let b = b.to_uint64()
#| let res = a * b
#| ((res >> 32).to_uint(), res.to_uint()) }
),
),
"trig_reduce": build(
(
#|fn trig_reduce(x : Float, switch_over : Float) -> (Float, Int) { if x.abs() <= switch_over {
#| let mut j : Float = 0.0
#| let mut r : Float = 0.0
#| j = x * (0x3f22f983).reinterpret_as_float() +
#| (0x4b40_0000).reinterpret_as_float()
#| j = (j.reinterpret_as_int() - 0x4b40_0000).to_float()
#| r = x - j * (0x3fc90f80).reinterpret_as_float()
#| r = r - j * (0x37354440).reinterpret_as_float()
#| r = r - j * (0x2c34611a).reinterpret_as_float()
#| return (r, j.to_int())
#| }
#| let xispos = x > 0.0
#| let mut exp : Int = ((x.reinterpret_as_int() >> 23) & 0xff) - 126
#| let ix = ((x.reinterpret_as_uint() & 0x007fffff) << 8) | 0x80000000
#| let ind = exp >> 5
#| exp = exp & 0x1f
#| let two_over_pi : Array[UInt] = [
#| 0x00000000, 0x28be60db, 0x9391054a, 0x7f09d5f4, 0x7d4d3770, 0x36d8a566, 0x4f10e410,
#| 0000000000,
#| ]
#| let mut hi = two_over_pi[ind]
#| let mut mi = two_over_pi[ind + 1]
#| let mut lo = two_over_pi[ind + 2]
#| let tp = two_over_pi[ind + 3]
#| if exp > 0 {
#| hi = (hi << exp) | (mi >> (32 - exp))
#| mi = (mi << exp) | (lo >> (32 - exp))
#| lo = (lo << exp) | (tp >> (32 - exp))
#| }
#| let phi = 0U
#| let (h, l) = mul(ix, lo)
#| let plo = phi + l
#| let phi = h + (if plo < l { 1 } else { 0 })
#| let (h, l) = mul(ix, mi)
#| let mut plo = phi + l
#| let phi = h + (if plo < l { 1 } else { 0 })
#| let l = ix * hi
#| let mut phi = phi + l
#| let mut q : Int = (phi >> 30).reinterpret_as_int()
#| phi = phi & 0x3fffffff
#| if (phi & 0x2000_0000) != 0 {
#| phi = phi - 0x4000_0000
#| q = q + 1
#| }
#| let s : UInt = phi & 0x8000_0000
#| if phi >= 0x8000_0000 {
#| phi = phi.lnot()
#| plo = 0U - plo
#| //phi += (plo == 0).to_uint()
#| phi += if plo == 0 { 1 } else { 0 }
#| }
#| exp = 0
#| while phi < 0x8000_0000 {
#| phi = (phi << 1) | (plo >> 31)
#| plo = plo << 1
#| exp = exp - 1
#| }
#| phi = mulh(phi, 0xc90f_daa2)
#| if phi < 0x8000_0000 {
#| phi = phi << 1
#| exp = exp - 1
#| }
#| let mut r = s +
#| ((exp + 128) << 23).reinterpret_as_uint() +
#| (phi >> 8) +
#| (if (phi & 0xff) > 0x7e { 1 } else { 0 })
#| if !xispos {
#| r = r ^ 0x8000_0000
#| q = -q
#| }
#| let r = r.reinterpret_as_float()
#| return (r, q) }
),
),
"sinf_poly": build(
(
#|fn sinf_poly(x : Float) -> Float { let s = x * x
#| let mut r = (0x3640_5000).reinterpret_as_float()
#| r = r * s - (0x3950_3486).reinterpret_as_float()
#| r = r * s + (0x3c08_88c1).reinterpret_as_float()
#| r = r * s - (0x3e2a_aaab).reinterpret_as_float()
#| let t = x * s
#| r = r * t + x
#| r }
),
),
"cosf_poly": build(
(
#|fn cosf_poly(x : Float) -> Float { let s = x * x
#| let mut r = (0x37cd_4000).reinterpret_as_float()
#| r = r * s - (0x3ab6_077d).reinterpret_as_float()
#| r = r * s + (0x3d2a_aaa8).reinterpret_as_float()
#| r = r * s - (0x3f00_0000).reinterpret_as_float()
#| r = r * s + (0x3f80_0000).reinterpret_as_float()
#| r }
),
),
"sin_cos_core": build(
(
#|fn sin_cos_core(x : Float, q : Int) -> Float { let mut r = if (q & 1) != 0 { cosf_poly(x) } else { sinf_poly(x) }
#| if (q & 2) != 0 {
#| r = -r
#| }
#| r }
),
),
"tanf_poly": build(
(
#|fn tanf_poly(x : Float, odd : Bool) -> Float { let x = x.to_double()
#| let coef : FixedArray[Double] = [
#| 0.333331395030791399758, // 0x15554d3418c99f.0p-54 */
#| 0.133392002712976742718, // 0x1112fd38999f72.0p-55 */
#| 0.0533812378445670393523, // 0x1b54c91d865afe.0p-57 */
#| 0.0245283181166547278873, // 0x191df3908c33ce.0p-58 */
#| 0.00297435743359967304927, // 0x185dadfcecf44e.0p-61 */
#| 0.00946564784943673166728, // 0x1362b9bf971bcd.0p-59 */
#| ]
#| let z = x * x
#| let mut r = coef[4] + z * coef[5]
#| let t = coef[2] + z * coef[3]
#| let w = z * z
#| let s = z * x
#| let u = coef[0] + z * coef[1]
#| r = x + s * u + s * w * (t + w * r)
#| (if odd { -1.0 / r } else { r }).to_float() }
),
),
"top12": build(
(
#|fn top12(x : Float) -> UInt { x.reinterpret_as_uint() >> 20 }
),
),
"__math_xflowf": build(
(
#|fn __math_xflowf(sign : UInt, y : Float) -> Float { return (if sign != 0 { -y } else { y }) * y }
),
),
"__math_oflowf": build(
(
#|fn __math_oflowf(sign : UInt) -> Float { return __math_xflowf(sign, 0x1.0p97) }
),
),
"__math_uflowf": build(
(
#|fn __math_uflowf(sign : UInt) -> Float { return __math_xflowf(sign, 0x1.0p-95) }
),
),
"exp2f_table_bits": (None, Int(5)),
"pow": build(
(
#|pub fn Float::pow(self : Float, other : Float) -> Float { self.to_double().pow(other.to_double()).to_float() }
),
),
"to_int": build(
(
#|pub fn to_int(self : Float) -> Int { if self != self {
#| 0
#| } else if self >= 2147483647 {
#| 2147483647
#| } else if self <= -2147483648 {
#| -2147483648
#| } else {
#| self.to_unchecked_int()
#| } }
),
),
}
},
)
///|
let moonbitlang_core_hashmap_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/hashmap",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/test": moonbitlang_core_test_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/tuple": moonbitlang_core_tuple_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/int": moonbitlang_core_int_module,
},
fn(_env, build) {
{
"op_get": build(
(
#|pub fn[K : Hash + Eq, V] op_get(self : T[K, V], key : K) -> V? { self.get(key) }
),
),
"debug_entries": build(
(
#|fn[K : Show, V : Show] debug_entries(self : T[K, V]) -> String { for s = \"\", i = 0; i < self.entries.length(); {
#| let s = if i > 0 { s + \",\" } else { s }
#| match self.entries[i] {
#| None => continue s + \"_\", i + 1
#| Some({ psl, key, value, .. }) =>
#| continue s + \"(\\{psl},\\{key},\\{value})\", i + 1
#| }
#| } else {
#| s
#| } }
),
),
"clear": build(
(
#|pub fn[K, V] clear(self : T[K, V]) -> Unit { self.entries.fill(None)
#| self.size = 0 }
),
),
"iter": build(
(
#|pub fn[K, V] iter(self : T[K, V]) -> Iter[(K, V)] { Iter::new(yield_ => for entry in self.entries {
#| if entry is Some({ key, value, .. }) {
#| guard yield_((key, value)) is IterContinue else { break IterEnd }
#| }
#| } else {
#| IterContinue
#| }) }
),
),
"iter2": build(
(
#|pub fn[K, V] iter2(self : T[K, V]) -> Iter2[K, V] { Iter2::new(yield_ => for entry in self.entries {
#| if entry is Some({ key, value, .. }) {
#| guard yield_(key, value) is IterContinue else { break IterEnd }
#| }
#| } else {
#| IterContinue
#| }) }
),
),
"from_iter": build(
(
#|pub fn[K : Hash + Eq, V] from_iter(iter : Iter[(K, V)]) -> T[K, V] { let m = new()
#| iter.each(e => m[e.0] = e.1)
#| m }
),
),
"to_array": build(
(
#|pub fn[K, V] to_array(self : T[K, V]) -> Array[(K, V)] { let mut i = 0
#| let res = while i < self.capacity {
#| if self.entries[i] is Some({ key, value, .. }) {
#| i += 1
#| break Array::make(self.size, (key, value))
#| }
#| i += 1
#| } else {
#| []
#| }
#| if !res.is_empty() {
#| let mut res_idx = 1
#| while res_idx < res.length() && i < self.capacity {
#| if self.entries[i] is Some({ key, value, .. }) {
#| res[res_idx] = (key, value)
#| res_idx += 1
#| }
#| i += 1
#| }
#| }
#| res }
),
),
"size": build(
(
#|pub fn[K, V] size(self : T[K, V]) -> Int { self.size }
),
),
"capacity": build(
(
#|pub fn[K, V] capacity(self : T[K, V]) -> Int { self.capacity }
),
),
"is_empty": build(
(
#|pub fn[K, V] is_empty(self : T[K, V]) -> Bool { self.size == 0 }
),
),
"each": build(
(
#|pub fn[K, V] each(self : T[K, V], f : (K, V) -> Unit) -> Unit { for i in 0.. Unit) -> Unit { for i = 0, idx = 0; i < self.capacity; {
#| match self.entries[i] {
#| Some({ key, value, .. }) => {
#| f(idx, key, value)
#| continue i + 1, idx + 1
#| }
#| None => continue i + 1, idx
#| }
#| } }
),
),
"new": build(
(
#|pub fn[K, V] new(capacity~ : Int = 8) -> T[K, V] { let capacity = capacity.next_power_of_two()
#| {
#| size: 0,
#| capacity,
#| entries: FixedArray::make(capacity, None),
#| capacity_mask: capacity - 1,
#| } }
),
),
"from_array": build(
(
#|pub fn[K : Hash + Eq, V] from_array(arr : Array[(K, V)]) -> T[K, V] { let m = new(capacity=arr.length())
#| arr.each(e => m.set(e.0, e.1))
#| m }
),
),
"set": build(
(
#|pub fn[K : Hash + Eq, V] set(self : T[K, V], key : K, value : V) -> Unit { self.set_with_hash(key, value, key.hash()) }
),
),
"op_set": build(
(
#|pub fn[K : Hash + Eq, V] op_set(self : T[K, V], key : K, value : V) -> Unit { self.set(key, value) }
),
),
"get": build(
(
#|pub fn[K : Hash + Eq, V] get(self : T[K, V], key : K) -> V? { // self.get_with_hash(key, key.hash())
#| let hash = key.hash()
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries[idx] is Some(entry) else { break None }
#| if entry.hash == hash && entry.key == key {
#| break Some(entry.value)
#| }
#| if i > entry.psl {
#| break None
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| } }
),
),
"get_with_hash": build(
(
#|fn[K : Eq, V] get_with_hash(self : T[K, V], key : K, hash : Int) -> V? { for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries[idx] is Some(entry) else { break None }
#| if entry.hash == hash && entry.key == key {
#| break Some(entry.value)
#| }
#| if i > entry.psl {
#| break None
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| } }
),
),
"contains": build(
(
#|pub fn[K : Hash + Eq, V] contains(self : T[K, V], key : K) -> Bool { let hash = key.hash()
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries[idx] is Some(entry) else { return false }
#| if entry.hash == hash && entry.key == key {
#| return true
#| }
#| if i > entry.psl {
#| return false
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| } }
),
),
"remove": build(
(
#|pub fn[K : Hash + Eq, V] remove(self : T[K, V], key : K) -> Unit { let hash = key.hash()
#| for i = 0, idx = hash & self.capacity_mask {
#| match self.entries[idx] {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| self.entries[idx] = None
#| self.shift_back(idx)
#| self.size -= 1
#| break
#| }
#| if i > entry.psl {
#| break
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#| None => break
#| }
#| } }
),
),
"shift_back": build(
(
#|fn[K, V] shift_back(self : T[K, V], start_index : Int) -> Unit { for prev = start_index, curr = (start_index + 1) & self.capacity_mask {
#| match self.entries[curr] {
#| Some({ psl, hash, key, value }) => {
#| if psl == 0 {
#| break
#| }
#| self.entries[prev] = Some({ psl: psl - 1, hash, key, value })
#| self.entries[curr] = None
#| continue curr, (curr + 1) & self.capacity_mask
#| }
#| None => break
#| }
#| } }
),
),
"grow": build(
(
#|fn[K : Eq, V] grow(self : T[K, V]) -> Unit { let old_entries = self.entries
#| let new_capacity = self.capacity << 1
#| self.entries = FixedArray::make(new_capacity, None)
#| self.capacity = new_capacity
#| self.capacity_mask = new_capacity - 1
#| self.size = 0
#| for i in 0.. T[K, V] { let m = new(capacity=arr.length())
#| arr.each(e => m.set(e.0, e.1))
#| m }
),
),
}
},
)
///|
let moonbitlang_core_hashset_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/hashset",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/test": moonbitlang_core_test_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
},
fn(_env, build) {
{
"default_init_capacity": (None, Int(8)),
"new": build(
(
#|pub fn[K] new(capacity~ : Int = default_init_capacity) -> T[K] { {
#| size: 0,
#| capacity,
#| grow_at: calc_grow_threshold(capacity),
#| entries: FixedArray::make(capacity, None),
#| } }
),
),
"from_array": build(
(
#|pub fn[K : Hash + Eq] from_array(arr : Array[K]) -> T[K] { let m = new()
#| arr.each(e => m.add(e))
#| m }
),
),
"of": build(
(
#|pub fn[K : Hash + Eq] of(arr : FixedArray[K]) -> T[K] { let m = new()
#| arr.each(e => m.add(e))
#| m }
),
),
"add": build(
(
#|pub fn[K : Hash + Eq] add(self : T[K], key : K) -> Unit { if self.capacity == 0 || self.size >= self.grow_at {
#| self.grow()
#| }
#| let hash = key.hash()
#| let entry = { psl: 0, hash, key }
#| loop (0, self.index(hash), entry) {
#| (i, idx, entry) => {
#| if i == self.capacity {
#| panic()
#| }
#| match self.entries[idx] {
#| None => {
#| self.entries[idx] = Some(entry)
#| self.size += 1
#| break
#| }
#| Some(curr_entry) => {
#| if curr_entry.hash == entry.hash && curr_entry.key == entry.key {
#| self.entries[idx] = Some(entry)
#| break
#| }
#| if entry.psl > curr_entry.psl {
#| self.entries[idx] = Some(entry)
#| curr_entry.psl += 1
#| continue (i + 1, self.next_index(idx), curr_entry)
#| }
#| entry.psl += 1
#| continue (i + 1, self.next_index(idx), entry)
#| }
#| }
#| }
#| } }
),
),
"contains": build(
(
#|pub fn[K : Hash + Eq] contains(self : T[K], key : K) -> Bool { let hash = key.hash()
#| for i = 0, idx = self.index(hash)
#| i < self.capacity
#| i = i + 1, idx = self.next_index(idx) {
#| match self.entries[idx] {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| return true
#| }
#| if i > entry.psl {
#| return false
#| }
#| }
#| None => return false
#| }
#| }
#| false }
),
),
"remove": build(
(
#|pub fn[K : Hash + Eq] remove(self : T[K], key : K) -> Unit { let hash = key.hash()
#| for i = 0, idx = self.index(hash)
#| i < self.capacity
#| i = i + 1, idx = self.next_index(idx) {
#| if self.entries[idx] is Some(entry) &&
#| entry.hash == hash &&
#| entry.key == key {
#| self.entries[idx] = None
#| self.shift_back(idx)
#| self.size -= 1
#| break
#| }
#| } }
),
),
"size": build(
(
#|pub fn[K] size(self : T[K]) -> Int { self.size }
),
),
"capacity": build(
(
#|pub fn[K] capacity(self : T[K]) -> Int { self.capacity }
),
),
"is_empty": build(
(
#|pub fn[K] is_empty(self : T[K]) -> Bool { self.size == 0 }
),
),
"each": build(
(
#|pub fn[K] each(self : T[K], f : (K) -> Unit) -> Unit { self.eachi((_i, k) => f(k)) }
),
),
"eachi": build(
(
#|pub fn[K] eachi(self : T[K], f : (Int, K) -> Unit) -> Unit { let mut idx = 0
#| for i in 0.. Unit { for i in 0.. T[K] { let m = new()
#| self.each(k => m.add(k))
#| other.each(k => m.add(k))
#| m }
),
),
"intersection": build(
(
#|pub fn[K : Hash + Eq] intersection(self : T[K], other : T[K]) -> T[K] { let m = new()
#| self.each(k => if other.contains(k) { m.add(k) })
#| m }
),
),
"difference": build(
(
#|pub fn[K : Hash + Eq] difference(self : T[K], other : T[K]) -> T[K] { let m = new()
#| self.each(k => if !other.contains(k) { m.add(k) })
#| m }
),
),
"symmetric_difference": build(
(
#|pub fn[K : Hash + Eq] symmetric_difference(self : T[K], other : T[K]) -> T[K] { let m = new()
#| self.each(k => if !other.contains(k) { m.add(k) })
#| other.each(k => if !self.contains(k) { m.add(k) })
#| m }
),
),
"is_disjoint": build(
(
#|pub fn[K : Hash + Eq] is_disjoint(self : T[K], other : T[K]) -> Bool { if self.size() <= other.size() {
#| self.iter().all(k => !other.contains(k))
#| } else {
#| other.iter().all(k => !self.contains(k))
#| } }
),
),
"is_subset": build(
(
#|pub fn[K : Hash + Eq] is_subset(self : T[K], other : T[K]) -> Bool { if self.size() <= other.size() {
#| self.iter().all(k => other.contains(k))
#| } else {
#| false
#| } }
),
),
"is_superset": build(
(
#|pub fn[K : Hash + Eq] is_superset(self : T[K], other : T[K]) -> Bool { other.is_subset(self) }
),
),
"iter": build(
(
#|pub fn[K] iter(self : T[K]) -> Iter[K] { Iter::new(yield_ => for entry in self.entries {
#| if entry is Some({ key, .. }) {
#| guard yield_(key) is IterContinue else { break IterEnd }
#| }
#| } else {
#| IterContinue
#| }) }
),
),
"from_iter": build(
(
#|pub fn[K : Hash + Eq] from_iter(iter : Iter[K]) -> T[K] { let s = new()
#| iter.each(e => s.add(e))
#| s }
),
),
"shift_back": build(
(
#|fn[K] shift_back(self : T[K], start_index : Int) -> Unit { for i = 0, prev = start_index, curr = self.next_index(start_index)
#| i < self.entries.length()
#| i = i + 1, prev = curr, curr = self.next_index(curr) {
#| match self.entries[curr] {
#| Some(entry) => {
#| if entry.psl == 0 {
#| break
#| }
#| entry.psl -= 1
#| self.entries[prev] = Some(entry)
#| self.entries[curr] = None
#| }
#| None => break
#| }
#| } }
),
),
"grow": build(
(
#|fn[K : Hash + Eq] grow(self : T[K]) -> Unit { // handle zero capacity
#| if self.capacity == 0 {
#| self.capacity = default_init_capacity
#| self.grow_at = calc_grow_threshold(self.capacity)
#| self.size = 0
#| self.entries = FixedArray::make(self.capacity, None)
#| return
#| }
#| let old_entries = self.entries
#| self.entries = FixedArray::make(self.capacity * 2, None)
#| self.capacity = self.capacity * 2
#| self.grow_at = calc_grow_threshold(self.capacity)
#| self.size = 0
#| for i in 0.. Int { abs(hash) & (self.capacity - 1) }
),
),
"abs": build(
(
#|fn abs(n : Int) -> Int { if n < 0 {
#| -n
#| } else {
#| n
#| } }
),
),
"next_index": build(
(
#|fn[K] next_index(self : T[K], index : Int) -> Int { (index + 1) & (self.capacity - 1) }
),
),
"calc_grow_threshold": build(
(
#|fn calc_grow_threshold(capacity : Int) -> Int { capacity * 13 / 16 }
),
),
"debug_entries": build(
(
#|fn[K : Show] debug_entries(self : T[K]) -> String { let mut s = \"\"
#| for i in 0.. 0 {
#| s += \",\"
#| }
#| match self.entries[i] {
#| None => s += \"_\"
#| Some({ psl, key, .. }) => s += \"(\\{psl},\\{key})\"
#| }
#| }
#| s }
),
),
"to_array": build(
(
#|pub fn[K] to_array(self : T[K]) -> Array[K] { let mut i = 0
#| let res = while i < self.capacity {
#| if self.entries[i] is Some({ key, .. }) {
#| i += 1
#| break Array::make(self.size, key)
#| }
#| i += 1
#| } else {
#| []
#| }
#| if !res.is_empty() {
#| let mut res_idx = 1
#| while res_idx < res.length() && i < self.capacity {
#| if self.entries[i] is Some({ key, .. }) {
#| res[res_idx] = key
#| res_idx += 1
#| }
#| i += 1
#| }
#| }
#| res }
),
),
"insert": build(
(
#|pub fn[K : Hash + Eq] insert(self : T[K], key : K) -> Unit { self.add(key) }
),
),
}
},
)
///|
let moonbitlang_core_immut_array_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/immut/array",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"core/array": moonbitlang_core_array_module,
},
fn(_env, build) {
{
"is_node": build(
(
#|fn[A] Tree::is_node(self : Tree[A]) -> Bool { self is Node(_, _) }
),
),
"is_leaf": build(
(
#|fn[A] Tree::is_leaf(self : Tree[A]) -> Bool { self is Leaf(_) }
),
),
"right_child": build(
(
#|fn[A] Tree::right_child(self : Tree[A]) -> Tree[A] { match self {
#| Node(children, _) => children[children.length() - 1]
#| Leaf(_) | Empty => abort(\"Should not get children on non-`Node`s\")
#| } }
),
),
"left_child": build(
(
#|fn[A] Tree::left_child(self : Tree[A]) -> Tree[A] { match self {
#| Node(children, _) => children[0]
#| Leaf(_) | Empty => abort(\"Should not get children on non-`Node`s\")
#| } }
),
),
"leaf_elements": build(
(
#|fn[A] Tree::leaf_elements(self : Tree[A]) -> FixedArray[A] { guard self is Leaf(children) else {
#| abort(\"Should not call `get_leaf_elements` on non-leaf nodes\")
#| }
#| children }
),
),
"node_children": build(
(
#|fn[A] Tree::node_children(self : Tree[A]) -> FixedArray[Tree[A]] { guard self is Node(children, _) else {
#| abort(\"Should not call `node_children` on non-`Node`s\")
#| }
#| children }
),
),
"local_size": build(
(
#|fn[A] Tree::local_size(self : Tree[A]) -> Int { match self {
#| Empty => 0
#| Leaf(l) => l.length()
#| Node(children, _) => children.length()
#| } }
),
),
"size": build(
(
#|fn[A] Tree::size(self : Tree[A], shift : Int) -> Int { match self {
#| Empty => 0
#| Leaf(l) => l.length()
#| Node(_, Some(sizes)) => sizes[sizes.length() - 1]
#| Node(children, None) => {
#| let len_1 = children.length() - 1
#| (len_1 << shift) + children[len_1].size(shift - num_bits)
#| }
#| } }
),
),
"new": build(
(
#|pub fn[A] new() -> T[A] { { tree: Tree::empty(), size: 0, shift: 0 } }
),
),
"make": build(
(
#|pub fn[A] make(len : Int, value : A) -> T[A] { let quot = len / branching_factor
#| let rem = len % branching_factor
#| let leaves = if rem == 0 {
#| Array::make(quot, FixedArray::make(branching_factor, value))
#| } else {
#| let arr : Array[FixedArray[A]] = Array::make(
#| quot + 1,
#| FixedArray::make(branching_factor, value),
#| )
#| arr[quot] = FixedArray::make(rem, value)
#| arr
#| }
#| let size = len
#| let (shift, cap) = shift_cap_of_size(size)
#| let tree = if size == 0 { Empty } else { from_leaves(leaves[:], cap) }
#| { shift, tree, size } }
),
),
"makei": build(
(
#|pub fn[A] makei(len : Int, f : (Int) -> A raise?) -> T[A] raise? { let quot = len / branching_factor
#| let rem = len % branching_factor
#| let leaves = if rem == 0 {
#| Array::makei(quot, k => FixedArray::makei(branching_factor, i => f(
#| k * branching_factor + i,
#| )))
#| } else {
#| let arr : Array[FixedArray[A]] = Array::make(quot + 1, [])
#| for k in 0.. f(
#| k * branching_factor + i,
#| ))
#| }
#| arr[quot] = FixedArray::makei(rem, i => f(quot * branching_factor + i))
#| arr
#| }
#| let size = len
#| let (shift, cap) = shift_cap_of_size(size)
#| let tree = if size == 0 { Empty } else { from_leaves(leaves[:], cap) }
#| { shift, tree, size } }
),
),
"of": build(
(
#|pub fn[A] of(arr : FixedArray[A]) -> T[A] { makei(arr.length(), i => arr[i]) }
),
),
"copy": build(
(
#|pub fn[A] copy(self : T[A]) -> T[A] { fn copy(t : Tree[A]) -> Tree[A] {
#| match t {
#| Leaf(l) => Leaf(l.copy())
#| Empty => Empty
#| Node(node, sizes) =>
#| Node(
#| FixedArray::makei(node.length(), i => copy(node[i])),
#| match sizes {
#| Some(sizes) => Some(FixedArray::copy(sizes))
#| None => None
#| },
#| )
#| }
#| }
#| { tree: copy(self.tree), size: self.size, shift: self.shift } }
),
),
"from_array": build(
(
#|pub fn[A] from_array(arr : Array[A]) -> T[A] { makei(arr.length(), i => arr[i]) }
),
),
"from_iter": build(
(
#|pub fn[A] from_iter(iter : Iter[A]) -> T[A] { let mut buf : FixedArray[A] = []
#| let mut index = 0
#| let leaves = []
#| iter.each(x => if index == 0 {
#| buf = FixedArray::make(branching_factor, x)
#| index += 1
#| } else if index < branching_factor {
#| buf[index] = x
#| index += 1
#| } else {
#| leaves.push(buf)
#| index = 1
#| buf = FixedArray::make(branching_factor, x)
#| })
#| if index == branching_factor {
#| leaves.push(buf)
#| } else if index > 0 {
#| let res = FixedArray::make(index, buf[0])
#| buf.blit_to(res, len=index)
#| leaves.push(res)
#| }
#| let size = leaves.fold(init=0, (acc, xs) => acc + xs.length())
#| let (shift, cap) = shift_cap_of_size(size)
#| let tree = if size == 0 { Empty } else { from_leaves(leaves[:], cap) }
#| { shift, tree, size } }
),
),
"to_array": build(
(
#|pub fn[A] to_array(self : T[A]) -> Array[A] { if self.is_empty() {
#| []
#| } else {
#| let arr = Array::make(self.length(), self[0])
#| self.eachi((i, v) => arr[i] = v)
#| arr
#| } }
),
),
"is_empty": build(
(
#|pub fn[A] is_empty(self : T[A]) -> Bool { self.size == 0 }
),
),
"length": build(
(
#|pub fn[A] length(self : T[A]) -> Int { self.size }
),
),
"op_get": build(
(
#|pub fn[A] op_get(self : T[A], index : Int) -> A { if index == 0 {
#| self.tree.get_first()
#| } else if index == self.size - 1 {
#| self.tree.get_last()
#| } else {
#| self.tree.get(index, self.shift)
#| } }
),
),
"get": build(
(
#|pub fn[A] get(self : T[A], index : Int) -> A? { guard 0 <= index && index < self.size else { None }
#| Some(self[index]) }
),
),
"set": build(
(
#|pub fn[A] set(self : T[A], index : Int, value : A) -> T[A] { {
#| tree: self.tree.set(index, self.shift, value),
#| size: self.size,
#| shift: self.shift,
#| } }
),
),
"push": build(
(
#|pub fn[A] push(self : T[A], value : A) -> T[A] { let (tree, shift) = self.tree.push_end(self.shift, value)
#| { tree, size: self.size + 1, shift } }
),
),
"concat": build(
(
#|pub fn[A] concat(self : T[A], other : T[A]) -> T[A] { if self.is_empty() {
#| return other
#| }
#| if other.is_empty() {
#| return self
#| }
#| let (tree, shift) = Tree::concat(
#| self.tree,
#| self.shift,
#| other.tree,
#| other.shift,
#| true,
#| )
#| { tree, size: self.size + other.size, shift } }
),
),
"iter": build(
(
#|pub fn[A] iter(self : T[A]) -> Iter[A] { self.tree.iter() }
),
),
"each": build(
(
#|pub fn[A] each(self : T[A], f : (A) -> Unit raise?) -> Unit raise? { self.tree.each(f) }
),
),
"eachi": build(
(
#|pub fn[A] eachi(self : T[A], f : (Int, A) -> Unit raise?) -> Unit raise? { self.tree.eachi(f, self.shift, 0) }
),
),
"fold": build(
(
#|pub fn[A, B] fold(self : T[A], init~ : B, f : (B, A) -> B raise?) -> B raise? { self.tree.fold(init, f) }
),
),
"fold_left": build(
(
#|pub fn[A] fold_left(self : T[A], f : (A, A) -> A raise?, init~ : A) -> A raise? { self.fold(init~, f) }
),
),
"map": build(
(
#|pub fn[A, B] map(self : T[A], f : (A) -> B raise?) -> T[B] raise? { { tree: self.tree.map(f), size: self.size, shift: self.shift } }
),
),
"shift_cap_of_size": build(
(
#|fn shift_cap_of_size(size : Int) -> (Int, Int) { let mut cap = branching_factor
#| let mut depth = 0
#| while cap < size {
#| cap *= branching_factor
#| depth += 1
#| }
#| let shift = num_bits * depth
#| (shift, cap) }
),
),
"new": build(
(
#|pub fn[A] T::new() -> T[A] { new() }
),
),
"from_iter": build(
(
#|pub fn[A] T::from_iter(iter : Iter[A]) -> T[A] { from_iter(iter) }
),
),
"from_array": build(
(
#|pub fn[A] T::from_array(arr : Array[A]) -> T[A] { from_array(arr) }
),
),
"make": build(
(
#|pub fn[A] T::make(len : Int, value : A) -> T[A] { make(len, value) }
),
),
"makei": build(
(
#|pub fn[A] T::makei(len : Int, f : (Int) -> A) -> T[A] { makei(len, f) }
),
),
"of": build(
(
#|pub fn[A] T::of(arr : FixedArray[A]) -> T[A] { of(arr) }
),
),
"immutable_set": build(
(
#|fn[T] immutable_set(arr : FixedArray[T], i : Int, v : T) -> FixedArray[T] { let arr = arr.copy()
#| arr[i] = v
#| arr }
),
),
"immutable_push": build(
(
#|fn[T] immutable_push(arr : FixedArray[T], val : T) -> FixedArray[T] { let len = arr.length()
#| let new_arr = FixedArray::make(len + 1, val)
#| arr.blit_to(new_arr, len~)
#| new_arr[len] = val
#| new_arr }
),
),
"shr_as_uint": build(
(
#|fn shr_as_uint(x : Int, y : Int) -> Int { (x.reinterpret_as_uint() >> y).reinterpret_as_int() }
),
),
"radix_indexing": build(
(
#|fn radix_indexing(index : Int, shift : Int) -> Int { shr_as_uint(index, shift) & bitmask }
),
),
"get_branch_index": build(
(
#|fn get_branch_index(sizes : FixedArray[Int], index : Int) -> Int { let mut lo = 0
#| let mut hi = sizes.length()
#| while LINEAR_THRESHOLD < hi - lo {
#| let mid = (lo + hi) / 2
#| if sizes[mid] <= index {
#| lo = mid
#| } else {
#| hi = mid
#| }
#| }
#| while sizes[lo] <= index {
#| lo += 1
#| }
#| lo }
),
),
"copy_sizes": build(
(
#|fn copy_sizes(sizes : FixedArray[Int]?) -> FixedArray[Int]? { match sizes {
#| Some(sizes) => Some(sizes.copy())
#| None => None
#| } }
),
),
"min": build(
(
#|fn min(a : Int, b : Int) -> Int { if a < b {
#| a
#| } else {
#| b
#| } }
),
),
"num_bits": (None, Int(5)),
"empty": build(
(
#|fn[T] Tree::empty() -> Tree[T] { Tree::Empty }
),
),
"new_branch_left": build(
(
#|fn[T] new_branch_left(leaf : FixedArray[T], shift : Int) -> Tree[T] { match shift {
#| 0 => Leaf(leaf)
#| s => Node([new_branch_left(leaf, s - num_bits)], None) // size is None because we can use radix indexing
#| } }
),
),
"get_first": build(
(
#|fn[T] Tree::get_first(self : Tree[T]) -> T { match self {
#| Leaf(leaf) => leaf[0]
#| Node(node, _) => node[0].get_first()
#| Empty => abort(\"Index out of bounds\")
#| } }
),
),
"get_last": build(
(
#|fn[T] Tree::get_last(self : Tree[T]) -> T { match self {
#| Leaf(leaf) => leaf[leaf.length() - 1]
#| Node(node, _) => node[node.length() - 1].get_last()
#| Empty => abort(\"Index out of bounds\")
#| } }
),
),
"get": build(
(
#|fn[T] Tree::get(self : Tree[T], index : Int, shift : Int) -> T { fn get_radix(node : Tree[T], shift : Int) -> T {
#| match node {
#| Leaf(leaf) => leaf[index & bitmask]
#| Node(node, None) =>
#| get_radix(node[radix_indexing(index, shift)], shift - num_bits)
#| Node(_, Some(_)) =>
#| abort(\"Unreachable: Node should not have sizes in get_radix\")
#| Empty => abort(\"Index out of bounds\")
#| }
#| }
#| match self {
#| Leaf(leaf) => leaf[index]
#| Node(children, Some(sizes)) => {
#| let branch_index = get_branch_index(sizes, index)
#| let sub_index = if branch_index == 0 {
#| index
#| } else {
#| index - sizes[branch_index - 1]
#| }
#| children[branch_index].get(sub_index, shift - num_bits)
#| }
#| Node(_, None) => get_radix(self, shift)
#| Empty => abort(\"Index out of bounds\")
#| } }
),
),
"set": build(
(
#|fn[T] Tree::set(self : Tree[T], index : Int, shift : Int, value : T) -> Tree[T] { // TODO: optimize this as loop
#| fn set_radix(node : Tree[T], shift : Int) -> Tree[T] {
#| match node {
#| Leaf(leaf) => Leaf(immutable_set(leaf, index & bitmask, value))
#| Node(node, None) => {
#| let sub_idx = radix_indexing(index, shift)
#| Node(
#| immutable_set(
#| node,
#| sub_idx,
#| set_radix(node[radix_indexing(index, shift)], shift - num_bits),
#| ),
#| None,
#| )
#| }
#| Node(_, Some(_)) =>
#| abort(\"Unreachable: Node should not have sizes in set_radix\")
#| Empty => abort(\"Index out of bounds\")
#| }
#| }
#| match self {
#| Leaf(leaf) => Leaf(immutable_set(leaf, index & bitmask, value))
#| Node(children, Some(sizes)) => {
#| let branch_index = get_branch_index(sizes, index)
#| let sub_index = if branch_index == 0 {
#| index
#| } else {
#| index - sizes[branch_index - 1]
#| }
#| Node(
#| immutable_set(
#| children,
#| branch_index,
#| children[branch_index].set(sub_index, shift - num_bits, value),
#| ),
#| Some(sizes),
#| )
#| }
#| Node(_children, None) => set_radix(self, shift)
#| Empty => abort(\"Index out of bounds\")
#| } }
),
),
"push_end": build(
(
#|fn[T] Tree::push_end(self : Tree[T], shift : Int, value : T) -> (Tree[T], Int) { fn update_sizes_last(sizes : FixedArray[Int]?) -> FixedArray[Int]? {
#| match sizes {
#| Some(sizes) => {
#| let new_sizes = sizes.copy()
#| new_sizes[new_sizes.length() - 1] += 1
#| Some(new_sizes)
#| }
#| None => None
#| }
#| }
#| fn push_sizes_last(sizes : FixedArray[Int]?) -> FixedArray[Int]? {
#| match sizes {
#| Some(sizes) => Some(immutable_push(sizes, 1 + sizes[sizes.length() - 1]))
#| None => None
#| }
#| }
#| fn worker(node : Tree[T], shift : Int) -> Tree[T]? {
#| match node {
#| Leaf(leaf) => {
#| if shift != 0 {
#| abort(
#| \"Unreachable: Leaf should not have a non-zero shift, which means we have not reached the bottom of the tree\",
#| )
#| }
#| if leaf.length() < branching_factor {
#| Some(Leaf(immutable_push(leaf, value)))
#| } else {
#| None
#| }
#| }
#| Node(nodes, sizes) => {
#| let len = nodes.length()
#| match worker(nodes[len - 1], shift - num_bits) {
#| // We have successfully pushed the value, now duplicate its ancestor nodes.
#| Some(new_node) => {
#| let new_nodes = nodes.copy()
#| new_nodes[len - 1] = new_node
#| let sizes = update_sizes_last(sizes)
#| Some(Node(new_nodes, sizes))
#| }
#| // We need to create a new node to push the value.
#| None =>
#| if len < branching_factor {
#| let sizes = push_sizes_last(sizes)
#| Some(
#| Node(
#| immutable_push(
#| nodes,
#| new_branch_left([value], shift - num_bits),
#| ),
#| sizes,
#| ),
#| )
#| } else {
#| None
#| }
#| }
#| }
#| Empty => Some(Leaf([value]))
#| }
#| }
#| match worker(self, shift) {
#| Some(new_tree) => (new_tree, shift)
#| None => {
#| let new_branch = new_branch_left([value], shift)
#| (
#| match self {
#| Leaf(_leaf) => Node([self, new_branch], None)
#| Node(_nodes, Some(sizes)) => {
#| let len = sizes[sizes.length() - 1]
#| let sizes = FixedArray::from_array([len, 1 + len])
#| Node([self, new_branch], Some(sizes))
#| }
#| Node(_nodes, None) => Node([self, new_branch], None)
#| Empty =>
#| abort(
#| \"Unreachable: Empty tree should have fallen into the Some(new_tree) branch\",
#| )
#| },
#| shift + num_bits,
#| )
#| }
#| } }
),
),
"each": build(
(
#|fn[A] Tree::each(self : Tree[A], f : (A) -> Unit raise?) -> Unit raise? { match self {
#| Empty => ()
#| Leaf(l) => l.each(f)
#| Node(ns, _) => ns.each(t => t.each(f))
#| } }
),
),
"iter": build(
(
#|fn[A] Tree::iter(self : Tree[A]) -> Iter[A] { Iter::new(yield_ => match self {
#| Empty => IterContinue
#| Leaf(l) => l.iter().run(yield_)
#| Node(ns, _) =>
#| for n in ns {
#| guard n.iter().run(yield_) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }
#| }) }
),
),
"map": build(
(
#|fn[A, B] Tree::map(self : Tree[A], f : (A) -> B raise?) -> Tree[B] raise? { match self {
#| Empty => Empty
#| Leaf(l) => Leaf(l.map(f))
#| Node(n, szs) =>
#| Node(FixedArray::makei(n.length(), i => n[i].map(f)), copy_sizes(szs))
#| } }
),
),
"redis_plan": build(
(
#|fn[A] redis_plan(t : FixedArray[Tree[A]]) -> (FixedArray[Int], Int) { let node_counts = FixedArray::makei(t.length(), i => t[i].local_size())
#| let total_nodes = node_counts.fold(init=0, (acc, x) => acc + x)
#| // round up to the nearest integer of S/branching_factor
#| let opt_len = (total_nodes + branching_factor - 1) / branching_factor
#| let mut new_len = t.length()
#| let mut i = 0
#| while opt_len + e_max_2 < new_len {
#| // Skip over all nodes satisfying the invariant.
#| while node_counts[i] > branching_factor - e_max_2 {
#| i += 1
#| }
#| // Found short node, so redistribute over the next nodes
#| let mut remaining_nodes = node_counts[i]
#| while remaining_nodes > 0 {
#| let min_size = min(remaining_nodes + node_counts[i + 1], branching_factor)
#| node_counts[i] = min_size
#| remaining_nodes = remaining_nodes + node_counts[i + 1] - min_size
#| i += 1
#| }
#| for j in i..<(new_len - 1) {
#| node_counts[j] = node_counts[j + 1]
#| }
#| new_len -= 1
#| i -= 1
#| }
#| return (node_counts, new_len) }
),
),
}
},
)
///|
let moonbitlang_core_immut_hashmap_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/immut/hashmap",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/tuple": moonbitlang_core_tuple_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/immut/internal/sparse_array": moonbitlang_core_immut_internal_sparse_array_module,
"moonbitlang/core/immut/internal/path": moonbitlang_core_immut_internal_path_module,
"moonbitlang/core/list": moonbitlang_core_list_module,
},
fn(_env, build) {
{
"new": build(
(
#|pub fn[K, V] new() -> T[K, V] { None }
),
),
"singleton": build(
(
#|pub fn[K : Hash, V] singleton(key : K, value : V) -> T[K, V] { Some(Flat(key, value, @path.of(key))) }
),
),
"contains": build(
(
#|pub fn[K : Eq + Hash, V] contains(self : T[K, V], key : K) -> Bool { self.get(key) is Some(_) }
),
),
"find": build(
(
#|pub fn[K : Eq + Hash, V] find(self : T[K, V], key : K) -> V? { self.get(key) }
),
),
"get": build(
(
#|pub fn[K : Eq + Hash, V] get(self : T[K, V], key : K) -> V? { match self.0 {
#| None => None
#| Some(node) => node.get_with_path(key, @path.of(key))
#| } }
),
),
"op_get": build(
(
#|pub fn[K : Eq + Hash, V] op_get(self : T[K, V], key : K) -> V? { self.get(key) }
),
),
"map": build(
(
#|pub fn[K, V, A] map(self : T[K, V], f : (V) -> A raise?) -> T[K, A] raise? { self.map_with_key((_k, v) => f(v)) }
),
),
"add": build(
(
#|pub fn[K : Eq + Hash, V] add(self : T[K, V], key : K, value : V) -> T[K, V] { match self.0 {
#| None => Some(Flat(key, value, @path.of(key)))
#| Some(node) => Some(node.add_with_path(key, value, @path.of(key)))
#| } }
),
),
"remove": build(
(
#|pub fn[K : Eq + Hash, V] remove(self : T[K, V], key : K) -> T[K, V] { match self.0 {
#| None => None
#| Some(node) => node.remove_with_path(key, @path.of(key))
#| } }
),
),
"size": build(
(
#|pub fn[K, V] size(self : T[K, V]) -> Int { fn node_size(node) {
#| match node {
#| Leaf(_, _, bucket) => 1 + bucket.length()
#| Flat(_) => 1
#| Branch(children) =>
#| for i = 0, total_size = 0; i < children.data.length(); {
#| continue i + 1, total_size + node_size(children.data[i])
#| } else {
#| total_size
#| }
#| }
#| }
#| match self.0 {
#| None => 0
#| Some(node) => node_size(node)
#| } }
),
),
"union": build(
(
#|pub fn[K : Eq, V] T::union(self : T[K, V], other : T[K, V]) -> T[K, V] { fn go(node1 : Node[_], node2) {
#| match (node1, node2) {
#| (_, Flat(key2, value2, path2)) => node1.add_with_path(key2, value2, path2)
#| (Flat(key1, value1, path1), _) =>
#| match node2.get_with_path(key1, path1) {
#| Some(_) => node2
#| None => node2.add_with_path(key1, value1, path1)
#| }
#| (Branch(children1), Branch(children2)) =>
#| Branch(children1.union(children2, go))
#| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => {
#| let kvs1 = bucket1.add((key1, value1))
#| let kvs2 = bucket2.add((key2, value2))
#| match kvs1.filter(kv => kvs2.lookup(kv.0) is None) {
#| Empty => node2
#| More(head, tail~) => Leaf(key2, value2, bucket2 + tail.add(head))
#| }
#| }
#| _ => abort(\"Unreachable\")
#| }
#| }
#| match (self.0, other.0) {
#| (None, x) | (x, None) => x
#| (Some(a), Some(b)) => Some(go(a, b))
#| } }
),
),
"intersection": build(
(
#|pub fn[K : Eq, V] T::intersection(self : T[K, V], other : T[K, V]) -> T[K, V] { fn go(node1 : Node[_], node2) {
#| match (node1, node2) {
#| (_, Flat(key2, _, path2)) =>
#| match node1.get_with_path(key2, path2) {
#| Some(_) => Some(node2)
#| None => None
#| }
#| (Flat(key1, _, path1), _) =>
#| match node2.get_with_path(key1, path1) {
#| Some(value2) => Some(Flat(key1, value2, path1))
#| None => None
#| }
#| (Branch(children1), Branch(children2)) =>
#| match children1.intersection(children2, go) {
#| None => None
#| Some({ data: [Flat(key, value, path)], elem_info }) =>
#| Some(Flat(key, value, path.push(elem_info.first_idx())))
#| Some(children) => Some(Branch(children))
#| }
#| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => {
#| let kvs1 = bucket1.add((key1, value1))
#| let kvs2 = bucket2.add((key2, value2))
#| match kvs2.filter(kv => kvs1.lookup(kv.0) is Some(_)) {
#| Empty => None
#| More(head, tail~) => Some(Leaf(head.0, head.1, tail))
#| }
#| }
#| _ => abort(\"Unreachable\")
#| }
#| }
#| match (self.0, other.0) {
#| (None, _) | (_, None) => None
#| (Some(a), Some(b)) => go(a, b)
#| } }
),
),
"difference": build(
(
#|pub fn[K : Eq, V] T::difference(self : T[K, V], other : T[K, V]) -> T[K, V] { fn go(node1 : Node[_], node2) {
#| match (node1, node2) {
#| (node, Flat(k, _, path)) => node.remove_with_path(k, path)
#| (Flat(key, _, path), _) =>
#| match node2.get_with_path(key, path) {
#| Some(_) => None
#| None => Some(node1)
#| }
#| (Branch(children1), Branch(children2)) =>
#| match children1.difference(children2, go) {
#| None => None
#| Some({ data: [Flat(key, value, path)], elem_info }) =>
#| Some(Flat(key, value, path.push(elem_info.first_idx())))
#| Some(children) => Some(Branch(children))
#| }
#| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => {
#| let kvs1 = bucket1.add((key1, value1))
#| let kvs2 = bucket2.add((key2, value2))
#| match kvs1.filter(kv => not(kvs2.lookup(kv.0) is Some(_))) {
#| Empty => None
#| More(head, tail~) => Some(Leaf(head.0, head.1, tail))
#| }
#| }
#| _ => abort(\"Unreachable\")
#| }
#| }
#| match (self.0, other.0) {
#| (None, _) => None
#| (_, None) => self
#| (Some(a), Some(b)) => go(a, b)
#| } }
),
),
"each": build(
(
#|pub fn[K, V] each(self : T[K, V], f : (K, V) -> Unit raise?) -> Unit raise? { fn go(node) raise? {
#| match node {
#| Leaf(k, v, bucket) => {
#| f(k, v)
#| bucket.each(kv => f(kv.0, kv.1))
#| }
#| Flat(k, v, _) => f(k, v)
#| Branch(children) => children.each(go)
#| }
#| }
#| match self.0 {
#| None => ()
#| Some(node) => go(node)
#| } }
),
),
"keys": build(
(
#|pub fn[K, V] keys(self : T[K, V]) -> Iter[K] { self.iter().map(p => p.0) }
),
),
"values": build(
(
#|pub fn[K, V] values(self : T[K, V]) -> Iter[V] { self.iter().map(p => p.1) }
),
),
"elems": build(
(
#|pub fn[K, V] elems(self : T[K, V]) -> Iter[V] { self.values() }
),
),
"iter": build(
(
#|pub fn[K, V] iter(self : T[K, V]) -> Iter[(K, V)] { fn go(node) -> Iter[(K, V)] {
#| match node {
#| Leaf(k, v, bucket) => Iter::singleton((k, v)) + bucket.iter()
#| Flat(k, v, _) => Iter::singleton((k, v))
#| Branch(children) => children.data.iter().flat_map(go)
#| }
#| }
#| match self.0 {
#| None => Iter::empty()
#| Some(node) => go(node)
#| } }
),
),
"iter2": build(
(
#|pub fn[K, V] iter2(self : T[K, V]) -> Iter2[K, V] { Iter2::new(yield_ => for kv in self {
#| guard yield_(kv.0, kv.1) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }) }
),
),
"from_iter": build(
(
#|pub fn[K : Eq + Hash, V] from_iter(iter : Iter[(K, V)]) -> T[K, V] { iter.fold(init=new(), (m, e) => m.add(e.0, e.1)) }
),
),
"from_array": build(
(
#|pub fn[K : Eq + Hash, V] from_array(arr : Array[(K, V)]) -> T[K, V] { loop (arr.length(), new()) {
#| (0, map) => map
#| (n, map) => {
#| let (k, v) = arr[n - 1]
#| continue (n - 1, map.add(k, v))
#| }
#| } }
),
),
"to_array": build(
(
#|pub fn[K, V] to_array(self : T[K, V]) -> Array[(K, V)] { let arr = Array::new(capacity=self.size())
#| self.each((k, v) => arr.push((k, v)))
#| arr }
),
),
"of": build(
(
#|pub fn[K : Eq + Hash, V] of(arr : FixedArray[(K, V)]) -> T[K, V] { loop (arr.length(), new()) {
#| (0, map) => map
#| (n, map) => {
#| let (k, v) = arr[n - 1]
#| continue (n - 1, map.add(k, v))
#| }
#| } }
),
),
}
},
)
///|
let moonbitlang_core_immut_hashset_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/immut/hashset",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/immut/internal/sparse_array": moonbitlang_core_immut_internal_sparse_array_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/immut/internal/path": moonbitlang_core_immut_internal_path_module,
"moonbitlang/core/list": moonbitlang_core_list_module,
},
fn(_env, build) {
{
"new": build(
(
#|pub fn[A] new() -> T[A] { None }
),
),
"contains": build(
(
#|pub fn[A : Eq + Hash] contains(self : T[A], key : A) -> Bool { self.0 is Some(node) && node.contains(key, @path.of(key)) }
),
),
"contains": build(
(
#|fn[A : Eq] Node::contains(self : Node[A], key : A, path : Path) -> Bool { loop (self, path) {
#| (Leaf(key1, bucket), _) => key == key1 || bucket.contains(key)
#| (Flat(key1, path1), path) => path == path1 && key == key1
#| (Branch(children), path) => {
#| let idx = path.idx()
#| if children[idx] is Some(child) {
#| continue (child, path.next())
#| }
#| false
#| }
#| } }
),
),
"join_2": build(
(
#|fn[A] join_2(key1 : A, path1 : Path, key2 : A, path2 : Path) -> Node[A] { let idx1 = path1.idx()
#| let idx2 = path2.idx()
#| if idx1 == idx2 {
#| let node = if path1.is_last() {
#| Leaf(key2, @list.singleton(key1))
#| } else {
#| join_2(key1, path1.next(), key2, path2.next())
#| }
#| Branch(@sparse_array.singleton(idx1, node))
#| } else {
#| let (node1, node2) = if path1.is_last() {
#| (Leaf(key1, @list.empty()), Leaf(key2, @list.empty()))
#| } else {
#| (Flat(key1, path1.next()), Flat(key2, path2.next()))
#| }
#| Branch(@sparse_array.doubleton(idx1, node1, idx2, node2))
#| } }
),
),
"add_with_path": build(
(
#|fn[A : Eq] add_with_path(self : Node[A], key : A, path : Path) -> Node[A] { match self {
#| Leaf(key1, bucket) =>
#| if key == key1 || bucket.contains(key) {
#| self
#| } else {
#| Leaf(key, bucket.add(key1))
#| }
#| Flat(key1, path1) =>
#| if path == path1 && key == key1 {
#| self
#| } else {
#| join_2(key1, path1, key, path)
#| }
#| Branch(children) => {
#| let idx = path.idx()
#| match children[idx] {
#| Some(child) => {
#| let child = child.add_with_path(key, path.next())
#| Branch(children.replace(idx, child))
#| }
#| None => {
#| let child = Flat(key, path.next())
#| Branch(children.add(idx, child))
#| }
#| }
#| }
#| } }
),
),
"add": build(
(
#|pub fn[A : Eq + Hash] add(self : T[A], key : A) -> T[A] { match self.0 {
#| None => Some(Flat(key, @path.of(key)))
#| Some(node) => Some(node.add_with_path(key, @path.of(key)))
#| } }
),
),
"remove": build(
(
#|pub fn[A : Eq + Hash] remove(self : T[A], key : A) -> T[A] { match self.0 {
#| None => None
#| Some(node) => node.remove_with_path(key, @path.of(key))
#| } }
),
),
"remove_with_path": build(
(
#|fn[A : Eq] remove_with_path(self : Node[A], key : A, path : Path) -> Node[A]? { match self {
#| Leaf(key1, bucket) =>
#| if key1 == key {
#| match bucket {
#| @list.Empty => None
#| More(key2, tail=xs) => Some(Leaf(key2, xs))
#| }
#| } else if bucket.find_index(key.op_equal(_)) is Some(index) {
#| Some(Leaf(key1, bucket.remove_at(index)))
#| } else {
#| Some(self)
#| }
#| Flat(key1, path1) =>
#| if path == path1 && key == key1 {
#| None
#| } else {
#| Some(self)
#| }
#| Branch(children) => {
#| let idx = path.idx()
#| match children[idx] {
#| None => Some(self)
#| Some(child) => {
#| let new_child = child.remove_with_path(key, path.next())
#| let new_children = match (children.size(), new_child) {
#| (1, None) => return None
#| (_, None) => children.remove(idx)
#| (_, Some(new_child)) => children.replace(idx, new_child)
#| }
#| match new_children.data {
#| [Flat(key1, path1)] =>
#| Some(Flat(key1, path1.push(new_children.elem_info.first_idx())))
#| _ => Some(Branch(new_children))
#| }
#| }
#| }
#| }
#| } }
),
),
"size": build(
(
#|pub fn[A] size(self : T[A]) -> Int { fn node_size(node) {
#| match node {
#| Leaf(_, bucket) => 1 + bucket.length()
#| Flat(_) => 1
#| Branch(children) =>
#| for i = 0, total_size = 0; i < children.data.length(); {
#| continue i + 1, total_size + node_size(children.data[i])
#| } else {
#| total_size
#| }
#| }
#| }
#| match self.0 {
#| None => 0
#| Some(node) => node_size(node)
#| } }
),
),
"union": build(
(
#|pub fn[K : Eq] T::union(self : T[K], other : T[K]) -> T[K] { fn go(node1, node2) {
#| match (node1, node2) {
#| (node, Flat(key, path)) | (Flat(key, path), node) =>
#| node.add_with_path(key, path)
#| (Branch(children1), Branch(children2)) =>
#| Branch(children1.union(children2, go))
#| (Leaf(key1, bucket1), Leaf(key2, bucket2)) => {
#| let keys1 = bucket1.add(key1)
#| let keys2 = bucket2.add(key2)
#| match keys1.filter(k => !keys2.contains(k)) {
#| Empty => node2
#| More(head, tail~) => Leaf(key2, bucket2 + tail.add(head))
#| }
#| }
#| _ => abort(\"Unreachable\")
#| }
#| }
#| match (self.0, other.0) {
#| (None, x) | (x, None) => x
#| (Some(a), Some(b)) => Some(go(a, b))
#| } }
),
),
"intersection": build(
(
#|pub fn[K : Eq] T::intersection(self : T[K], other : T[K]) -> T[K] { fn go(node1, node2) {
#| match (node1, node2) {
#| (node, Flat(key, path) as flat) | (Flat(key, path) as flat, node) =>
#| if node.contains(key, path) {
#| Some(flat)
#| } else {
#| None
#| }
#| (Branch(children1), Branch(children2)) =>
#| match children1.intersection(children2, go) {
#| None => None
#| Some({ data: [Flat(key, path)], elem_info }) =>
#| Some(Flat(key, path.push(elem_info.first_idx())))
#| Some(children) => Some(Branch(children))
#| }
#| (Leaf(key1, bucket1), Leaf(key2, bucket2)) => {
#| let keys1 = bucket1.add(key1)
#| let keys2 = bucket2.add(key2)
#| match keys1.filter(keys2.contains(_)) {
#| Empty => None
#| More(head, tail~) => Some(Leaf(head, tail))
#| }
#| }
#| _ => abort(\"Unreachable\")
#| }
#| }
#| match (self.0, other.0) {
#| (None, _) | (_, None) => None
#| (Some(a), Some(b)) => go(a, b)
#| } }
),
),
"difference": build(
(
#|pub fn[K : Eq] T::difference(self : T[K], other : T[K]) -> T[K] { fn go(node1 : Node[_], node2) {
#| match (node1, node2) {
#| (node, Flat(k, path)) => node.remove_with_path(k, path)
#| (Flat(key, path) as flat, node) =>
#| if node.contains(key, path) {
#| None
#| } else {
#| Some(flat)
#| }
#| (Branch(children1), Branch(children2)) =>
#| match children1.difference(children2, go) {
#| None => None
#| Some({ data: [Flat(key, path)], elem_info }) =>
#| Some(Flat(key, path.push(elem_info.first_idx())))
#| Some(children) => Some(Branch(children))
#| }
#| (Leaf(key1, bucket1), Leaf(key2, bucket2)) => {
#| let keys1 = bucket1.add(key1)
#| let keys2 = bucket2.add(key2)
#| match keys1.filter(k => !keys2.contains(k)) {
#| Empty => None
#| More(head, tail~) => Some(Leaf(head, tail))
#| }
#| }
#| _ => abort(\"Unreachable\")
#| }
#| }
#| match (self.0, other.0) {
#| (None, _) => None
#| (_, None) => self
#| (Some(a), Some(b)) => go(a, b)
#| } }
),
),
"is_empty": build(
(
#|pub fn[A] is_empty(self : T[A]) -> Bool { self.0 is None }
),
),
"each": build(
(
#|pub fn[A] each(self : T[A], f : (A) -> Unit raise?) -> Unit raise? { fn go(node) raise? {
#| match node {
#| Leaf(k, bucket) => {
#| f(k)
#| bucket.each(f)
#| }
#| Flat(k, _) => f(k)
#| Branch(children) => children.each(go)
#| }
#| }
#| match self.0 {
#| None => ()
#| Some(node) => go(node)
#| } }
),
),
"iter": build(
(
#|pub fn[A] iter(self : T[A]) -> Iter[A] { fn go(node) -> Iter[A] {
#| match node {
#| Leaf(k, bucket) => Iter::singleton(k) + bucket.iter()
#| Flat(k, _) => Iter::singleton(k)
#| Branch(children) => children.data.iter().flat_map(go)
#| }
#| }
#| match self.0 {
#| None => Iter::empty()
#| Some(node) => go(node)
#| } }
),
),
"from_iter": build(
(
#|pub fn[A : Eq + Hash] from_iter(iter : Iter[A]) -> T[A] { iter.fold(init=new(), (s, e) => s.add(e)) }
),
),
"from_array": build(
(
#|pub fn[A : Eq + Hash] from_array(arr : Array[A]) -> T[A] { loop (arr.length(), new()) {
#| (0, set) => set
#| (n, set) => {
#| let k = arr[n - 1]
#| continue (n - 1, set.add(k))
#| }
#| } }
),
),
"of": build(
(
#|pub fn[A : Eq + Hash] of(arr : FixedArray[A]) -> T[A] { loop (arr.length(), new()) {
#| (0, set) => set
#| (n, set) => {
#| let k = arr[n - 1]
#| continue (n - 1, set.add(k))
#| }
#| } }
),
),
}
},
)
///|
let moonbitlang_core_immut_internal_path_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/immut/internal/path",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
fn(_env, build) {
{
"of": build(
(
#|pub fn[A : Hash] of(key : A) -> Path { key.hash().reinterpret_as_uint() | HEAD_TAG }
),
),
"is_last": build(
(
#|pub fn Path::is_last(self : Path) -> Bool { let Path(self) = self
#| self <= MAX_TAIL }
),
),
"push": build(
(
#|pub fn Path::push(self : Path, idx : Int) -> Path { let Path(self) = self
#| (self << SEGMENT_LENGTH) | idx.reinterpret_as_uint() }
),
),
"idx": build(
(
#|pub fn Path::idx(self : Path) -> Int { let Path(self) = self
#| (self & INDEX_MASK).reinterpret_as_int() }
),
),
"next": build(
(
#|pub fn Path::next(self : Path) -> Path { let Path(self) = self
#| self >> SEGMENT_LENGTH }
),
),
}
},
)
///|
let moonbitlang_core_immut_internal_sparse_array_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/immut/internal/sparse_array",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
},
fn(_env, build) {
{
"empty": build(
(
#|pub fn[X] empty() -> SparseArray[X] { { elem_info: empty_bitset, data: [] } }
),
),
"singleton": build(
(
#|pub fn[X] singleton(idx : Int, value : X) -> SparseArray[X] { { elem_info: empty_bitset.add(idx), data: [value] } }
),
),
"op_get": build(
(
#|pub fn[X] op_get(self : SparseArray[X], idx : Int) -> X? { if self.elem_info.has(idx) {
#| Some(self.data[self.elem_info.index_of(idx)])
#| } else {
#| None
#| } }
),
),
"unsafe_get": build(
(
#|fn[X] unsafe_get(self : SparseArray[X], idx : Int) -> X { self.data[self.elem_info.index_of(idx)] }
),
),
"add": build(
(
#|pub fn[X] add(self : SparseArray[X], idx : Int, value : X) -> SparseArray[X] { let old_data = self.data
#| let old_len = old_data.length()
#| let new_len = old_len + 1
#| let pos_of_new_item = self.elem_info.index_of(idx)
#| let new_data = FixedArray::make(new_len, value)
#| old_data.blit_to(new_data, len=pos_of_new_item)
#| old_data.blit_to(
#| new_data,
#| len=old_len - pos_of_new_item,
#| src_offset=pos_of_new_item,
#| dst_offset=pos_of_new_item + 1,
#| )
#| { elem_info: self.elem_info.add(idx), data: new_data } }
),
),
"remove": build(
(
#|pub fn[X] remove(self : SparseArray[X], idx : Int) -> SparseArray[X] { let old_data = self.data
#| let old_len = old_data.length()
#| let pos_of_removed_item = self.elem_info.index_of(idx)
#| let new_data = FixedArray::make(old_len - 1, old_data.unsafe_get(0))
#| old_data.blit_to(
#| new_data,
#| len=pos_of_removed_item,
#| src_offset=0,
#| dst_offset=0,
#| )
#| old_data.blit_to(
#| new_data,
#| len=old_len - pos_of_removed_item - 1,
#| src_offset=pos_of_removed_item + 1,
#| dst_offset=pos_of_removed_item,
#| )
#| { elem_info: self.elem_info.remove(idx), data: new_data } }
),
),
"size": build(
(
#|pub fn[X] size(self : SparseArray[X]) -> Int { self.data.length() }
),
),
"each": build(
(
#|pub fn[X] each(self : SparseArray[X], f : (X) -> Unit raise?) -> Unit raise? { for i in 0.. Bool { (self.0 & (1U << idx)) != 0 }
),
),
"index_of": build(
(
#|pub fn Bitset::index_of(self : Bitset, idx : Int) -> Int { (self.0 & ((1U << idx) - 1)).popcnt() }
),
),
"first_idx": build(
(
#|pub fn Bitset::first_idx(self : Bitset) -> Int { self.0.ctz() }
),
),
"union": build(
(
#|pub fn Bitset::union(self : Bitset, other : Bitset) -> Bitset { Bitset(self.0 | other.0) }
),
),
"intersection": build(
(
#|pub fn Bitset::intersection(self : Bitset, other : Bitset) -> Bitset { Bitset(self.0 & other.0) }
),
),
"add": build(
(
#|pub fn Bitset::add(self : Bitset, idx : Int) -> Bitset { Bitset(self.0 | (1U << idx)) }
),
),
"remove": build(
(
#|pub fn Bitset::remove(self : Bitset, idx : Int) -> Bitset { Bitset(self.0 ^ (1U << idx)) }
),
),
"size": build(
(
#|pub fn Bitset::size(self : Bitset) -> Int { let Bitset(self) = self
#| self.popcnt() }
),
),
}
},
)
///|
let moonbitlang_core_immut_list_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/immut/list",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
"moonbitlang/core/option": moonbitlang_core_option_module,
},
fn(_env, build) {
{
"add": build(
(
#|pub fn[A] add(self : T[A], head : A) -> T[A] { Cons(head, self) }
),
),
"to_json": build(
(
#|pub fn[A : ToJson] to_json(self : T[A]) -> Json { ToJson::to_json(self) }
),
),
"from_array": build(
(
#|pub fn[A] from_array(arr : Array[A]) -> T[A] { for i = arr.length() - 1, list = Nil; i >= 0; {
#| continue i - 1, Cons(arr[i], list)
#| } else {
#| list
#| } }
),
),
"length": build(
(
#|pub fn[A] length(self : T[A]) -> Int { loop (self, 0) {
#| (Nil, len) => len
#| (Cons(_, rest), acc) => continue (rest, acc + 1)
#| } }
),
),
"each": build(
(
#|pub fn[A] each(self : T[A], f : (A) -> Unit raise?) -> Unit raise? { loop self {
#| Nil => ()
#| Cons(head, tail) => {
#| f(head)
#| continue tail
#| }
#| } }
),
),
"eachi": build(
(
#|pub fn[A] eachi(self : T[A], f : (Int, A) -> Unit raise?) -> Unit raise? { loop (self, 0) {
#| (Nil, _) => ()
#| (Cons(x, xs), i) => {
#| f(i, x)
#| continue (xs, i + 1)
#| }
#| } }
),
),
"map": build(
(
#|pub fn[A, B] map(self : T[A], f : (A) -> B) -> T[B] { match self {
#| Nil => Nil
#| Cons(head, tail) => Cons(f(head), tail.map(f))
#| } }
),
),
"mapi": build(
(
#|pub fn[A, B] mapi(self : T[A], f : (Int, A) -> B raise?) -> T[B] raise? { fn go(xs : T[A], i : Int, f : (Int, A) -> B raise?) -> T[B] raise? {
#| match xs {
#| Nil => Nil
#| Cons(x, xs) => Cons(f(i, x), go(xs, i + 1, f))
#| }
#| }
#| go(self, 0, f) }
),
),
"rev_map": build(
(
#|pub fn[A, B] rev_map(self : T[A], f : (A) -> B raise?) -> T[B] raise? { loop (Nil, self) {
#| (acc, Nil) => acc
#| (acc, Cons(x, xs)) => continue (Cons(f(x), acc), xs)
#| } }
),
),
"to_array": build(
(
#|pub fn[A] to_array(self : T[A]) -> Array[A] { match self {
#| Nil => []
#| Cons(x, xs) => {
#| let arr = [x]
#| loop xs {
#| Nil => ()
#| Cons(x, xs) => {
#| arr.push(x)
#| continue xs
#| }
#| }
#| arr
#| }
#| } }
),
),
"filter": build(
(
#|pub fn[A] filter(self : T[A], f : (A) -> Bool raise?) -> T[A] raise? { match self {
#| Nil => Nil
#| Cons(head, tail) =>
#| if f(head) {
#| Cons(head, tail.filter(f))
#| } else {
#| tail.filter(f)
#| }
#| } }
),
),
"all": build(
(
#|pub fn[A] all(self : T[A], f : (A) -> Bool raise?) -> Bool raise? { loop self {
#| Nil => true
#| Cons(head, tail) => if f(head) { continue tail } else { false }
#| } }
),
),
"any": build(
(
#|pub fn[A] any(self : T[A], f : (A) -> Bool raise?) -> Bool raise? { match self {
#| Nil => false
#| Cons(head, tail) => f(head) || tail.any(f)
#| } }
),
),
"tail": build(
(
#|pub fn[A] tail(self : T[A]) -> T[A] { match self {
#| Nil => Nil
#| Cons(_, tail) => tail
#| } }
),
),
"unsafe_head": build(
(
#|pub fn[A] unsafe_head(self : T[A]) -> A { match self {
#| Nil => abort(\"head of empty list\")
#| Cons(head, _) => head
#| } }
),
),
"head_exn": build(
(
#|pub fn[A] head_exn(self : T[A]) -> A { self.unsafe_head() }
),
),
"head": build(
(
#|pub fn[A] head(self : T[A]) -> A? { match self {
#| Nil => None
#| Cons(head, _) => Some(head)
#| } }
),
),
"unsafe_last": build(
(
#|pub fn[A] unsafe_last(self : T[A]) -> A { loop self {
#| Nil => abort(\"last of empty list\")
#| Cons(head, Nil) => head
#| Cons(_, tail) => continue tail
#| } }
),
),
"last": build(
(
#|pub fn[A] last(self : T[A]) -> A? { loop self {
#| Nil => None
#| Cons(head, Nil) => Some(head)
#| Cons(_, tail) => continue tail
#| } }
),
),
"concat": build(
(
#|pub fn[A] concat(self : T[A], other : T[A]) -> T[A] { match self {
#| Nil => other
#| Cons(head, tail) => Cons(head, tail.concat(other))
#| } }
),
),
"rev_concat": build(
(
#|pub fn[A] rev_concat(self : T[A], other : T[A]) -> T[A] { loop (self, other) {
#| (Nil, other) => other
#| (Cons(head, tail), other) => continue (tail, Cons(head, other))
#| } }
),
),
"rev": build(
(
#|pub fn[A] rev(self : T[A]) -> T[A] { self.rev_concat(Nil) }
),
),
"fold": build(
(
#|pub fn[A, B] fold(self : T[A], init~ : B, f : (B, A) -> B raise?) -> B raise? { match self {
#| Nil => init
#| Cons(head, tail) => tail.fold(f, init=f(init, head))
#| } }
),
),
"zip": build(
(
#|pub fn[A, B] zip(self : T[A], other : T[B]) -> T[(A, B)]? { let mut acc = Nil
#| let res = loop (self, other) {
#| (Nil, Nil) => break Some(acc)
#| (Cons(x, xs), Cons(y, ys)) => {
#| acc = Cons((x, y), acc)
#| continue (xs, ys)
#| }
#| (_, _) => break None
#| }
#| res.map(T::rev) }
),
),
"concat_map": build(
(
#|pub fn[A, B] concat_map(self : T[A], f : (A) -> T[B]) -> T[B] { self.flat_map(f) }
),
),
"flat_map": build(
(
#|pub fn[A, B] flat_map(self : T[A], f : (A) -> T[B] raise?) -> T[B] raise? { match self {
#| Nil => Nil
#| Cons(head, tail) => f(head).concat(tail.flat_map(f))
#| } }
),
),
"filter_map": build(
(
#|pub fn[A, B] filter_map(self : T[A], f : (A) -> B?) -> T[B] { loop (Nil, self) {
#| (acc, Nil) => acc.rev()
#| (acc, Cons(x, xs)) =>
#| match f(x) {
#| Some(v) => continue (acc.add(v), xs)
#| None => continue (acc, xs)
#| }
#| } }
),
),
"unsafe_nth": build(
(
#|pub fn[A] unsafe_nth(self : T[A], n : Int) -> A { loop (self, n) {
#| (Nil, _) => abort(\"nth: index out of bounds\")
#| (Cons(head, _), 0) => head
#| (Cons(_, tail), n) => continue (tail, n - 1)
#| } }
),
),
"nth_exn": build(
(
#|pub fn[A] nth_exn(self : T[A], n : Int) -> A { self.unsafe_nth(n) }
),
),
"nth": build(
(
#|pub fn[A] nth(self : T[A], n : Int) -> A? { loop (self, n) {
#| (Nil, _) => None
#| (Cons(head, _), 0) => Some(head)
#| (Cons(_, tail), n) => continue (tail, n - 1)
#| } }
),
),
"repeat": build(
(
#|pub fn[A] repeat(n : Int, x : A) -> T[A] { if n == 0 {
#| Nil
#| } else {
#| Cons(x, repeat(n - 1, x))
#| } }
),
),
"intersperse": build(
(
#|pub fn[A] intersperse(self : T[A], separator : A) -> T[A] { match self {
#| Nil => Nil
#| Cons(head, Nil) => Cons(head, Nil)
#| Cons(head, tail) => Cons(head, Cons(separator, tail.intersperse(separator)))
#| } }
),
),
"is_empty": build(
(
#|pub fn[A] is_empty(self : T[A]) -> Bool { self is Nil }
),
),
"unzip": build(
(
#|pub fn[A, B] unzip(self : T[(A, B)]) -> (T[A], T[B]) { let mut xs = Nil
#| let mut ys = Nil
#| // implemented with loop to avoid stack overflow
#| loop self.rev() {
#| Nil => break (xs, ys)
#| Cons((x, y), tail) => {
#| xs = Cons(x, xs)
#| ys = Cons(y, ys)
#| continue tail
#| }
#| } }
),
),
"flatten": build(
(
#|pub fn[A] flatten(self : T[T[A]]) -> T[A] { match self {
#| Nil => Nil
#| Cons(head, tail) => head.concat(tail.flatten())
#| } }
),
),
"unsafe_maximum": build(
(
#|pub fn[A : Compare] unsafe_maximum(self : T[A]) -> A { match self {
#| Nil => abort(\"maximum: empty list\")
#| Cons(x, Nil) => x
#| Cons(x, xs) => {
#| let y = xs.unsafe_maximum()
#| if x > y {
#| x
#| } else {
#| y
#| }
#| }
#| } }
),
),
"maximum": build(
(
#|pub fn[A : Compare] maximum(self : T[A]) -> A? { match self {
#| Nil => None
#| Cons(x, Nil) => Some(x)
#| Cons(x, xs) =>
#| match xs.maximum() {
#| None => Some(x)
#| Some(y) => Some(if x > y { x } else { y })
#| }
#| } }
),
),
"unsafe_minimum": build(
(
#|pub fn[A : Compare] unsafe_minimum(self : T[A]) -> A { match self {
#| Nil => abort(\"minimum: empty list\")
#| Cons(x, Nil) => x
#| Cons(x, xs) => {
#| let y = xs.unsafe_minimum()
#| if x < y {
#| x
#| } else {
#| y
#| }
#| }
#| } }
),
),
"minimum": build(
(
#|pub fn[A : Compare] minimum(self : T[A]) -> A? { match self {
#| Nil => None
#| Cons(x, Nil) => Some(x)
#| Cons(x, xs) =>
#| match xs.minimum() {
#| None => Some(x)
#| Some(y) => Some(if x < y { x } else { y })
#| }
#| } }
),
),
"sort": build(
(
#|pub fn[A : Compare] sort(self : T[A]) -> T[A] { match self {
#| Nil => Nil
#| Cons(x, xs) => {
#| let smaller = xs.filter(y => y < x)
#| let greater = xs.filter(y => y >= x)
#| smaller.sort().concat(Cons(x, greater.sort()))
#| }
#| } }
),
),
"contains": build(
(
#|pub fn[A : Eq] contains(self : T[A], value : A) -> Bool { loop self {
#| Nil => false
#| Cons(x, xs) => if x == value { true } else { continue xs }
#| } }
),
),
"unfold": build(
(
#|pub fn[A, S] unfold(f : (S) -> (A, S)? raise?, init~ : S) -> T[A] raise? { match f(init) {
#| Some((element, new_state)) => Cons(element, unfold(init=new_state, f))
#| None => Nil
#| } }
),
),
"take": build(
(
#|pub fn[A] take(self : T[A], n : Int) -> T[A] { fn go(n, t) {
#| match (n, t) {
#| (_, Nil) => Nil
#| (1, Cons(x, _)) => Cons(x, Nil)
#| (n, Cons(x, xs)) => Cons(x, go(n - 1, xs))
#| }
#| }
#| if n <= 0 {
#| Nil
#| } else {
#| go(n, self)
#| } }
),
),
"drop": build(
(
#|pub fn[A] drop(self : T[A], n : Int) -> T[A] { if n <= 0 {
#| self
#| } else {
#| loop (n, self) {
#| (_, Nil) => Nil
#| (1, Cons(_, xs)) => xs
#| (n, Cons(_, xs)) => continue (n - 1, xs)
#| }
#| } }
),
),
"take_while": build(
(
#|pub fn[A] take_while(self : T[A], p : (A) -> Bool) -> T[A] { match self {
#| Nil => Nil
#| Cons(x, xs) => if p(x) { Cons(x, xs.take_while(p)) } else { Nil }
#| } }
),
),
"drop_while": build(
(
#|pub fn[A] drop_while(self : T[A], p : (A) -> Bool raise?) -> T[A] raise? { loop self {
#| Nil => Nil
#| Cons(x, xs) => if p(x) { continue xs } else { Cons(x, xs) }
#| } }
),
),
"lookup": build(
(
#|pub fn[A : Eq, B] lookup(self : T[(A, B)], v : A) -> B? { loop self {
#| Nil => None
#| Cons((x, y), xs) => if x == v { Some(y) } else { continue xs }
#| } }
),
),
"find": build(
(
#|pub fn[A] find(self : T[A], f : (A) -> Bool raise?) -> A? raise? { loop self {
#| Nil => None
#| Cons(element, list) =>
#| if f(element) {
#| Some(element)
#| } else {
#| continue list
#| }
#| } }
),
),
"findi": build(
(
#|pub fn[A] findi(self : T[A], f : (A, Int) -> Bool raise?) -> A? raise? { loop (self, 0) {
#| (list, index) =>
#| match list {
#| Nil => None
#| Cons(element, list) =>
#| if f(element, index) {
#| Some(element)
#| } else {
#| continue (list, index + 1)
#| }
#| }
#| } }
),
),
"remove_at": build(
(
#|pub fn[A] remove_at(self : T[A], index : Int) -> T[A] { match (index, self) {
#| (0, Cons(_, tail)) => tail
#| (_, Cons(head, tail)) => Cons(head, tail.remove_at(index - 1))
#| (_, Nil) => Nil
#| // abort(\"remove_at: index out of bounds\")
#| } }
),
),
"remove": build(
(
#|pub fn[A : Eq] remove(self : T[A], elem : A) -> T[A] { match self {
#| Nil => Nil
#| Cons(head, tail) =>
#| if head == elem {
#| tail
#| } else {
#| Cons(head, tail.remove(elem))
#| }
#| } }
),
),
"is_prefix": build(
(
#|pub fn[A : Eq] is_prefix(self : T[A], prefix : T[A]) -> Bool { loop (self, prefix) {
#| (_, Nil) => true
#| (Nil, Cons(_)) => false
#| (Cons(h1, t1), Cons(h2, t2)) =>
#| if h1 == h2 {
#| continue (t1, t2)
#| } else {
#| false
#| }
#| } }
),
),
"is_suffix": build(
(
#|pub fn[A : Eq] is_suffix(self : T[A], suffix : T[A]) -> Bool { self.rev().is_prefix(suffix.rev()) }
),
),
"intercalate": build(
(
#|pub fn[A] intercalate(self : T[T[A]], sep : T[A]) -> T[A] { self.intersperse(sep).flatten() }
),
),
"default": build(
(
#|pub fn[X] default() -> T[X] { Nil }
),
),
"iter": build(
(
#|pub fn[A] iter(self : T[A]) -> Iter[A] { Iter::new(yield_ => loop self {
#| Nil => IterContinue
#| Cons(head, tail) => {
#| if yield_(head) == IterEnd {
#| break IterEnd
#| }
#| continue tail
#| }
#| }) }
),
),
"iter2": build(
(
#|pub fn[A] iter2(self : T[A]) -> Iter2[Int, A] { Iter2::new(yield_ => loop (self, 0) {
#| (Nil, _) => IterEnd
#| (Cons(head, tail), i) => {
#| if yield_(i, head) == IterEnd {
#| break IterEnd
#| }
#| continue (tail, i + 1)
#| }
#| }) }
),
),
"from_iter": build(
(
#|pub fn[A] from_iter(iter : Iter[A]) -> T[A] { iter.fold(init=Nil, (acc, e) => Cons(e, acc)).rev() }
),
),
"from_iter_rev": build(
(
#|pub fn[A] from_iter_rev(iter : Iter[A]) -> T[A] { iter.fold(init=Nil, (acc, e) => Cons(e, acc)) }
),
),
"of": build(
(
#|pub fn[A] of(arr : FixedArray[A]) -> T[A] { for i = arr.length() - 1, list = Nil; i >= 0; {
#| continue i - 1, Cons(arr[i], list)
#| } else {
#| list
#| } }
),
),
"singleton": build(
(
#|pub fn[A] singleton(x : A) -> T[A] { Cons(x, Nil) }
),
),
"init_": build(
(
#|pub fn[A] init_(self : T[A]) -> T[A] { fn aux(self) {
#| match self {
#| Nil => Nil
#| Cons(_, Nil) => Nil
#| Cons(head, tail) => Cons(head, aux(tail))
#| }
#| }
#| aux(self) }
),
),
"equal": build(
(
#|pub fn[A : Eq] equal(self : T[A], other : T[A]) -> Bool { loop (self, other) {
#| (Nil, Nil) => true
#| (Cons(h, t), Cons(h1, t1)) => if h == h1 { continue (t, t1) } else { false }
#| (_, _) => false
#| } }
),
),
"from_array": build(
(
#|pub fn[A] T::from_array(arr : Array[A]) -> T[A] { from_array(arr) }
),
),
"default": build(
(
#|pub fn[X] T::default() -> T[X] { Nil }
),
),
"from_iter": build(
(
#|pub fn[A] T::from_iter(iter : Iter[A]) -> T[A] { from_iter(iter) }
),
),
"of": build(
(
#|pub fn[A] T::of(arr : FixedArray[A]) -> T[A] { of(arr) }
),
),
}
},
)
///|
let moonbitlang_core_immut_priority_queue_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/immut/priority_queue",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
},
fn(_env, build) {
{
"new": build(
(
#|pub fn[A] new() -> T[A] { { node: Empty, size: 0 } }
),
),
"from_array": build(
(
#|pub fn[A : Compare] from_array(array : Array[A]) -> T[A] { let mut pq = new()
#| for i in 0.. Array[A] { let arr : Array[A] = []
#| fn go(x : Node[A]) {
#| match x {
#| Empty => return
#| Leaf(a) => arr.push(a)
#| Branch(a, left=l, right=r) => {
#| arr.push(a)
#| go(l)
#| go(r)
#| }
#| }
#| }
#| go(self.node)
#| arr.sort_by((x, y) => y.compare(x))
#| arr }
),
),
"iter": build(
(
#|pub fn[A : Compare] iter(self : T[A]) -> Iter[A] { Iter::new(yield_ => {
#| let arr = self.to_array()
#| for i in 0.. T[A] { iter.fold(init=new(), (s, e) => s.push(e)) }
),
),
"path": build(
(
#|fn path(size : Int) -> Path { loop (size, 0) {
#| (1, y) => Path(y)
#| (x, y) => continue (x >> 1, (y << 1) | (x & 1))
#| } }
),
),
"is_left": build(
(
#|fn is_left(self : Path) -> Bool { (self.0 & 1) == 0 }
),
),
"next": build(
(
#|fn next(self : Path) -> Path { Path(self.0 >> 1) }
),
),
"pop": build(
(
#|pub fn[A : Compare] pop(self : T[A]) -> T[A]? { match self.node {
#| Empty => None
#| Leaf(_) => Some({ node: Empty, size: 0 })
#| Branch(_) => {
#| let (value, temp) = self.node.remove_last_leaf(path(self.size))
#| Some({ node: temp.change_and_down(value), size: self.size - 1 })
#| }
#| } }
),
),
"remove_last_leaf": build(
(
#|fn[A : Compare] remove_last_leaf(self : Node[A], path : Path) -> (A, Node[A]) { match self {
#| Empty => abort(\"Priority queue is empty!\")
#| Leaf(a) => (a, Empty)
#| Branch(a, left=Leaf(l_top), right=Empty) => (l_top, Leaf(a))
#| Branch(a, left=l, right=r) =>
#| if path.is_left() {
#| let (e, ld) = l.remove_last_leaf(path.next())
#| (e, Branch(a, left=ld, right=r))
#| } else {
#| let (e, rd) = r.remove_last_leaf(path.next())
#| (e, Branch(a, left=l, right=rd))
#| }
#| } }
),
),
"change_and_down": build(
(
#|fn[A : Compare] change_and_down(self : Node[A], value : A) -> Node[A] { match self {
#| Empty => abort(\"unreachable\")
#| Leaf(_) => Leaf(value)
#| Branch(_, left=l, right=r) =>
#| match (l, r) {
#| (Leaf(l_top), Empty) =>
#| if value >= l_top {
#| Branch(value, left=l, right=Empty)
#| } else {
#| Branch(l_top, left=Leaf(value), right=Empty)
#| }
#| (Branch(l_top, ..) | Leaf(l_top), Branch(r_top, ..) | Leaf(r_top)) =>
#| if value >= l_top && value >= r_top {
#| Branch(value, left=l, right=r)
#| } else if l_top >= r_top {
#| Branch(l_top, left=l.change_and_down(value), right=r)
#| } else {
#| Branch(r_top, left=l, right=r.change_and_down(value))
#| }
#| _ => abort(\"unreachable\")
#| }
#| } }
),
),
"unsafe_pop": build(
(
#|pub fn[A : Compare] unsafe_pop(self : T[A]) -> T[A] { match self.node {
#| Empty => abort(\"Priority queue is empty!\")
#| Leaf(_) => { node: Empty, size: 0 }
#| Branch(_) => {
#| let (value, temp) = self.node.remove_last_leaf(path(self.size))
#| { node: temp.change_and_down(value), size: self.size - 1 }
#| }
#| } }
),
),
"push": build(
(
#|pub fn[A : Compare] push(self : T[A], value : A) -> T[A] { match self.node {
#| Empty => { node: Leaf(value), size: 1 }
#| Leaf(_) | Branch(_) => {
#| let size = self.size + 1
#| { node: self.node.push(value, path(size)), size }
#| }
#| } }
),
),
"push": build(
(
#|fn[A : Compare] Node::push(self : Node[A], value : A, path : Path) -> Node[A] { match self {
#| Empty => Leaf(value)
#| Leaf(a) => {
#| let (high, low) = if a > value { (a, value) } else { (value, a) }
#| Branch(high, left=Leaf(low), right=Empty)
#| }
#| Branch(a, left=l, right=r) => {
#| let (high, low) = if a > value { (a, value) } else { (value, a) }
#| if path.is_left() {
#| Branch(high, left=l.push(low, path.next()), right=r)
#| } else {
#| Branch(high, left=l, right=r.push(low, path.next()))
#| }
#| }
#| } }
),
),
"peek": build(
(
#|pub fn[A] peek(self : T[A]) -> A? { match self.node {
#| Empty => None
#| Leaf(a) => Some(a)
#| Branch(a, ..) => Some(a)
#| } }
),
),
"is_empty": build(
(
#|pub fn[A] is_empty(self : T[A]) -> Bool { self.node is Empty }
),
),
"length": build(
(
#|pub fn[A] length(self : T[A]) -> Int { self.size }
),
),
"of": build(
(
#|pub fn[A : Compare] of(arr : FixedArray[A]) -> T[A] { let mut pq = new()
#| for i in 0.. T[A] { self.unsafe_pop() }
),
),
}
},
)
///|
let moonbitlang_core_immut_sorted_map_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/immut/sorted_map",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/tuple": moonbitlang_core_tuple_module,
"moonbitlang/core/string": moonbitlang_core_string_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
},
fn(_env, build) {
{
"add": build(
(
#|pub fn[K : Compare, V] add(self : T[K, V], key : K, value : V) -> T[K, V] { match self {
#| Empty => singleton(key, value)
#| Tree(k, value=v, l, r, ..) => {
#| let c = key.compare(k)
#| if c == 0 {
#| make_tree(k, value, l, r)
#| } else if c < 0 {
#| balance(k, v, l.add(key, value), r)
#| } else {
#| balance(k, v, l, r.add(key, value))
#| }
#| }
#| } }
),
),
"split_max": build(
(
#|fn[K : Compare, V] split_max(self : T[K, V]) -> (K, V, T[K, V]) { match self {
#| Tree(k, value=v, l, Empty, ..) => (k, v, l)
#| Tree(k, value=v, l, r, ..) => {
#| let (k1, v1, r) = r.split_max()
#| (k1, v1, balance(k, v, l, r))
#| }
#| Empty => abort(\"Map::split_max error\")
#| } }
),
),
"split_min": build(
(
#|fn[K : Compare, V] split_min(self : T[K, V]) -> (K, V, T[K, V]) { match self {
#| Tree(k, value=v, Empty, r, ..) => (k, v, r)
#| Tree(k, value=v, l, r, ..) => {
#| let (k1, v1, l) = l.split_min()
#| (k1, v1, balance(k, v, l, r))
#| }
#| Empty => abort(\"Map::split_min error\")
#| } }
),
),
"glue": build(
(
#|fn[K : Compare, V] glue(l : T[K, V], r : T[K, V]) -> T[K, V] { match (l, r) {
#| (Empty, r) => r
#| (l, Empty) => l
#| (l, r) =>
#| if l.size() > r.size() {
#| let (k, v, l) = l.split_max()
#| balance(k, v, l, r)
#| } else {
#| let (k, v, r) = r.split_min()
#| balance(k, v, l, r)
#| }
#| } }
),
),
"remove": build(
(
#|pub fn[K : Compare, V] remove(self : T[K, V], key : K) -> T[K, V] { match self {
#| Empty => Empty
#| Tree(k, value=v, l, r, ..) => {
#| let c = key.compare(k)
#| if c == 0 {
#| glue(l, r)
#| } else if c < 0 {
#| balance(k, v, l.remove(key), r)
#| } else {
#| balance(k, v, l, r.remove(key))
#| }
#| }
#| } }
),
),
"to_array": build(
(
#|pub fn[K, V] to_array(self : T[K, V]) -> Array[(K, V)] { let arr = []
#| self.each((k, v) => arr.push((k, v)))
#| arr }
),
),
"ratio": (None, Int(5)),
"balance": build(
(
#|fn[K, V] balance(key : K, value : V, l : T[K, V], r : T[K, V]) -> T[K, V] { // 1 2
#| // / \\ / \\
#| // x 2 ---> 1 z
#| // / \\ / \\
#| // y z x y
#| fn single_l(k1, v1, x, r) {
#| guard r is Tree(k2, value=v2, y, z, ..)
#| make_tree(k2, v2, make_tree(k1, v1, x, y), z)
#| }
#| fn single_r(k2, v2, l, z) {
#| guard l is Tree(k1, value=v1, x, y, ..)
#| make_tree(k1, v1, x, make_tree(k2, v2, y, z))
#| }
#| // 1 2
#| // / \\ / \\
#| // x 3 1 3
#| // / \\ --> / \\ / \\
#| // 2 z x y1 y2 z
#| // / \\
#| // y1 y2
#| fn double_l(k1, v1, x, r) {
#| guard r is Tree(k3, value=v3, Tree(k2, value=v2, y1, y2, ..), z, ..)
#| make_tree(k2, v2, make_tree(k1, v1, x, y1), make_tree(k3, v3, y2, z))
#| }
#| // 3 2
#| // / \\ / \\
#| // 1 z 1 3
#| // / \\ --> / \\ / \\
#| // x 2 x y1 y2 z
#| // / \\
#| // y1 y2
#| fn double_r(k3, v3, l, z) {
#| guard l is Tree(k1, value=v1, x, Tree(k2, value=v2, y1, y2, ..), ..)
#| make_tree(k2, v2, make_tree(k1, v1, x, y1), make_tree(k3, v3, y2, z))
#| }
#| let ln = l.size()
#| let rn = r.size()
#| if ln + rn < 2 {
#| make_tree(key, value, l, r)
#| } else if rn > ratio * ln {
#| // right is too big
#| guard r is Tree(_, rl, rr, ..)
#| let rln = rl.size()
#| let rrn = rr.size()
#| if rln < rrn {
#| single_l(key, value, l, r)
#| } else {
#| double_l(key, value, l, r)
#| }
#| } else if ln > ratio * rn {
#| // left is too big
#| guard l is Tree(_, ll, lr, ..)
#| let lln = ll.size()
#| let lrn = lr.size()
#| if lrn < lln {
#| single_r(key, value, l, r)
#| } else {
#| double_r(key, value, l, r)
#| }
#| } else {
#| make_tree(key, value, l, r)
#| } }
),
),
"insert": build(
(
#|pub fn[K : Compare, V] insert(self : T[K, V], key : K, value : V) -> T[K, V] { self.add(key, value) }
),
),
"new": build(
(
#|pub fn[K, V] T::new() -> T[K, V] { Empty }
),
),
"singleton": build(
(
#|pub fn[K, V] T::singleton(key : K, value : V) -> T[K, V] { singleton(key, value) }
),
),
"from_array": build(
(
#|pub fn[K : Compare, V] T::from_array(array : Array[(K, V)]) -> T[K, V] { from_array(array) }
),
),
"from_iter": build(
(
#|pub fn[K : Compare, V] T::from_iter(iter : Iter[(K, V)]) -> T[K, V] { from_iter(iter) }
),
),
"of": build(
(
#|pub fn[K : Compare, V] T::of(array : FixedArray[(K, V)]) -> T[K, V] { of(array) }
),
),
"empty": build(
(
#|pub fn[K, V] T::empty() -> T[K, V] { Empty }
),
),
"new": build(
(
#|pub fn[K, V] new() -> T[K, V] { Empty }
),
),
"singleton": build(
(
#|pub fn[K, V] singleton(key : K, value : V) -> T[K, V] { Tree(key, value~, size=1, Empty, Empty) }
),
),
"contains": build(
(
#|pub fn[K : Compare, V] contains(self : T[K, V], key : K) -> Bool { loop self {
#| Empty => false
#| Tree(k, l, r, ..) => {
#| let c = key.compare(k)
#| if c == 0 {
#| true
#| } else if c < 0 {
#| continue l
#| } else {
#| continue r
#| }
#| }
#| } }
),
),
"size": build(
(
#|pub fn[K, V] size(self : T[K, V]) -> Int { match self {
#| Empty => 0
#| Tree(_) as t => t.size
#| } }
),
),
"is_empty": build(
(
#|pub fn[K, V] is_empty(self : T[K, V]) -> Bool { self.size() == 0 }
),
),
"make_tree": build(
(
#|fn[K, V] make_tree(key : K, value : V, l : T[K, V], r : T[K, V]) -> T[K, V] { let size = l.size() + r.size() + 1
#| Tree(key, value~, size~, l, r) }
),
),
"lookup": build(
(
#|pub fn[K : Compare, V] lookup(self : T[K, V], key : K) -> V? { self.get(key) }
),
),
"get": build(
(
#|pub fn[K : Compare, V] get(self : T[K, V], key : K) -> V? { loop self {
#| Empty => None
#| Tree(k, value~, l, r, ..) => {
#| let c = key.compare(k)
#| if c == 0 {
#| Some(value)
#| } else if c < 0 {
#| continue l
#| } else {
#| continue r
#| }
#| }
#| } }
),
),
"op_get": build(
(
#|pub fn[K : Compare, V] op_get(self : T[K, V], key : K) -> V? { self.get(key) }
),
),
"each": build(
(
#|pub fn[K, V] each(self : T[K, V], f : (K, V) -> Unit) -> Unit { match self {
#| Empty => ()
#| Tree(k, value~, l, r, ..) => {
#| l.each(f)
#| f(k, value)
#| r.each(f)
#| }
#| } }
),
),
"eachi": build(
(
#|pub fn[K, V] eachi(self : T[K, V], f : (Int, K, V) -> Unit) -> Unit { fn do_eachi(m : T[K, V], f, i) {
#| match m {
#| Empty => ()
#| Tree(k, value~, l, r, ..) => {
#| do_eachi(l, f, i)
#| f(l.size() + i, k, value)
#| do_eachi(r, f, l.size() + i + 1)
#| }
#| }
#| }
#| do_eachi(self, f, 0) }
),
),
"map": build(
(
#|pub fn[K, X, Y] map(self : T[K, X], f : (X) -> Y) -> T[K, Y] { match self {
#| Empty => Empty
#| Tree(k, value~, size~, l, r) =>
#| Tree(k, value=f(value), size~, l.map(f), r.map(f))
#| } }
),
),
"map_with_key": build(
(
#|pub fn[K, X, Y] map_with_key(self : T[K, X], f : (K, X) -> Y) -> T[K, Y] { match self {
#| Empty => Empty
#| Tree(k, value~, l, r, size~) =>
#| Tree(k, value=f(k, value), size~, l.map_with_key(f), r.map_with_key(f))
#| } }
),
),
"fold": build(
(
#|pub fn[K, V, A] fold(self : T[K, V], init~ : A, f : (A, V) -> A) -> A { self.foldl_with_key((acc, _k, v) => f(acc, v), init~) }
),
),
"debug_tree": build(
(
#|fn[K : Show, V : Show] debug_tree(self : T[K, V]) -> String { match self {
#| Empty => \"_\"
#| Tree(k, value~, l, r, ..) => {
#| let l = l.debug_tree()
#| let r = r.debug_tree()
#| \"(\\{k},\\{value},\\{l},\\{r})\"
#| }
#| } }
),
),
"from_array": build(
(
#|pub fn[K : Compare, V] from_array(array : Array[(K, V)]) -> T[K, V] { for i = 0, mp = Empty; i < array.length(); {
#| let (k, v) = array[i]
#| continue i + 1, mp.add(k, v)
#| } else {
#| mp
#| } }
),
),
"iter": build(
(
#|pub fn[K, V] iter(self : T[K, V]) -> Iter[(K, V)] { Iter::new(yield_ => {
#| fn go(t) {
#| match t {
#| Empty => IterContinue
#| Tree(k, value~, l, r, ..) =>
#| if go(l) is IterEnd {
#| IterEnd
#| } else if yield_((k, value)) is IterEnd {
#| IterEnd
#| } else {
#| go(r)
#| }
#| }
#| }
#| go(self)
#| }) }
),
),
"iter2": build(
(
#|pub fn[K, V] iter2(self : T[K, V]) -> Iter2[K, V] { Iter2::new(yield_ => {
#| fn go(t) {
#| match t {
#| Empty => IterContinue
#| Tree(k, value~, l, r, ..) =>
#| if go(l) is IterEnd {
#| IterEnd
#| } else if yield_(k, value) is IterEnd {
#| IterEnd
#| } else {
#| go(r)
#| }
#| }
#| }
#| go(self)
#| }) }
),
),
"from_iter": build(
(
#|pub fn[K : Compare, V] from_iter(iter : Iter[(K, V)]) -> T[K, V] { iter.fold(init=new(), (m, e) => m.add(e.0, e.1)) }
),
),
"keys": build(
(
#|pub fn[K, V] keys(self : T[K, V]) -> Array[K] { self.iter().map(p => p.0).collect() }
),
),
"values": build(
(
#|pub fn[K, V] values(self : T[K, V]) -> Iter[V] { self.iter().map(p => p.1) }
),
),
"elems": build(
(
#|pub fn[K, V] elems(self : T[K, V]) -> Array[V] { self.values().collect() }
),
),
"of": build(
(
#|pub fn[K : Compare, V] of(array : FixedArray[(K, V)]) -> T[K, V] { for i = 0, mp = Empty; i < array.length(); {
#| let (k, v) = array[i]
#| continue i + 1, mp.add(k, v)
#| } else {
#| mp
#| } }
),
),
"to_json": build(
(
#|pub fn[K : Show, V : ToJson] to_json(self : T[K, V]) -> Json { ToJson::to_json(self) }
),
),
"T": build(
(
#|enum T[K, V] {
#| Empty
#| Tree(K, value~ : V, size~ : Int, T[K, V], T[K, V])
#|}
),
),
"new": build(
(
#|fn[K, V] InorderIterator::new(root : T[K, V]) -> InorderIterator[K, V] { let it = InorderIterator([])
#| it.move_left(root)
#| it }
),
),
"next": build(
(
#|fn[K, V] InorderIterator::next(self : InorderIterator[K, V]) -> (K, V)? { let InorderIterator(s) = self
#| guard s.pop() is Some(curr) else { return None }
#| guard curr is Tree(key, _, right, value~, ..)
#| self.move_left(right)
#| Some((key, value)) }
),
),
}
},
)
///|
let moonbitlang_core_immut_sorted_set_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/immut/sorted_set",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
},
fn(_env, build) {
{
"new": build(
(
#|pub fn[A] T::new() -> T[A] { Empty }
),
),
"singleton": build(
(
#|pub fn[A] T::singleton(value : A) -> T[A] { singleton(value) }
),
),
"from_array": build(
(
#|pub fn[A : Compare] T::from_array(array : Array[A]) -> T[A] { from_array(array) }
),
),
"of": build(
(
#|pub fn[A : Compare] T::of(array : FixedArray[A]) -> T[A] { of(array) }
),
),
"T": build(
(
#|enum T[A] {
#| Empty
#| Node(left~ : T[A], right~ : T[A], size~ : Int, value~ : A)
#|}
),
),
"iter": build(
(
#|pub fn[A] iter(self : T[A]) -> Iter[A] { Iter::new(yield_ => {
#| fn go(t) {
#| match t {
#| Empty => IterContinue
#| Node(left~, right~, value~, ..) =>
#| if go(left) is IterEnd {
#| IterEnd
#| } else if yield_(value) is IterEnd {
#| IterEnd
#| } else {
#| go(right)
#| }
#| }
#| }
#| go(self)
#| }) }
),
),
"from_iter": build(
(
#|pub fn[A : Compare] from_iter(iter : Iter[A]) -> T[A] { iter.fold(init=new(), (s, e) => s.add(e)) }
),
),
"from_iter": build(
(
#|pub fn[A : Compare] T::from_iter(iter : Iter[A]) -> T[A] { from_iter(iter) }
),
),
"new": build(
(
#|fn[A] InorderIterator::new(root : T[A]) -> InorderIterator[A] { let it = InorderIterator([])
#| it.move_left(root)
#| it }
),
),
"next": build(
(
#|fn[A] InorderIterator::next(self : InorderIterator[A]) -> A? { let InorderIterator(s) = self
#| guard s.pop() is Some(curr) else { return None }
#| guard curr is Node(right~, value~, ..)
#| self.move_left(right)
#| Some(value) }
),
),
"new": build(
(
#|pub fn[A] new() -> T[A] { Empty }
),
),
"singleton": build(
(
#|pub fn[A] singleton(value : A) -> T[A] { Node(left=Empty, value~, right=Empty, size=1) }
),
),
"from_array": build(
(
#|pub fn[A : Compare] from_array(array : Array[A]) -> T[A] { for i = array.length() - 1, set = Empty; i >= 0; {
#| continue i - 1, set.add(array[i])
#| } else {
#| set
#| } }
),
),
"to_array": build(
(
#|pub fn[A] to_array(self : T[A]) -> Array[A] { let arr = []
#| fn aux(set : T[A]) {
#| match set {
#| Empty => ()
#| Node(left~, value~, right~, ..) => {
#| aux(left)
#| arr.push(value)
#| aux(right)
#| //TODO: rewrite [...aux(left),value,...aux(right)]
#| }
#| }
#| }
#| aux(self)
#| arr }
),
),
"remove_min": build(
(
#|pub fn[A : Compare] remove_min(self : T[A]) -> T[A] { match self {
#| Empty => abort(\"remove_min: empty ImmutableSet\")
#| Node(left~, right~, value~, ..) =>
#| if left is Empty {
#| right
#| } else {
#| balance(left.remove_min(), value, right)
#| }
#| } }
),
),
"add": build(
(
#|pub fn[A : Compare] add(self : T[A], value : A) -> T[A] { match self {
#| Empty => Node(left=Empty, value~, right=Empty, size=1)
#| Node(left~, right~, value=node_value, ..) => {
#| let compare_result = value.compare(node_value)
#| if compare_result == 0 {
#| self
#| } else if compare_result < 0 {
#| let ll = left.add(value)
#| if physical_equal(left, ll) {
#| self
#| } else {
#| balance(ll, node_value, right)
#| }
#| } else {
#| let rr = right.add(value)
#| if physical_equal(right, rr) {
#| self
#| } else {
#| balance(left, node_value, rr)
#| }
#| }
#| }
#| } }
),
),
"remove": build(
(
#|pub fn[A : Compare] remove(self : T[A], value : A) -> T[A] { match self {
#| Empty => Empty
#| Node(left~, right~, value=node_value, ..) => {
#| let compare_result = value.compare(node_value)
#| if compare_result == 0 {
#| left.merge(right)
#| } else if compare_result < 0 {
#| let new_left = left.remove(value)
#| if physical_equal(left, new_left) {
#| self
#| } else {
#| balance(new_left, node_value, right)
#| }
#| } else {
#| let new_right = right.remove(value)
#| if physical_equal(right, new_right) {
#| self
#| } else {
#| balance(left, node_value, new_right)
#| }
#| }
#| }
#| } }
),
),
"min": build(
(
#|pub fn[A : Compare] min(self : T[A]) -> A { match self {
#| Empty => abort(\"min: there are no values in sorted_set.\")
#| Node(left~, value~, ..) => if left is Empty { value } else { left.min() }
#| } }
),
),
"min_option": build(
(
#|pub fn[A : Compare] min_option(self : T[A]) -> A? { match self {
#| Empty => None
#| Node(left~, value~, ..) =>
#| if left is Empty {
#| Some(value)
#| } else {
#| left.min_option()
#| }
#| } }
),
),
"max": build(
(
#|pub fn[A : Compare] max(self : T[A]) -> A { match self {
#| Empty => abort(\"max: there are no values in ImmutableSet.\")
#| Node(right~, value~, ..) => if right is Empty { value } else { right.max() }
#| } }
),
),
"max_option": build(
(
#|pub fn[A : Compare] max_option(self : T[A]) -> A? { match self {
#| Empty => None
#| Node(right~, value~, ..) =>
#| if right is Empty {
#| Some(value)
#| } else {
#| right.max_option()
#| }
#| } }
),
),
"split": build(
(
#|pub fn[A : Compare] split(self : T[A], divide : A) -> (T[A], Bool, T[A]) { match self {
#| Empty => (Empty, false, Empty)
#| Node(left~, right~, value~, ..) => {
#| let compare_result = divide.compare(value)
#| if compare_result == 0 {
#| (left, true, right)
#| } else if compare_result < 0 {
#| let (left_left, present, right_left) = left.split(divide)
#| (left_left, present, join(right_left, value, right))
#| } else {
#| let (left_right, present, right_right) = right.split(divide)
#| (join(left, value, left_right), present, right_right)
#| }
#| }
#| } }
),
),
"is_empty": build(
(
#|pub fn[A] is_empty(self : T[A]) -> Bool { self is Empty }
),
),
"contains": build(
(
#|pub fn[A : Compare] contains(self : T[A], value : A) -> Bool { match self {
#| Empty => false
#| Node(left~, right~, value=node_value, ..) => {
#| let compare_result = value.compare(node_value)
#| compare_result == 0 ||
#| (if compare_result < 0 { left } else { right }).contains(value)
#| }
#| } }
),
),
"union": build(
(
#|pub fn[A : Compare] union(self : T[A], other : T[A]) -> T[A] { match (self, other) {
#| (Empty, _) => other
#| (_, Empty) => self
#| (
#| Node(left=l1, value=v1, right=r1, size=s1),
#| Node(left=l2, value=v2, right=r2, size=s2),
#| ) =>
#| if s1 >= s2 {
#| if s2 == 1 {
#| self.add(v2)
#| } else {
#| let (l2, _, r2) = other.split(v1)
#| join(l1.union(l2), v1, r1.union(r2))
#| }
#| } else if s1 == 1 {
#| other.add(v1)
#| } else {
#| let (l1, _, r1) = self.split(v2)
#| join(l1.union(l2), v2, r1.union(r2))
#| }
#| } }
),
),
"inter": build(
(
#|pub fn[A : Compare] inter(self : T[A], other : T[A]) -> T[A] { self.intersection(other) }
),
),
"intersection": build(
(
#|pub fn[A : Compare] intersection(self : T[A], other : T[A]) -> T[A] { match (self, other) {
#| (Empty, _) | (_, Empty) => Empty
#| (Node(left=l1, value=v1, right=r1, ..), _) =>
#| match other.split(v1) {
#| (l2, false, r2) => l1.intersection(l2).concat(r1.intersection(r2))
#| (l2, true, r2) => join(l1.intersection(l2), v1, r1.intersection(r2))
#| }
#| } }
),
),
"diff": build(
(
#|pub fn[A : Compare] diff(self : T[A], other : T[A]) -> T[A] { self.difference(other) }
),
),
"difference": build(
(
#|pub fn[A : Compare] difference(self : T[A], other : T[A]) -> T[A] { match (self, other) {
#| (Empty, _) => Empty
#| (_, Empty) => self
#| (Node(left=l1, value=v1, right=r1, ..), _) =>
#| match other.split(v1) {
#| (l2, false, r2) => join(l1.difference(l2), v1, r1.difference(r2))
#| (l2, true, r2) => l1.difference(l2).concat(r1.difference(r2))
#| }
#| } }
),
),
"symmetric_difference": build(
(
#|pub fn[A : Compare] symmetric_difference(self : T[A], other : T[A]) -> T[A] { match (self, other) {
#| (Empty, _) => other
#| (_, Empty) => self
#| (Node(left=l1, value=v1, right=r1, ..), _) =>
#| match other.split(v1) {
#| (l2, false, r2) =>
#| join(l1.symmetric_difference(l2), v1, r1.symmetric_difference(r2))
#| (l2, true, r2) =>
#| l1.symmetric_difference(l2).concat(r1.symmetric_difference(r2))
#| }
#| } }
),
),
"subset": build(
(
#|pub fn[A : Compare] subset(self : T[A], other : T[A]) -> Bool { match (self, other) {
#| (Empty, _) => true
#| (_, Empty) => false
#| (
#| Node(left=l1, value=v1, right=r1, ..),
#| Node(left=l2, value=v2, right=r2, ..),
#| ) => {
#| let compare_result = v1.compare(v2)
#| if compare_result == 0 {
#| l1.subset(l2) && r1.subset(r2)
#| } else if compare_result < 0 {
#| Node(left=l1, value=v1, right=Empty, size=1).subset(l2) &&
#| r1.subset(self)
#| } else {
#| Node(left=Empty, value=v1, right=r1, size=1).subset(r2) &&
#| l1.subset(self)
#| }
#| }
#| } }
),
),
"disjoint": build(
(
#|pub fn[A : Compare] disjoint(self : T[A], other : T[A]) -> Bool { match (self, other) {
#| (Empty, _) | (_, Empty) => true
#| (Node(left=l1, value=v1, right=r1, ..), _) =>
#| if physical_equal(self, other) {
#| false
#| } else {
#| match other.split_bis(v1) {
#| NotFound(l2, r2) => l1.disjoint(l2) && r1.disjoint(r2())
#| Found => false
#| }
#| }
#| } }
),
),
"each": build(
(
#|pub fn[A] each(self : T[A], f : (A) -> Unit raise?) -> Unit raise? { match self {
#| Empty => ()
#| Node(left~, value~, right~, ..) => {
#| left.each(f)
#| f(value)
#| right.each(f)
#| }
#| } }
),
),
"all": build(
(
#|pub fn[A : Compare] all(self : T[A], f : (A) -> Bool raise?) -> Bool raise? { match self {
#| Empty => true
#| Node(left~, value~, right~, ..) => f(value) && left.all(f) && right.all(f)
#| } }
),
),
"any": build(
(
#|pub fn[A : Compare] any(self : T[A], f : (A) -> Bool raise?) -> Bool raise? { match self {
#| Empty => false
#| Node(left~, value~, right~, ..) => f(value) || left.any(f) || right.any(f)
#| } }
),
),
"filter": build(
(
#|pub fn[A : Compare] filter(self : T[A], f : (A) -> Bool raise?) -> T[A] raise? { match self {
#| Empty => Empty
#| Node(left~, value~, right~, ..) => {
#| let l = left.filter(f)
#| let v = f(value)
#| let r = right.filter(f)
#| if v {
#| if physical_equal(l, left) && physical_equal(r, right) {
#| self
#| } else {
#| join(l, value, r)
#| }
#| } else {
#| l.concat(r)
#| }
#| }
#| } }
),
),
"to_json": build(
(
#|pub fn[A : ToJson] to_json(self : T[A]) -> Json { ToJson::to_json(self) }
),
),
"split_bis": build(
(
#|fn[A : Compare] split_bis(self : T[A], value : A) -> SplitBis[A] { match self {
#| Empty => NotFound(Empty, () => Empty)
#| Node(left~, value=node_value, right~, ..) => {
#| let compare_result = value.compare(node_value)
#| if compare_result == 0 {
#| Found
#| } else if compare_result < 0 {
#| match left.split_bis(value) {
#| Found => Found
#| NotFound(ll, rl) => NotFound(ll, () => join(rl(), node_value, right))
#| }
#| } else {
#| match right.split_bis(value) {
#| Found => Found
#| NotFound(lr, rr) => NotFound(join(left, node_value, lr), rr)
#| }
#| }
#| }
#| } }
),
),
"size": build(
(
#|pub fn[A] size(self : T[A]) -> Int { match self {
#| Empty => 0
#| Node(size~, ..) => size
#| } }
),
),
"create": build(
(
#|fn[A] create(left : T[A], value : A, right : T[A]) -> T[A] { Node(left~, right~, value~, size=left.size() + right.size() + 1) }
),
),
"balance": build(
(
#|fn[A] balance(left : T[A], value : A, right : T[A]) -> T[A] { let left_size = left.size()
#| let right_size = right.size()
#| if left_size + right_size < 2 {
#| create(left, value, right)
#| } else if left_size > right_size * BALANCE_RATIO {
#| match left {
#| Empty => abort(\"balance: left is empty.\")
#| Node(left=ll, value=lv, right=lr, ..) =>
#| if ll.size() >= lr.size() {
#| create(ll, lv, create(lr, value, right))
#| } else {
#| match lr {
#| Empty => abort(\"balance: right left.right is empty.\")
#| Node(left=lrl, value=lrv, right=lrr, ..) =>
#| create(create(ll, lv, lrl), lrv, create(lrr, value, right))
#| }
#| }
#| }
#| } else if right_size > left_size * BALANCE_RATIO {
#| match right {
#| Empty => abort(\"balance: right is empty\")
#| Node(left=rl, value=rv, right=rr, ..) =>
#| if rr.size() >= rl.size() {
#| create(create(left, value, rl), rv, rr)
#| } else {
#| match rl {
#| Empty => abort(\"balance: right.left is empty\")
#| Node(left=rll, value=rlv, right=rlr, ..) =>
#| create(create(left, value, rll), rlv, create(rlr, rv, rr))
#| }
#| }
#| }
#| } else {
#| create(left, value, right)
#| } }
),
),
"add_min_value": build(
(
#|fn[A : Compare] add_min_value(self : T[A], value : A) -> T[A] { match self {
#| Empty => singleton(value)
#| Node(left~, value=node_value, right~, ..) =>
#| balance(left.add_min_value(value), node_value, right)
#| } }
),
),
"add_max_value": build(
(
#|fn[A : Compare] add_max_value(self : T[A], value : A) -> T[A] { match self {
#| Empty => singleton(value)
#| Node(left~, value=node_value, right~, ..) =>
#| balance(left, node_value, right.add_max_value(value))
#| } }
),
),
"join": build(
(
#|fn[A : Compare] join(left : T[A], value : A, right : T[A]) -> T[A] { match (left, right) {
#| (Empty, _) => right.add_min_value(value)
#| (_, Empty) => left.add_max_value(value)
#| (
#| Node(left=ll, value=lv, right=lr, size=ls),
#| Node(left=rl, value=rv, right=rr, size=rs),
#| ) =>
#| if ls > rs * BALANCE_RATIO {
#| balance(ll, lv, join(lr, value, right))
#| } else if rs > ls * BALANCE_RATIO {
#| balance(join(left, value, rl), rv, rr)
#| } else {
#| create(left, value, right)
#| }
#| } }
),
),
"try_join": build(
(
#|fn[A : Compare] try_join(left : T[A], value : A, right : T[A]) -> T[A] { if (left == Empty || left.max().compare(value) < 0) &&
#| (right == Empty || value.compare(right.min()) < 0) {
#| join(left, value, right)
#| } else {
#| left.union(right.add(value))
#| } }
),
),
"merge": build(
(
#|fn[A : Compare] merge(self : T[A], other : T[A]) -> T[A] { match (self, other) {
#| (Empty, _) => other
#| (_, Empty) => self
#| _ => balance(self, other.min(), other.remove_min())
#| } }
),
),
"concat": build(
(
#|fn[A : Compare] concat(self : T[A], other : T[A]) -> T[A] { match (self, other) {
#| (Empty, _) => other
#| (_, Empty) => self
#| _ => join(self, other.min(), other.remove_min())
#| } }
),
),
"of": build(
(
#|pub fn[A : Compare] of(array : FixedArray[A]) -> T[A] { for i = array.length() - 1, set = Empty; i >= 0; {
#| continue i - 1, set.add(array[i])
#| } else {
#| set
#| } }
),
),
}
},
)
///|
let moonbitlang_core_int_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/int",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/uint": moonbitlang_core_uint_module,
},
fn(_env, build) {
{
"max_value": (None, Int(2147483647)),
"min_value": (None, Int(-2147483648)),
"abs": build(
(
#|pub fn Int::abs(self : Int) -> Int { if self < 0 {
#| -self
#| } else {
#| self
#| } }
),
),
"to_be_bytes": build(
(
#|pub fn to_be_bytes(self : Int) -> Bytes { self.reinterpret_as_uint().to_be_bytes() }
),
),
"to_le_bytes": build(
(
#|pub fn to_le_bytes(self : Int) -> Bytes { self.reinterpret_as_uint().to_le_bytes() }
),
),
}
},
)
///|
let moonbitlang_core_int16_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/int16",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
},
fn(_env, build) {
{
"abs": build(
(
#|pub fn Int16::abs(self : Int16) -> Int16 { if self < 0 {
#| -self
#| } else {
#| self
#| } }
),
),
"reinterpret_as_uint16": build(
(
#|pub fn Int16::reinterpret_as_uint16(self : Int16) -> UInt16 { self.to_int().to_uint16() }
),
),
}
},
)
///|
let moonbitlang_core_int64_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/int64",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/bytes": moonbitlang_core_bytes_module,
"moonbitlang/core/uint": moonbitlang_core_uint_module,
"moonbitlang/core/uint64": moonbitlang_core_uint64_module,
},
fn(_env, build) {
{
"max_value": (None, Int64(9223372036854775807L)),
"min_value": (None, Int64(-9223372036854775808L)),
"from_int": build(
(
#|pub fn Int64::from_int(i : Int) -> Int64 { i.to_int64() }
),
),
"from_int": build(
(
#|pub fn from_int(i : Int) -> Int64 { i.to_int64() }
),
),
"abs": build(
(
#|pub fn Int64::abs(self : Int64) -> Int64 { if self < 0L {
#| -self
#| } else {
#| self
#| } }
),
),
"to_be_bytes": build(
(
#|pub fn to_be_bytes(self : Int64) -> Bytes { self.reinterpret_as_uint64().to_be_bytes() }
),
),
"to_le_bytes": build(
(
#|pub fn to_le_bytes(self : Int64) -> Bytes { self.reinterpret_as_uint64().to_le_bytes() }
),
),
"gPRIME2": (None, UInt(0x85EBCA77U)),
"gPRIME3": (None, UInt(0xC2B2AE3DU)),
"gPRIME4": (None, UInt(0x27D4EB2FU)),
"gPRIME5": (None, UInt(0x165667B1U)),
"slow_hash": build(
(
#|fn slow_hash(self : Int64) -> Int { let self = self.reinterpret_as_uint64()
#| let b : Bytes = [
#| (self & 0xFF).to_byte(),
#| ((self >> 8) & 0xFF).to_byte(),
#| ((self >> 16) & 0xFF).to_byte(),
#| ((self >> 24) & 0xFF).to_byte(),
#| ((self >> 32) & 0xFF).to_byte(),
#| ((self >> 40) & 0xFF).to_byte(),
#| ((self >> 48) & 0xFF).to_byte(),
#| ((self >> 56) & 0xFF).to_byte(),
#| ]
#| b.hash() }
),
),
}
},
)
///|
let moonbitlang_core_json_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/json",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/char": moonbitlang_core_char_module,
"moonbitlang/core/double": moonbitlang_core_double_module,
"moonbitlang/core/string": moonbitlang_core_string_module,
"moonbitlang/core/strconv": moonbitlang_core_strconv_module,
"moonbitlang/core/option": moonbitlang_core_option_module,
},
fn(_env, build) {
{
"read_char": build(
(
#|fn ParseContext::read_char(ctx : ParseContext) -> Char? { if ctx.offset < ctx.end_offset {
#| let c1 = ctx.input.unsafe_charcode_at(ctx.offset)
#| ctx.offset += 1
#| if c1 >= 0xD800 && c1 <= 0xDBFF {
#| if ctx.offset < ctx.end_offset {
#| let c2 = ctx.input.unsafe_charcode_at(ctx.offset)
#| if c2 >= 0xDC00 && c2 <= 0xDFFF {
#| ctx.offset += 1
#| let c3 = (c1 << 10) + c2 - 0x35fdc00
#| return Some(c3.unsafe_to_char())
#| }
#| }
#| }
#| Some(c1.unsafe_to_char())
#| } else {
#| None
#| } }
),
),
"lex_skip_whitespace": build(
(
#|fn ParseContext::lex_skip_whitespace(ctx : ParseContext) -> Unit { for {
#| match ctx.read_char() {
#| Some('\\t' | ' ' | '\\n' | '\\r') => continue
#| Some(c) => {
#| if c > '\\u{7f}' && non_ascii_whitespace.contains(c) {
#| continue
#| }
#| ctx.offset -= 1
#| break
#| }
#| None => break
#| }
#| } }
),
),
"decode_error": build(
(
#|fn[T] decode_error(path : JsonPath, msg : String) -> T raise JsonDecodeError { raise JsonDecodeError((path, msg)) }
),
),
"as_null": build(
(
#|pub fn as_null(self : JsonValue) -> Unit? { guard self is Null else { return None }
#| Some(()) }
),
),
"as_bool": build(
(
#|pub fn as_bool(self : JsonValue) -> Bool? { match self {
#| True => Some(true)
#| False => Some(false)
#| _ => None
#| } }
),
),
"as_number": build(
(
#|pub fn as_number(self : JsonValue) -> Double? { guard self is Number(n, ..) else { return None }
#| Some(n) }
),
),
"as_string": build(
(
#|pub fn as_string(self : JsonValue) -> String? { guard self is String(s) else { return None }
#| Some(s) }
),
),
"as_array": build(
(
#|pub fn as_array(self : JsonValue) -> Array[JsonValue]? { guard self is Array(arr) else { return None }
#| Some(arr) }
),
),
"item": build(
(
#|pub fn item(self : JsonValue, index : Int) -> JsonValue? { match self.as_array() {
#| Some(arr) => arr.get(index)
#| None => None
#| } }
),
),
"as_object": build(
(
#|pub fn as_object(self : JsonValue) -> Map[String, JsonValue]? { guard self is Object(obj) else { return None }
#| Some(obj) }
),
),
"value": build(
(
#|pub fn value(self : JsonValue, key : String) -> JsonValue? { match self.as_object() {
#| Some(obj) => obj.get(key)
#| None => None
#| } }
),
),
"indent_str": build(
(
#|fn indent_str(level : Int, indent : Int) -> String { if indent == 0 {
#| \"\"
#| } else {
#| \"\\n\" + \" \".repeat(indent * level)
#| } }
),
),
"escape": build(
(
#|fn escape(str : String, escape_slash~ : Bool) -> String { fn to_hex_digit(i : Int) -> Char {
#| if i < 10 {
#| ('0'.to_int() + i).unsafe_to_char()
#| } else {
#| ('a'.to_int() + (i - 10)).unsafe_to_char()
#| }
#| }
#| let buf = StringBuilder::new(size_hint=str.length())
#| for c in str {
#| match c {
#| '\"' => buf.write_string(\"\\\\\\\"\")
#| '\\\\' => buf.write_string(\"\\\\\\\\\")
#| '/' =>
#| if escape_slash {
#| buf.write_string(\"\\\\/\")
#| } else {
#| buf.write_char(c)
#| }
#| '\\n' => buf.write_string(\"\\\\n\")
#| '\\r' => buf.write_string(\"\\\\r\")
#| '\\b' => buf.write_string(\"\\\\b\")
#| '\\t' => buf.write_string(\"\\\\t\")
#| _ => {
#| let code = c.to_int()
#| if code == 0x0C {
#| buf.write_string(\"\\\\f\")
#| } else if code < 0x20 {
#| buf.write_string(\"\\\\u00\")
#| buf.write_char(to_hex_digit(code / 16))
#| buf.write_char(to_hex_digit(code % 16))
#| } else {
#| buf.write_char(c)
#| }
#| }
#| }
#| }
#| buf.to_string() }
),
),
"JsonPath": build(
(
#|enum JsonPath {
#| Root
#| Key(JsonPath, mut key~ : String)
#| Index(JsonPath, mut index~ : Int)
#|} derive(Eq)
),
),
"add_index": build(
(
#|pub fn add_index(self : JsonPath, index : Int) -> JsonPath { Index(self, index~) }
),
),
"add_key": build(
(
#|pub fn add_key(self : JsonPath, key : String) -> JsonPath { Key(self, key~) }
),
),
"lex_string": build(
(
#|fn ParseContext::lex_string(ctx : ParseContext) -> String raise ParseError { let buf = StringBuilder::new()
#| let mut start = ctx.offset
#| fn flush(end : Int) {
#| if start > 0 && end > start {
#| buf.write_substring(ctx.input, start, end - start)
#| }
#| }
#| for {
#| match ctx.read_char() {
#| Some('\"') => {
#| flush(ctx.offset - 1)
#| break
#| }
#| Some('\\n' | '\\r') => ctx.invalid_char(shift=-1)
#| Some('\\\\') => {
#| flush(ctx.offset - 1)
#| match ctx.read_char() {
#| Some('b') => buf.write_char('\\b')
#| Some('f') => buf.write_char('\\u{0C}')
#| Some('n') => buf.write_char('\\n')
#| Some('r') => buf.write_char('\\r')
#| Some('t') => buf.write_char('\\t')
#| Some('\"') => buf.write_char('\"')
#| Some('\\\\') => buf.write_char('\\\\')
#| Some('/') => buf.write_char('/')
#| Some('u') => {
#| let c = ctx.lex_hex_digits(4)
#| buf.write_char(c.unsafe_to_char())
#| }
#| Some(_) => ctx.invalid_char(shift=-1)
#| None => raise InvalidEof
#| }
#| start = ctx.offset
#| }
#| Some(ch) =>
#| if ch.to_int() < 32 {
#| ctx.invalid_char(shift=-1)
#| } else {
#| continue
#| }
#| None => raise InvalidEof
#| }
#| }
#| buf.to_string() }
),
),
"valid": build(
(
#|pub fn valid(input : String) -> Bool { try {
#| parse(input) |> ignore
#| true
#| } catch {
#| _ => return false
#| } }
),
),
"parse": build(
(
#|pub fn parse(input : String) -> JsonValue raise ParseError { let ctx = ParseContext::make(input)
#| let val = ctx.parse_value()
#| ctx.lex_skip_whitespace()
#| if ctx.offset >= ctx.end_offset {
#| val
#| } else {
#| ctx.invalid_char()
#| } }
),
),
"parse_value": build(
(
#|fn ParseContext::parse_value(ctx : ParseContext) -> JsonValue raise ParseError { let tok = ctx.lex_value(allow_rbracket=false)
#| ctx.parse_value2(tok) }
),
),
"parse_object": build(
(
#|fn ParseContext::parse_object(ctx : ParseContext) -> JsonValue raise ParseError { let map = Map::new()
#| loop ctx.lex_property_name() {
#| RBrace => Json::object(map)
#| String(name) => {
#| ctx.lex_after_property_name()
#| map[name] = ctx.parse_value()
#| match ctx.lex_after_object_value() {
#| Comma => continue ctx.lex_property_name2()
#| RBrace => Json::object(map)
#| _ => abort(\"unreachable\")
#| }
#| }
#| _ => abort(\"unreachable\")
#| } }
),
),
"parse_array": build(
(
#|fn ParseContext::parse_array(ctx : ParseContext) -> JsonValue raise ParseError { let vec = []
#| loop ctx.lex_value(allow_rbracket=true) {
#| RBracket => Json::array(vec)
#| tok => {
#| vec.push(ctx.parse_value2(tok))
#| let tok2 = ctx.lex_after_array_value()
#| match tok2 {
#| Comma => continue ctx.lex_value(allow_rbracket=false)
#| RBracket => Json::array(vec)
#| _ => abort(\"unreachable\")
#| }
#| }
#| } }
),
),
"offset_to_position": build(
(
#|fn offset_to_position(input : String, offset : Int) -> Position { let mut line = 1
#| let mut column = 0
#| for i in 0.. ParseContext { { offset: 0, input, end_offset: input.length() } }
),
),
"of": build(
(
#|fn CharClass::of(array : Array[(Char, Char)]) -> CharClass { CharClass(array) }
),
),
"contains": build(
(
#|fn contains(self : CharClass, c : Char) -> Bool { let CharClass(self) = self
#| for left = 0, right = self.length(); left < right; {
#| let middle = (left + right) / 2
#| let (min, max) = self[middle]
#| if c < min {
#| continue left, middle
#| } else if c > max {
#| continue middle + 1, right
#| } else {
#| break true
#| }
#| } else {
#| false
#| } }
),
),
}
},
)
///|
let moonbitlang_core_list_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/list",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
},
fn(_env, build) {
{
"new": build(
(
#|pub fn[A] new() -> List[A] { Empty }
),
),
"empty": build(
(
#|pub fn[A] empty() -> List[A] { Empty }
),
),
"construct": build(
(
#|pub fn[A] construct(head : A, tail : List[A]) -> List[A] { More(head, tail~) }
),
),
"prepend": build(
(
#|pub fn[A] prepend(self : List[A], head : A) -> List[A] { More(head, tail=self) }
),
),
"add": build(
(
#|pub fn[A] add(self : List[A], head : A) -> List[A] { More(head, tail=self) }
),
),
"to_json": build(
(
#|pub fn[A : ToJson] to_json(self : List[A]) -> Json { ToJson::to_json(self) }
),
),
"from_array": build(
(
#|pub fn[A] from_array(arr : Array[A]) -> List[A] { for i = arr.length() - 1, list = Empty; i >= 0; {
#| continue i - 1, More(arr[i], tail=list)
#| } else {
#| list
#| } }
),
),
"length": build(
(
#|pub fn[A] length(self : List[A]) -> Int { loop (self, 0) {
#| (Empty, len) => len
#| (More(_, tail=rest), acc) => continue (rest, acc + 1)
#| } }
),
),
"each": build(
(
#|pub fn[A] each(self : List[A], f : (A) -> Unit raise?) -> Unit raise? { loop self {
#| Empty => ()
#| More(head, tail~) => {
#| f(head)
#| continue tail
#| }
#| } }
),
),
"eachi": build(
(
#|pub fn[A] eachi(self : List[A], f : (Int, A) -> Unit raise?) -> Unit raise? { loop (self, 0) {
#| (Empty, _) => ()
#| (More(x, tail=xs), i) => {
#| f(i, x)
#| continue (xs, i + 1)
#| }
#| } }
),
),
"map": build(
(
#|pub fn[A, B] map(self : List[A], f : (A) -> B raise?) -> List[B] raise? { match self {
#| Empty => Empty
#| More(hd, tail~) => {
#| let dest = More(f(hd), tail=Empty)
#| loop (dest, tail) {
#| (_, Empty) => ()
#| (More(_) as dest, More(hd, tail~)) => {
#| dest.tail = More(f(hd), tail=Empty)
#| continue (dest.tail, tail)
#| }
#| // unreachable
#| (Empty, _) => panic()
#| }
#| dest
#| }
#| } }
),
),
"mapi": build(
(
#|pub fn[A, B] mapi(self : List[A], f : (Int, A) -> B raise?) -> List[B] raise? { match self {
#| Empty => Empty
#| More(hd, tail~) => {
#| let dest = More(f(0, hd), tail=Empty)
#| loop (1, dest, tail) {
#| (_, _, Empty) => ()
#| (i, More(_) as dest, More(hd, tail~)) => {
#| dest.tail = More(f(i, hd), tail=Empty)
#| continue (i + 1, dest.tail, tail)
#| }
#| // unreachable
#| (_, Empty, _) => panic()
#| }
#| dest
#| }
#| } }
),
),
"rev_map": build(
(
#|pub fn[A, B] rev_map(self : List[A], f : (A) -> B raise?) -> List[B] raise? { loop (Empty, self) {
#| (acc, Empty) => acc
#| (acc, More(x, tail=xs)) => continue (More(f(x), tail=acc), xs)
#| } }
),
),
"to_array": build(
(
#|pub fn[A] to_array(self : List[A]) -> Array[A] { match self {
#| Empty => []
#| More(x, tail=xs) => {
#| let arr = [x]
#| loop xs {
#| Empty => ()
#| More(x, tail=xs) => {
#| arr.push(x)
#| continue xs
#| }
#| }
#| arr
#| }
#| } }
),
),
"filter": build(
(
#|pub fn[A] filter(self : List[A], f : (A) -> Bool raise?) -> List[A] raise? { loop self {
#| Empty => Empty
#| More(head, tail~) =>
#| if !f(head) {
#| continue tail
#| } else {
#| let dest = More(head, tail=Empty)
#| loop (dest, tail) {
#| (_, Empty) => ()
#| (More(_) as dest, More(hd, tail~)) =>
#| if f(hd) {
#| dest.tail = More(hd, tail=Empty)
#| continue (dest.tail, tail)
#| } else {
#| continue (dest, tail)
#| }
#| (Empty, _) =>
#| // unreachable
#| panic()
#| }
#| dest
#| }
#| } }
),
),
"all": build(
(
#|pub fn[A] all(self : List[A], f : (A) -> Bool raise?) -> Bool raise? { loop self {
#| Empty => true
#| More(head, tail~) => if f(head) { continue tail } else { false }
#| } }
),
),
"any": build(
(
#|pub fn[A] any(self : List[A], f : (A) -> Bool raise?) -> Bool raise? { loop self {
#| Empty => false
#| More(head, tail~) => if f(head) { true } else { continue tail }
#| } }
),
),
"unsafe_head": build(
(
#|pub fn[A] unsafe_head(self : List[A]) -> A { match self {
#| Empty => abort(\"head of empty list\")
#| More(head, tail=_) => head
#| } }
),
),
"unsafe_tail": build(
(
#|pub fn[A] unsafe_tail(self : List[A]) -> List[A] { match self {
#| Empty => abort(\"tail of empty list\")
#| More(_, tail~) => tail
#| } }
),
),
"head": build(
(
#|pub fn[A] head(self : List[A]) -> A? { match self {
#| Empty => None
#| More(head, tail=_) => Some(head)
#| } }
),
),
"unsafe_last": build(
(
#|pub fn[A] unsafe_last(self : List[A]) -> A { loop self {
#| Empty => abort(\"last of empty list\")
#| More(head, tail=Empty) => head
#| More(_, tail~) => continue tail
#| } }
),
),
"last": build(
(
#|pub fn[A] last(self : List[A]) -> A? { loop self {
#| Empty => None
#| More(head, tail=Empty) => Some(head)
#| More(_, tail~) => continue tail
#| } }
),
),
"concat": build(
(
#|pub fn[A] concat(self : List[A], other : List[A]) -> List[A] { match self {
#| Empty => other
#| More(hd, tail=Empty) => More(hd, tail=other)
#| More(hd, tail~) => {
#| let dest = More(hd, tail=Empty)
#| loop (dest, tail) {
#| (More(_) as dest, Empty) => dest.tail = other
#| (More(_) as dest, More(head, tail~)) => {
#| dest.tail = More(head, tail=Empty)
#| continue (dest.tail, tail)
#| }
#| // unreachable
#| (Empty, _) => panic()
#| }
#| dest
#| }
#| } }
),
),
"rev_concat": build(
(
#|pub fn[A] rev_concat(self : List[A], other : List[A]) -> List[A] { loop (self, other) {
#| (Empty, other) => other
#| (More(head, tail~), other) => continue (tail, More(head, tail=other))
#| } }
),
),
"rev": build(
(
#|pub fn[A] rev(self : List[A]) -> List[A] { self.rev_concat(Empty) }
),
),
"zip": build(
(
#|pub fn[A, B] List::zip(self : List[A], other : List[B]) -> List[(A, B)] { let res = loop (self, other, Empty) {
#| (Empty, _, acc) => break acc
#| (_, Empty, acc) => break acc
#| (More(x, tail=xs), More(y, tail=ys), acc) =>
#| continue (xs, ys, More((x, y), tail=acc))
#| }
#| res.reverse_inplace() }
),
),
"filter_map": build(
(
#|pub fn[A, B] filter_map(self : List[A], f : (A) -> B? raise?) -> List[B] raise? { loop self {
#| Empty => Empty
#| More(hd, tail~) =>
#| match f(hd) {
#| None => continue tail
#| Some(head) => {
#| let dest = More(head, tail=Empty)
#| loop (dest, tail) {
#| (_, Empty) => ()
#| (More(_) as dest, More(hd, tail~)) =>
#| match f(hd) {
#| None => continue (dest, tail)
#| Some(head) => {
#| dest.tail = More(head, tail=Empty)
#| continue (dest.tail, tail)
#| }
#| }
#| (Empty, _) => panic()
#| }
#| dest
#| }
#| }
#| } }
),
),
"unsafe_nth": build(
(
#|pub fn[A] unsafe_nth(self : List[A], n : Int) -> A { loop (self, n) {
#| (Empty, _) => abort(\"nth: index out of bounds\")
#| (More(head, tail=_), 0) => head
#| (More(_, tail~), n) => continue (tail, n - 1)
#| } }
),
),
"nth": build(
(
#|pub fn[A] nth(self : List[A], n : Int) -> A? { loop (self, n) {
#| (Empty, _) => None
#| (More(head, tail=_), 0) => Some(head)
#| (More(_, tail~), n) => continue (tail, n - 1)
#| } }
),
),
"repeat": build(
(
#|pub fn[A] repeat(n : Int, x : A) -> List[A] { loop (Empty, n) {
#| (acc, n) => if n <= 0 { acc } else { continue (More(x, tail=acc), n - 1) }
#| } }
),
),
"intersperse": build(
(
#|pub fn[A] intersperse(self : List[A], separator : A) -> List[A] { match self {
#| Empty => Empty
#| More(head, tail=Empty) => More(head, tail=Empty)
#| More(head, tail~) => {
#| let dest = More(head, tail=Empty)
#| loop (dest, tail) {
#| (_, Empty) => ()
#| (More(_) as dest, More(hd, tail=tl)) => {
#| let new_tail = More(hd, tail=Empty)
#| dest.tail = More(separator, tail=new_tail)
#| continue (new_tail, tl)
#| }
#| // unreachable
#| (Empty, _) => panic()
#| }
#| dest
#| }
#| } }
),
),
"is_empty": build(
(
#|pub fn[A] is_empty(self : List[A]) -> Bool { self is Empty }
),
),
"unzip": build(
(
#|pub fn[A, B] unzip(self : List[(A, B)]) -> (List[A], List[B]) { match self {
#| Empty => (Empty, Empty)
#| More((x, y), tail~) => {
#| let xs = More(x, tail=Empty)
#| let ys = More(y, tail=Empty)
#| loop (tail, xs, ys) {
#| (Empty, _, _) => ()
#| (More((x, y), tail~), More(_) as xptr, More(_) as yptr) => {
#| xptr.tail = More(x, tail=Empty)
#| yptr.tail = More(y, tail=Empty)
#| continue (tail, xptr.tail, yptr.tail)
#| }
#| (_, _, _) => abort(\"unreachable\")
#| }
#| (xs, ys)
#| }
#| } }
),
),
"flatten": build(
(
#|pub fn[A] flatten(self : List[List[A]]) -> List[A] { loop self {
#| Empty => Empty
#| More(head, tail~) =>
#| match head {
#| // continue until we have at least one element
#| Empty => continue tail
#| More(hd, tail=tl) => {
#| let dest = More(hd, tail=Empty)
#| // copy all the elements of `head` first
#| let dest1 = loop (dest, tl) {
#| (dest, Empty) => dest
#| (More(_) as dest, More(hd, tail~)) => {
#| dest.tail = More(hd, tail=Empty)
#| continue (dest.tail, tail)
#| }
#| (Empty, _) => panic()
#| }
#| // continue looping on the `tail` of `self`
#| loop_over_tail~: loop (dest1, tail) {
#| (_, Empty) => ()
#| (More(_) as dest, More(t_hd, tail=Empty)) => dest.tail = t_hd
#| (dest, More(t_hd, tail=t_tl)) =>
#| loop (dest, t_hd) {
#| (dest, Empty) => continue loop_over_tail~ (dest, t_tl)
#| (More(_) as dest, More(hd, tail~)) => {
#| dest.tail = More(hd, tail=Empty)
#| continue (dest.tail, tail)
#| }
#| (Empty, _) => panic()
#| }
#| }
#| dest
#| }
#| }
#| } }
),
),
"unsafe_maximum": build(
(
#|pub fn[A : Compare] unsafe_maximum(self : List[A]) -> A { match self {
#| Empty => abort(\"maximum: empty list\")
#| More(head, tail~) =>
#| loop (tail, head) {
#| (Empty, curr_max) => curr_max
#| (More(item, tail~), curr_max) =>
#| continue (tail, if item > curr_max { item } else { curr_max })
#| }
#| } }
),
),
"maximum": build(
(
#|pub fn[A : Compare] maximum(self : List[A]) -> A? { match self {
#| Empty => None
#| More(head, tail~) =>
#| loop (tail, head) {
#| (Empty, curr_max) => Some(curr_max)
#| (More(item, tail~), curr_max) =>
#| continue (tail, if item > curr_max { item } else { curr_max })
#| }
#| } }
),
),
"unsafe_minimum": build(
(
#|pub fn[A : Compare] unsafe_minimum(self : List[A]) -> A { match self {
#| Empty => abort(\"minimum: empty list\")
#| More(head, tail~) =>
#| loop (tail, head) {
#| (Empty, curr_min) => curr_min
#| (More(item, tail~), curr_min) =>
#| continue (tail, if item < curr_min { item } else { curr_min })
#| }
#| } }
),
),
"minimum": build(
(
#|pub fn[A : Compare] minimum(self : List[A]) -> A? { match self {
#| Empty => None
#| More(head, tail~) =>
#| loop (tail, head) {
#| (Empty, curr_min) => Some(curr_min)
#| (More(item, tail~), curr_min) =>
#| continue (tail, if item < curr_min { item } else { curr_min })
#| }
#| } }
),
),
"sort": build(
(
#|pub fn[A : Compare] sort(self : List[A]) -> List[A] { let arr = self.to_array()
#| arr.sort()
#| from_array(arr) }
),
),
"contains": build(
(
#|pub fn[A : Eq] contains(self : List[A], value : A) -> Bool { loop self {
#| Empty => false
#| More(x, tail=xs) => if x == value { true } else { continue xs }
#| } }
),
),
"unfold": build(
(
#|pub fn[A, S] unfold(f : (S) -> (A, S)? raise?, init~ : S) -> List[A] raise? { match f(init) {
#| None => Empty
#| Some((element, new_state)) => {
#| let dest = More(element, tail=Empty)
#| loop (dest, f(new_state)) {
#| (_, None) => ()
#| (More(_) as dest, Some((element, new_state))) => {
#| dest.tail = More(element, tail=Empty)
#| continue (dest.tail, f(new_state))
#| }
#| (Empty, _) => panic()
#| }
#| dest
#| }
#| } }
),
),
"rev_unfold": build(
(
#|pub fn[A, S] rev_unfold(f : (S) -> (A, S)? raise?, init~ : S) -> List[A] raise? { loop (f(init), Empty) {
#| (None, acc) => acc
#| (Some((x, s)), acc) => continue (f(s), More(x, tail=acc))
#| } }
),
),
"take": build(
(
#|pub fn[A] take(self : List[A], n : Int) -> List[A] { if n <= 0 {
#| Empty
#| } else {
#| match self {
#| Empty => Empty
#| More(head, tail~) => {
#| let dest = More(head, tail=Empty)
#| loop (dest, tail, n - 1) {
#| (_, Empty, _) => ()
#| (_, _, 0) => ()
#| (More(_) as dest, More(x, tail=xs), n) => {
#| dest.tail = More(x, tail=Empty)
#| continue (dest.tail, xs, n - 1)
#| }
#| (Empty, _, _) => panic()
#| }
#| dest
#| }
#| }
#| } }
),
),
"drop": build(
(
#|pub fn[A] drop(self : List[A], n : Int) -> List[A] { if n <= 0 {
#| self
#| } else {
#| loop (n, self) {
#| (_, Empty) => Empty
#| (1, More(_, tail=xs)) => xs
#| (n, More(_, tail=xs)) => continue (n - 1, xs)
#| }
#| } }
),
),
"take_while": build(
(
#|pub fn[A] take_while(self : List[A], p : (A) -> Bool raise?) -> List[A] raise? { match self {
#| Empty => Empty
#| More(head, tail~) =>
#| if p(head) {
#| let dest = More(head, tail=Empty)
#| loop (dest, tail) {
#| (_, Empty) => ()
#| (More(_) as dest, More(x, tail=xs)) if p(x) => {
#| dest.tail = More(x, tail=Empty)
#| continue (dest.tail, xs)
#| }
#| (More(_), _) => ()
#| (Empty, _) => panic()
#| }
#| dest
#| } else {
#| Empty
#| }
#| } }
),
),
"drop_while": build(
(
#|pub fn[A] drop_while(self : List[A], p : (A) -> Bool raise?) -> List[A] raise? { loop self {
#| Empty => Empty
#| More(x, tail=xs) => if p(x) { continue xs } else { More(x, tail=xs) }
#| } }
),
),
"lookup": build(
(
#|pub fn[A : Eq, B] lookup(self : List[(A, B)], v : A) -> B? { loop self {
#| Empty => None
#| More((x, y), tail=xs) => if x == v { Some(y) } else { continue xs }
#| } }
),
),
"find": build(
(
#|pub fn[A] find(self : List[A], f : (A) -> Bool raise?) -> A? raise? { loop self {
#| Empty => None
#| More(element, tail=list) =>
#| if f(element) {
#| Some(element)
#| } else {
#| continue list
#| }
#| } }
),
),
"findi": build(
(
#|pub fn[A] findi(self : List[A], f : (A, Int) -> Bool raise?) -> A? raise? { loop (self, 0) {
#| (list, index) =>
#| match list {
#| Empty => None
#| More(element, tail=list) =>
#| if f(element, index) {
#| Some(element)
#| } else {
#| continue (list, index + 1)
#| }
#| }
#| } }
),
),
"remove_at": build(
(
#|pub fn[A] remove_at(self : List[A], index : Int) -> List[A] { match (index, self) {
#| (_, Empty) => Empty
#| (_..<0, _) => self
#| (0, More(_, tail~)) => tail
#| (n, More(head, tail~)) => {
#| let dest = More(head, tail=Empty)
#| loop (dest, tail, n - 1) {
#| (_, Empty, _) => ()
#| (More(_) as dest, More(_, tail~), 0) => dest.tail = tail
#| (More(_) as dest, More(x, tail=xs), n) => {
#| dest.tail = More(x, tail=Empty)
#| continue (dest.tail, xs, n - 1)
#| }
#| (Empty, _, _) => panic()
#| }
#| dest
#| }
#| } }
),
),
"remove": build(
(
#|pub fn[A : Eq] remove(self : List[A], elem : A) -> List[A] { match self {
#| Empty => Empty
#| More(head, tail~) if head == elem => tail
#| More(head, tail~) => {
#| let dest = More(head, tail~)
#| loop (dest, tail) {
#| (_, Empty) => ()
#| (More(_) as dest, More(x, tail=xs)) =>
#| if x == elem {
#| dest.tail = xs
#| } else {
#| dest.tail = More(x, tail=Empty)
#| continue (dest.tail, xs)
#| }
#| (Empty, _) => panic()
#| }
#| dest
#| }
#| } }
),
),
"is_prefix": build(
(
#|pub fn[A : Eq] is_prefix(self : List[A], prefix : List[A]) -> Bool { loop (self, prefix) {
#| (_, Empty) => true
#| (Empty, More(_)) => false
#| (More(h1, tail=t1), More(h2, tail=t2)) =>
#| if h1 == h2 {
#| continue (t1, t2)
#| } else {
#| false
#| }
#| } }
),
),
"is_suffix": build(
(
#|pub fn[A : Eq] is_suffix(self : List[A], suffix : List[A]) -> Bool { self.rev().is_prefix(suffix.rev()) }
),
),
"intercalate": build(
(
#|pub fn[A] intercalate(self : List[List[A]], sep : List[A]) -> List[A] { self.intersperse(sep).flatten() }
),
),
"default": build(
(
#|pub fn[X] default() -> List[X] { Empty }
),
),
"iter": build(
(
#|pub fn[A] iter(self : List[A]) -> Iter[A] { Iter::new(yield_ => loop self {
#| Empty => IterContinue
#| More(head, tail~) => {
#| if yield_(head) == IterEnd {
#| break IterEnd
#| }
#| continue tail
#| }
#| }) }
),
),
"iter2": build(
(
#|pub fn[A] iter2(self : List[A]) -> Iter2[Int, A] { Iter2::new(yield_ => loop (self, 0) {
#| (Empty, _) => IterEnd
#| (More(head, tail~), i) => {
#| if yield_(i, head) == IterEnd {
#| break IterEnd
#| }
#| continue (tail, i + 1)
#| }
#| }) }
),
),
"from_iter": build(
(
#|pub fn[A] from_iter(iter : Iter[A]) -> List[A] { let mut res = Empty
#| let mut ptr = Empty
#| for x in iter {
#| match (res, ptr) {
#| (Empty, _) => {
#| res = More(x, tail=Empty)
#| ptr = res
#| }
#| (More(_), More(_) as ptr_) => {
#| ptr_.tail = More(x, tail=Empty)
#| ptr = ptr_.tail
#| }
#| (_, _) => panic()
#| }
#| }
#| res }
),
),
"from_iter_rev": build(
(
#|pub fn[A] from_iter_rev(iter : Iter[A]) -> List[A] { iter.fold(init=Empty, (acc, e) => More(e, tail=acc)) }
),
),
"of": build(
(
#|pub fn[A] of(arr : FixedArray[A]) -> List[A] { for i = arr.length() - 1, list = Empty; i >= 0; {
#| continue i - 1, More(arr[i], tail=list)
#| } else {
#| list
#| } }
),
),
"singleton": build(
(
#|pub fn[A] singleton(x : A) -> List[A] { More(x, tail=Empty) }
),
),
"reverse_inplace": build(
(
#|fn[A] reverse_inplace(self : List[A]) -> List[A] { match self {
#| Empty | More(_, tail=Empty) => self
#| More(head, tail~) =>
#| loop (More(head, tail=Empty), tail) {
#| (result, Empty) => result
#| (result, More(_, tail=xs) as new_result) => {
#| new_result.tail = result
#| continue (new_result, xs)
#| }
#| }
#| } }
),
),
"rev_fold": build(
(
#|pub fn[A, B] rev_fold(self : List[A], init~ : B, f : (B, A) -> B) -> B { let xs = self.to_array()
#| let mut acc = init
#| for x in xs.rev_iter() {
#| acc = f(acc, x)
#| }
#| acc }
),
),
"rev_foldi": build(
(
#|pub fn[A, B] rev_foldi(self : List[A], init~ : B, f : (Int, B, A) -> B) -> B { self.rev().foldi(init~, (i, b, a) => f(i, b, a)) }
),
),
"tail": build(
(
#|pub fn[A] tail(self : List[A]) -> List[A] { match self {
#| Empty => Empty
#| More(_, tail~) => tail
#| } }
),
),
"List": build(
(
#|pub enum List[A] {
#| Empty
#| More(A, mut tail~ : List[A])
#|} derive(Eq)
),
),
}
},
)
///|
let moonbitlang_core_math_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/math",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/double": moonbitlang_core_double_module,
"moonbitlang/core/float": moonbitlang_core_float_module,
"moonbitlang/core/int": moonbitlang_core_int_module,
"moonbitlang/core/bigint": moonbitlang_core_bigint_module,
"moonbitlang/core/random": moonbitlang_core_random_module,
},
fn(_env, build) {
{
"ln": build(
(
#|pub fn ln(x : Double) -> Double { let l1 = 6.666666666666735130e-01 // 3FE55555 55555593
#| let l2 = 3.999999999940941908e-01 // 3FD99999 9997FA04
#| let l3 = 2.857142874366239149e-01 // 3FD24924 94229359
#| let l4 = 2.222219843214978396e-01 // 3FCC71C5 1D8E78AF
#| let l5 = 1.818357216161805012e-01 // 3FC74664 96CB03DE
#| let l6 = 1.531383769920937332e-01 // 3FC39A09 D078C69F
#| let l7 = 1.479819860511658591e-01 // 3FC2F112 DF3E5244
#| if x < 0.0 {
#| return @double.not_a_number
#| } else if x.is_nan() || x.is_inf() {
#| return x
#| } else if x == 0.0 {
#| return @double.neg_infinity
#| }
#| let (f1, ki) = frexp(x)
#| let (f, k) = if f1 < SQRT2 / 2.0 {
#| (f1 * 2.0 - 1.0, (ki - 1).to_double())
#| } else {
#| (f1 - 1.0, ki.to_double())
#| }
#| let s = f / (2.0 + f)
#| let s2 = s * s
#| let s4 = s2 * s2
#| let t1 = s2 * (l1 + s4 * (l3 + s4 * (l5 + s4 * l7)))
#| let t2 = s4 * (l2 + s4 * (l4 + s4 * l6))
#| let r = t1 + t2
#| let hfsq = 0.5 * f * f
#| k * LN2_HI - (hfsq - (s * (hfsq + r) + k * LN2_LO) - f) }
),
),
"log2": build(
(
#|pub fn log2(x : Double) -> Double { let (f, e) = frexp(x)
#| if f == 0.5 {
#| return e.to_double() - 1.0
#| }
#| ln(f) / LN2 + e.to_double() }
),
),
"log10": build(
(
#|pub fn log10(x : Double) -> Double { if x < 0.0 {
#| return @double.not_a_number
#| } else if x.is_nan() || x.is_inf() {
#| return x
#| } else if x == 0.0 {
#| return @double.neg_infinity
#| }
#| let ivln10 = 4.34294481903251816668e-01
#| let log10_2hi = 3.01029995663611771306e-01
#| let log10_2lo = 3.69423907715893078616e-13
#| let (f, e) = frexp(x)
#| let (f, e) = if e >= 1 {
#| (f * 2.0, (e - 1).to_double())
#| } else {
#| (f, e.to_double())
#| }
#| let z = e * log10_2lo + ivln10 * ln(f)
#| z + e * log10_2hi }
),
),
"ln_1p": build(
(
#|pub fn ln_1p(x : Double) -> Double { if x < -1.0 || x.is_nan() {
#| return @double.not_a_number
#| }
#| if x == -1.0 {
#| return @double.neg_infinity
#| }
#| if x.is_inf() {
#| return @double.infinity
#| }
#| let ln2_hi = 6.93147180369123816490e-01
#| let ln2_lo = 1.90821492927058770002e-10
#| let two54 = 1.80143985094819840000e+16
#| let lp1 = 6.666666666666735130e-01
#| let lp2 = 3.999999999940941908e-01
#| let lp3 = 2.857142874366239149e-01
#| let lp4 = 2.222219843214978396e-01
#| let lp5 = 1.818357216161805012e-01
#| let lp6 = 1.531383769920937332e-01
#| let zero = 0.0
#| let lp7 = 1.479819860511658591e-01
#| let hx = get_high_word(x).reinterpret_as_int()
#| let ax = hx & 0x7fffffff
#| let mut f = 0.0
#| let mut c = 0.0
#| let mut s = 0.0
#| let mut z = 0.0
#| let mut r = 0.0
#| let mut u = 0.0
#| let mut hu = 0
#| let mut k = 1
#| if hx < 0x3FDA827A {
#| if ax < 0x3e200000 {
#| if two54 + x > zero && ax < 0x3c900000 {
#| return x
#| } else {
#| return x - x * x * 0.5
#| }
#| }
#| if hx > 0 || hx <= 0xbfd2bec3 {
#| k = 0
#| f = x
#| hu = 1
#| }
#| }
#| if k != 0 {
#| if hx < 0x43400000 {
#| u = 1.0 + x
#| hu = get_high_word(u).reinterpret_as_int()
#| k = (hu >> 20) - 1023
#| c = if k > 0 { 1.0 - (u - x) } else { x - (u - 1.0) }
#| c /= u
#| } else {
#| u = x
#| hu = get_high_word(u).reinterpret_as_int()
#| k = (hu >> 20) - 1023
#| c = 0.0
#| }
#| hu = hu & 0x000fffff
#| if hu < 0x6a09e {
#| u = set_high_word(u, hu.reinterpret_as_uint() | 0x3ff00000)
#| } else {
#| k += 1
#| u = set_high_word(u, hu.reinterpret_as_uint() | 0x3fe00000)
#| hu = (0x00100000 - hu) >> 2
#| }
#| f = u - 1.0
#| }
#| let hfsq = 0.5 * f * f
#| if hu == 0 {
#| if f == zero {
#| if k == 0 {
#| return zero
#| } else {
#| c += k.to_double() * ln2_lo
#| return k.to_double() * ln2_hi + c
#| }
#| }
#| r = hfsq * (1.0 - 0.66666666666666666 * f)
#| if k == 0 {
#| return f - r
#| } else {
#| return k.to_double() * ln2_hi - (r - (k.to_double() * ln2_lo + c) - f)
#| }
#| }
#| s = f / (2.0 + f)
#| z = s * s
#| r = z *
#| (lp1 + z * (lp2 + z * (lp3 + z * (lp4 + z * (lp5 + z * (lp6 + z * lp7))))))
#| if k == 0 {
#| return f - (hfsq - s * (hfsq + r))
#| } else {
#| return k.to_double() * ln2_hi -
#| (hfsq - (s * (hfsq + r) + (k.to_double() * ln2_lo + c)) - f)
#| } }
),
),
"sin": build(
(
#|pub fn sin(x : Double) -> Double { if x.is_inf() || x.is_nan() {
#| return @double.not_a_number
#| }
#| let y = [0.0, 0.0]
#| let z = 0.0
#| if x.abs() <= PI_OVER_4 {
#| return __kernel_sin(x, z, 0)
#| } else {
#| let n = rem_pio2(x, y)
#| match n & 3 {
#| 0 => __kernel_sin(y[0], y[1], 1)
#| 1 => __kernel_cos(y[0], y[1])
#| 2 => -__kernel_sin(y[0], y[1], 1)
#| _ => -__kernel_cos(y[0], y[1])
#| }
#| } }
),
),
"cos": build(
(
#|pub fn cos(x : Double) -> Double { if x.is_inf() || x.is_nan() {
#| return @double.not_a_number
#| }
#| let y = [0.0, 0.0]
#| let z = 0.0
#| if x.abs() <= PI_OVER_4 {
#| return __kernel_cos(x, z)
#| } else {
#| let n = rem_pio2(x, y)
#| match n & 3 {
#| 0 => __kernel_cos(y[0], y[1])
#| 1 => -__kernel_sin(y[0], y[1], 1)
#| 2 => -__kernel_cos(y[0], y[1])
#| _ => __kernel_sin(y[0], y[1], 1)
#| }
#| } }
),
),
"tan": build(
(
#|pub fn tan(x : Double) -> Double { if x.is_inf() || x.is_nan() {
#| return @double.not_a_number
#| }
#| let y = Array::make(2, 0.0)
#| let z = 0.0
#| if x.abs() <= PI_OVER_4 {
#| __kernal_tan(x, z, 1)
#| } else {
#| let n = rem_pio2(x, y)
#| __kernal_tan(y[0], y[1], 1 - ((n & 1) << 1))
#| } }
),
),
"asin": build(
(
#|pub fn asin(x : Double) -> Double { let huge = 1.0e+300
#| let pio4_hi = 7.85398163397448278999e-01
#| let pio2_hi = 1.57079632679489655800
#| let pio2_lo = 6.12323399573676603587e-17
#| let ps0 = 1.66666666666666657415e-01
#| let ps1 = -3.25565818622400915405e-01
#| let ps2 = 2.01212532134862925881e-01
#| let ps3 = -4.00555345006794114027e-02
#| let ps4 = 7.91534994289814532176e-04
#| let ps5 = 3.47933107596021167570e-05
#| let qs1 = -2.40339491173441421878e+00
#| let qs2 = 2.02094576023350569471e+00
#| let qs3 = -6.88283971605453293030e-01
#| let qs4 = 7.70381505559019352791e-02
#| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff
#| let absx = x.abs()
#| if absx >= 1.0 {
#| if absx == 1.0 {
#| return x * pio2_hi + x * pio2_lo
#| } else {
#| return @double.not_a_number
#| }
#| } else if absx < 0.5 {
#| if ix < 0x3e400000 {
#| if huge + x > 1.0 {
#| return x
#| }
#| } else {
#| let t = x * x
#| let p = t *
#| (ps0 + t * (ps1 + t * (ps2 + t * (ps3 + t * (ps4 + t * ps5)))))
#| let q = 1.0 + t * (qs1 + t * (qs2 + t * (qs3 + t * qs4)))
#| let w = p / q
#| return x + x * w
#| }
#| }
#| let w = 1.0 - absx
#| let t = w * 0.5
#| let p = t * (ps0 + t * (ps1 + t * (ps2 + t * (ps3 + t * (ps4 + t * ps5)))))
#| let q = 1.0 + t * (qs1 + t * (qs2 + t * (qs3 + t * qs4)))
#| let s = t.sqrt()
#| if ix >= 0x3FEF3333 {
#| let w = p / q
#| let t = pio2_hi - (2.0 * (s + s * w) - pio2_lo)
#| return if x > 0.0 { t } else { -t }
#| } else {
#| let mut w = s
#| w = set_low_word(w, 0)
#| let c = (t - w * w) / (s + w)
#| let r = p / q
#| let p = 2.0 * s * r - (pio2_lo - 2.0 * c)
#| let q = pio4_hi - 2.0 * w
#| let t = pio4_hi - (p - q)
#| return if x > 0.0 { t } else { -t }
#| } }
),
),
"acos": build(
(
#|pub fn acos(x : Double) -> Double { let one : Double = 1.0
#| let pi : Double = 3.14159265358979311600
#| let pio2_hi : Double = 1.57079632679489655800
#| let pio2_lo : Double = 6.12323399573676603587e-17
#| let ps0 : Double = 1.66666666666666657415e-01
#| let ps1 : Double = -3.25565818622400915405e-01
#| let ps2 : Double = 2.01212532134862925881e-01
#| let ps3 : Double = -4.00555345006794114027e-02
#| let ps4 : Double = 7.91534994289814532176e-04
#| let ps5 : Double = 3.47933107596021167570e-05
#| let qs1 : Double = -2.40339491173441421878e+00
#| let qs2 : Double = 2.02094576023350569471e+00
#| let qs3 : Double = -6.88283971605453293030e-01
#| let qs4 : Double = 7.70381505559019352791e-02
#| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff
#| let absx = x.abs()
#| if absx >= 1.0 {
#| if absx == 1.0 {
#| if x > 0 {
#| return 0.0
#| } else {
#| return pi + 2.0 * pio2_lo
#| }
#| }
#| return @double.not_a_number
#| }
#| if absx < 0.5 {
#| if ix <= 0x3c600000 {
#| return pio2_hi + pio2_lo
#| }
#| let z = x * x
#| let p = z * (ps0 + z * (ps1 + z * (ps2 + z * (ps3 + z * (ps4 + z * ps5)))))
#| let q = one + z * (qs1 + z * (qs2 + z * (qs3 + z * qs4)))
#| let r = p / q
#| pio2_hi - (x - (pio2_lo - x * r))
#| } else if x < 0 {
#| let z = (one + x) * 0.5
#| let p = z * (ps0 + z * (ps1 + z * (ps2 + z * (ps3 + z * (ps4 + z * ps5)))))
#| let q = one + z * (qs1 + z * (qs2 + z * (qs3 + z * qs4)))
#| let s = z.sqrt()
#| let r = p / q
#| let w = r * s - pio2_lo
#| pi - 2.0 * (s + w)
#| } else {
#| let z = (one - x) * 0.5
#| let s = z.sqrt()
#| let df = s
#| let c = (z - df * df) / (s + df)
#| let p = z * (ps0 + z * (ps1 + z * (ps2 + z * (ps3 + z * (ps4 + z * ps5)))))
#| let q = one + z * (qs1 + z * (qs2 + z * (qs3 + z * qs4)))
#| let r = p / q
#| let w = r * s + c
#| 2.0 * (df + w)
#| } }
),
),
"atan": build(
(
#|pub fn atan(x : Double) -> Double { if x.is_nan() || x == 0.0 {
#| return x
#| }
#| let atan_hi = [
#| 4.63647609000806093515e-01, 7.85398163397448278999e-01, 9.82793723247329054082e-01,
#| 1.57079632679489655800e+00,
#| ]
#| let atan_lo = [
#| 2.26987774529616870924e-17, 3.06161699786838301793e-17, 1.39033110312309984516e-17,
#| 6.12323399573676603587e-17,
#| ]
#| let a_t = [
#| 3.33333333333329318027e-01, -1.99999999998764832476e-01, 1.42857142725034663711e-01,
#| -1.11111104054623557880e-01, 9.09088713343650656196e-02, -7.69187620504482999495e-02,
#| 6.66107313738753120669e-02, -5.83357013379057348645e-02, 4.97687799461593236017e-02,
#| -3.65315727442169155270e-02, 1.62858201153657823623e-02,
#| ]
#| let one = 1.0
#| let huge = 1.0e300
#| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff
#| let mut id = 0
#| let mut z = 0.0
#| let mut w = 0.0
#| let mut x = x
#| let x_is_neg = x < 0.0
#| if ix >= 0x44100000 {
#| if x > 0 {
#| return atan_hi[3] + atan_lo[3]
#| } else {
#| return -atan_hi[3] - atan_lo[3]
#| }
#| }
#| if ix < 0x3fdc0000 {
#| if ix < 0x3e200000 {
#| if huge + x > one {
#| return x
#| }
#| }
#| id = -1
#| } else {
#| x = x.abs()
#| if ix < 0x3ff30000 {
#| if ix < 0x3fe60000 {
#| id = 0
#| x = (2.0 * x - one) / (2.0 + x)
#| } else {
#| id = 1
#| x = (x - one) / (x + one)
#| }
#| } else if ix < 0x40038000 {
#| id = 2
#| x = (x - 1.5) / (one + 1.5 * x)
#| } else {
#| id = 3
#| x = -1.0 / x
#| }
#| }
#| z = x * x
#| w = z * z
#| let s1 = z *
#| (
#| a_t[0] +
#| w * (a_t[2] + w * (a_t[4] + w * (a_t[6] + w * (a_t[8] + w * a_t[10]))))
#| )
#| let s2 = w *
#| (a_t[1] + w * (a_t[3] + w * (a_t[5] + w * (a_t[7] + w * a_t[9]))))
#| if id < 0 {
#| x - x * (s1 + s2)
#| } else {
#| z = atan_hi[id] - (x * (s1 + s2) - atan_lo[id] - x)
#| if x_is_neg {
#| -z
#| } else {
#| z
#| }
#| } }
),
),
"atan2": build(
(
#|pub fn atan2(y : Double, x : Double) -> Double { if x.is_nan() || y.is_nan() {
#| return @double.not_a_number
#| }
#| let tiny = 1.0e-300
#| let zero = 0.0
#| let pi_o_4 = 7.8539816339744827900E-01
#| let pi_o_2 = 1.5707963267948965580E+00
#| let pi = 3.1415926535897931160E+00
#| let pi_lo = 1.2246467991473531772E-16
#| let hx = get_high_word(x).reinterpret_as_int()
#| let hy = get_high_word(y).reinterpret_as_int()
#| let ix = hx & 0x7fffffff
#| let iy = hy & 0x7fffffff
#| if x == 1.0 {
#| return atan(y)
#| }
#| let m = ((hy >> 31) & 1) | ((hx >> 30) & 2)
#| if y == 0 {
#| match m {
#| 0 | 1 => return y
#| 2 => return pi + tiny
#| _ => return -pi - tiny
#| }
#| }
#| if x == 0 {
#| return if hy < 0 { -pi_o_2 - tiny } else { pi_o_2 + tiny }
#| }
#| if x.is_inf() {
#| if y.is_inf() {
#| match m {
#| 0 => return pi_o_4 + tiny
#| 1 => return -pi_o_4 - tiny
#| 2 => return 3.0 * pi_o_4 + tiny
#| _ => return -3.0 * pi_o_4 - tiny
#| }
#| } else {
#| match m {
#| 0 => return zero
#| 1 => return -zero
#| 2 => return pi + tiny
#| _ => return -pi - tiny
#| }
#| }
#| }
#| if y.is_inf() {
#| return if hy < 0 { -pi_o_2 - tiny } else { pi_o_2 + tiny }
#| }
#| let k = (iy - ix) >> 20
#| let z = if k > 60 {
#| pi_o_2 + 0.5 * pi_lo
#| } else if hx < 0 && k < -60 {
#| 0.0
#| } else {
#| atan(abs(y / x))
#| }
#| match m {
#| 0 => z
#| 1 => -z
#| 2 => pi - (z - pi_lo)
#| _ => z - pi_lo - pi
#| } }
),
),
"rem_pio2": build(
(
#|fn rem_pio2(x : Double, y : Array[Double]) -> Int { let hx = get_high_word(x).reinterpret_as_int()
#| let ix : Int = hx & 0x7fffffff
#| let mut z = 0.0
#| if ix <= 0x3fe921fb {
#| // |x| <= pi/4, no reduction needed
#| y[0] = x
#| y[1] = 0.0
#| return 0
#| }
#| if ix < 0x4002d97c {
#| // |x| < 3pi/4, special case with n = +-1
#| if hx > 0 {
#| z = x - PIO2_1
#| if ix != 0x3ff921fb {
#| // 33+53 bit pi is good enough
#| y[0] = z - PIO2_1T
#| y[1] = z - y[0] - PIO2_1T
#| } else {
#| // Near pi/2, use 33+33+53 bit pi
#| z = z - PIO2_2
#| y[0] = z - PIO2_2T
#| y[1] = z - y[0] - PIO2_2T
#| }
#| return 1
#| } else {
#| // Negative x
#| z = x + PIO2_1
#| if ix != 0x3ff921fb {
#| // 33+53 bit pi is good enough
#| y[0] = z + PIO2_1T
#| y[1] = z - y[0] + PIO2_1T
#| } else {
#| // Near pi/2, use 33+33+53 bit pi
#| let z = z + PIO2_2
#| y[0] = z + PIO2_2T
#| y[1] = z - y[0] + PIO2_2T
#| }
#| return -1
#| }
#| }
#| if ix <= 0x413921fb {
#| // |x| <= 2^19 * (pi/2), medium size
#| let t = x.abs()
#| let n = (t * INV_PIO2 + HALF).to_int()
#| let fn_ = n.to_double()
#| let mut r = t - fn_ * PIO2_1
#| let mut w = fn_ * PIO2_1T
#| if n < 32 && ix != npio2_hw[n - 1] {
#| y[0] = r - w
#| } else {
#| let j = ix >> 20
#| y[0] = r - w
#| let i = j - ((get_high_word(y[0]) >> 20).reinterpret_as_int() & 0x7ff)
#| if i > 16 {
#| // 2nd iteration needed, good to 118 bits
#| let t = r
#| w = fn_ * PIO2_2
#| r = t - w
#| w = fn_ * PIO2_2T - (t - r - w)
#| y[0] = r - w
#| let i = j - ((get_high_word(y[0]) >> 20).reinterpret_as_int() & 0x7ff)
#| if i > 49 {
#| // 3rd iteration needed, 151 bits accuracy
#| let t = r
#| w = fn_ * PIO2_3
#| r = t - w
#| w = fn_ * PIO2_3T - (t - r - w)
#| y[0] = r - w
#| }
#| }
#| }
#| y[1] = r - y[0] - w
#| if hx > 0 {
#| return n
#| } else {
#| y[0] = -y[0]
#| y[1] = -y[1]
#| return -n
#| }
#| }
#| // All other (large) arguments
#| if ix >= 0x7ff00000 {
#| // x is inf or NaN
#| y[0] = x - x
#| y[1] = y[0]
#| return 0
#| }
#| // Set z = scalbn(|x|, ilogb(x) - 23)
#| z = set_low_word(z, get_low_word(x))
#| let e0 = (ix >> 20) - 1046 // e0 = ilogb(z) - 23
#| z = set_high_word(z, (ix - (e0 << 20)).reinterpret_as_uint())
#| let tx = [0.0, 0.0, 0.0]
#| for i in 0..<2 {
#| tx[i] = z.to_int().to_double()
#| z = (z - tx[i]) * TWO24
#| }
#| tx[2] = z
#| let mut nx = 3
#| while tx[nx - 1] == 0.0 {
#| nx -= 1
#| }
#| let n = __kernel_rem_pio2(tx, y, e0, nx, 2)
#| if hx > 0 {
#| n
#| } else {
#| y[0] = -y[0]
#| y[1] = -y[1]
#| -n
#| } }
),
),
"__kernel_sin": build(
(
#|fn __kernel_sin(x : Double, y : Double, iy : Int) -> Double { let s1 = -1.66666666666666324348e-01
#| let s2 = 8.33333333332248946124e-03
#| let s3 = -1.98412698298579493134e-04
#| let s4 = 2.75573137070700676789e-06
#| let s5 = -2.50507602534068634195e-08
#| let s6 = 1.58969099521155010221e-10
#| let mut z = 0.0
#| let mut r = 0.0
#| let mut v = 0.0
#| let ix = get_high_word(x) & 0x7fffffff
#| if ix < 0x3e400000 {
#| if x.to_int() == 0 {
#| return x
#| }
#| }
#| z = x * x
#| v = z * x
#| r = s2 + z * (s3 + z * (s4 + z * (s5 + z * s6)))
#| if iy == 0 {
#| x + v * (s1 + z * r)
#| } else {
#| x - (z * (0.5 * y - v * r) - y - v * s1)
#| } }
),
),
"__kernel_cos": build(
(
#|fn __kernel_cos(x : Double, y : Double) -> Double { let one = 1.00000000000000000000e+00
#| let c1 = 4.16666666666666019037e-02
#| let c2 = -1.38888888888741095749e-03
#| let c3 = 2.48015872894767294178e-05
#| let c4 = -2.75573143513906633035e-07
#| let c5 = 2.08757232129817482790e-09
#| let c6 = -1.13596475577881948265e-11
#| let mut a = 0.0
#| let mut hz = 0.0
#| let mut z = 0.0
#| let mut r = 0.0
#| let mut qx = 0.0
#| let ix = get_high_word(x) & 0x7fffffff
#| if ix < 0x3e400000 {
#| if x.to_int() == 0 {
#| return one
#| }
#| }
#| z = x * x
#| r = z * (c1 + z * (c2 + z * (c3 + z * (c4 + z * (c5 + z * c6)))))
#| if ix < 0x3fd33333 {
#| return one - (0.5 * z - (z * r - x * y))
#| } else {
#| if ix > 0x3fe90000 {
#| qx = 0.28125
#| } else {
#| qx = ((ix - 0x00200000).to_uint64() << 32).reinterpret_as_double()
#| }
#| hz = 0.5 * z - qx
#| a = one - qx
#| return a - (hz - (z * r - x * y))
#| } }
),
),
"__kernal_tan": build(
(
#|fn __kernal_tan(x : Double, y : Double, iy : Int) -> Double { let one = 1.0
#| let pio4 = 7.85398163397448278999e-01
#| let pio4lo = 3.06161699786838301793e-17
#| let mut x = x
#| let mut y = y
#| let mut z = 0.0
#| let mut r = 0.0
#| let mut v = 0.0
#| let mut w = 0.0
#| let mut s = 0.0
#| let t = [
#| 3.33333333333334091986e-01, // 3FD55555, 55555563 */
#| 1.33333333333201242699e-01, // 3FC11111, 1110FE7A */
#| 5.39682539762260521377e-02, // 3FABA1BA, 1BB341FE */
#| 2.18694882948595424599e-02, // 3F9664F4, 8406D637 */
#| 8.86323982359930005737e-03, // 3F8226E3, E96E8493 */
#| 3.59207910759131235356e-03, // 3F6D6D22, C9560328 */
#| 1.45620945432529025516e-03, // 3F57DBC8, FEE08315 */
#| 5.88041240820264096874e-04, // 3F4344D8, F2F26501 */
#| 2.46463134818469906812e-04, // 3F3026F7, 1A8D1068 */
#| 7.81794442939557092300e-05, // 3F147E88, A03792A6 */
#| 7.14072491382608190305e-05, // 3F12B80F, 32F0A7E9 */
#| -1.85586374855275456654e-05, // BEF375CB, DB605373 */
#| 2.59073051863633712884e-05, // 3EFB2A70, 74BF7AD4 */
#| 1.00000000000000000000e+00, // 3FF00000, 00000000 (one) */
#| 7.85398163397448278999e-01, // 3FE921FB, 54442D18 (pio4) */
#| 3.06161699786838301793e-17, // 3C81A626, 33145C07 (pio4lo) */
#| ]
#| let hx = get_high_word(x).reinterpret_as_int()
#| let ix = hx & 0x7fffffff
#| if ix < 0x3e300000 {
#| if x.to_int() == 0 {
#| if (ix | get_low_word(x).reinterpret_as_int() | (iy + 1)) == 0 {
#| return one / x.abs()
#| } else if iy == 1 {
#| return x
#| } else {
#| w = x + y
#| z = w
#| z = set_low_word(z, 0)
#| v = y - (z - x)
#| let a = -one / w
#| let mut t = a
#| t = set_low_word(t, 0)
#| s = one + t * z
#| return t + a * (s + t * v)
#| }
#| }
#| }
#| if ix >= 0x3fe59428 {
#| if hx < 0 {
#| x = -x
#| y = -y
#| }
#| z = pio4 - x
#| w = pio4lo - y
#| x = z + w
#| y = 0.0
#| }
#| z = x * x
#| w = z * z
#| r = t[1] + w * (t[3] + w * (t[5] + w * (t[7] + w * (t[9] + w * t[11]))))
#| v = z *
#| (t[2] + w * (t[4] + w * (t[6] + w * (t[8] + w * (t[10] + w * t[12])))))
#| s = z * x
#| r = y + z * (s * (r + v) + y)
#| r += t[0] * s
#| w = x + r
#| if ix >= 0x3fe59428 {
#| v = iy.to_double()
#| return (1 - ((hx >> 30) & 2)).to_double() *
#| (v - 2.0 * (x - (w * w / (w + v) - r)))
#| }
#| if iy == 1 {
#| w
#| } else {
#| z = w
#| z = set_low_word(z, 0)
#| v = r - (z - x)
#| let a = -1.0 / w
#| let mut t = a
#| t = set_low_word(t, 0)
#| s = 1.0 + t * z
#| t + a * (s + t * v)
#| } }
),
),
"probable_prime": build(
(
#|pub fn probable_prime(bits : Int, rand : @random.Rand) -> @bigint.BigInt { for {
#| let b = rand.bigint(bits)
#| if is_probable_prime(b, rand) {
#| break b
#| }
#| } }
),
),
"trial_divisions": build(
(
#|fn trial_divisions(n : @bigint.BigInt) -> Bool { // calculate the number of trial divisions based on the bit length of the candidate
#| let td = match n.bit_length() {
#| _..=512 => 64
#| 512..=1024 => 128
#| 1024..=2048 => 384
#| 2048..=4096 => 1024
#| _ => 2048
#| }
#| for i in 1.. Double { if x.is_nan() || x.is_inf() {
#| return x
#| }
#| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff
#| let abs_x = x.abs()
#| let shuge = 1.0e307
#| let h = if x < 0.0 { -0.5 } else { 0.5 }
#| if ix < 0x40360000 {
#| if ix < 0x3e300000 {
#| if shuge + x > 1.0 {
#| return x
#| }
#| }
#| let t = expm1(abs_x)
#| if ix < 0x3ff00000 {
#| return h * (2.0 * t - t * t / (t + 1.0))
#| }
#| return h * (t + t / (t + 1.0))
#| }
#| if ix < 0x40862E42 {
#| return h * exp(abs_x)
#| }
#| if abs_x.reinterpret_as_uint64() < 0x408633ce8fb9f87d {
#| let w = exp(0.5 * abs_x)
#| let t = h * w
#| return t * w
#| }
#| x * shuge }
),
),
"cosh": build(
(
#|pub fn cosh(x : Double) -> Double { if x.is_nan() {
#| return x
#| }
#| if x.is_inf() {
#| return @double.infinity
#| }
#| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff
#| if ix < 0x3fd62e43 {
#| let t = expm1(x.abs())
#| let w = 1.0 + t
#| if ix < 0x3c800000 {
#| return w
#| }
#| return 1.0 + t * t / (w + w)
#| }
#| if ix < 0x40360000 {
#| let t = exp(x.abs())
#| return 0.5 * t + 0.5 / t
#| }
#| if ix < 0x40862E42 {
#| return (0.5 * x.abs()) |> exp
#| }
#| let lx = get_low_word(x).reinterpret_as_int()
#| if ix < 0x408633ce || (ix == 0x408633ce && lx <= 0x8fb9f87d) {
#| let w = exp(0.5 * x.abs())
#| let t = 0.5 * w
#| return t * w
#| }
#| @double.infinity }
),
),
"tanh": build(
(
#|pub fn tanh(x : Double) -> Double { if x.is_nan() {
#| return x
#| }
#| if x.is_pos_inf() {
#| return 1.0
#| }
#| if x.is_neg_inf() {
#| return -1.0
#| }
#| let ix = get_high_word(x).reinterpret_as_int() & 0x7fffffff
#| let tiny = 1.0e-300
#| let z = if ix < 0x40360000 {
#| if ix < 0x3c800000 {
#| x * (1.0 + x)
#| } else if ix >= 0x3ff00000 {
#| let t = (2.0 * x.abs()) |> expm1
#| 1.0 - 2.0 / (t + 2.0)
#| } else {
#| let t = (-2.0 * x.abs()) |> expm1
#| -t / (t + 2.0)
#| }
#| } else {
#| 1.0 - tiny
#| }
#| if x >= 0.0 {
#| z
#| } else {
#| -z
#| } }
),
),
"asinh": build(
(
#|pub fn asinh(x : Double) -> Double { if x.is_nan() || x.is_inf() {
#| return x
#| }
#| let one : Double = 1.0
#| let ln2 : Double = 6.93147180559945286227e-01
#| let huge : Double = 1.0e300
#| let hx = get_high_word(x).reinterpret_as_int()
#| let ix = hx & 0x7fffffff
#| if ix < 0x3e300000 {
#| if huge + x > one {
#| return x
#| }
#| }
#| let w : Double = if ix > 0x41b00000 {
#| ln(x.abs()) + ln2
#| } else if ix > 0x40000000 {
#| let t = x.abs()
#| (2.0 * t + one / ((x * x + one).sqrt() + t)) |> ln
#| } else {
#| let t = x * x
#| (x.abs() + t / (one + (one + t).sqrt())) |> ln_1p
#| }
#| if hx > 0 {
#| w
#| } else {
#| -w
#| } }
),
),
"acosh": build(
(
#|pub fn acosh(x : Double) -> Double { let one = 1.0
#| let hx = get_high_word(x).reinterpret_as_int()
#| if x < 1.0 || x.is_nan() {
#| return @double.not_a_number
#| } else if x == 1.0 {
#| return 0.0
#| } else if x.is_pos_inf() {
#| return @double.infinity
#| } else if hx >= 0x41b00000 {
#| return ln(x) + LN2
#| } else if hx > 0x40000000 {
#| let t = x * x
#| return (2.0 * x - one / (x + (t - one).sqrt())) |> ln
#| } else {
#| let t = x - one
#| return (t + (2.0 * t + t * t).sqrt()) |> ln_1p
#| } }
),
),
"atanh": build(
(
#|pub fn atanh(x : Double) -> Double { let hx : Int = get_high_word(x).reinterpret_as_int()
#| let ix = hx & 0x7fffffff
#| if x.abs() > 1.0 {
#| return @double.not_a_number
#| }
#| if x == 1.0 {
#| return @double.infinity
#| }
#| if x == -1.0 {
#| return @double.neg_infinity
#| }
#| if ix < 0x3e300000 && 1.0e300 + x > 0.0 {
#| return x
#| }
#| let x = x.abs()
#| let t = if x <= 0.5 {
#| let t = x + x
#| 0.5 * ln_1p(t + t * x / (1.0 - x))
#| } else {
#| 0.5 * ln_1p((x + x) / (1.0 - x))
#| }
#| if hx >= 0 {
#| t
#| } else {
#| -t
#| } }
),
),
"cbrt": build(
(
#|pub fn cbrt(x : Double) -> Double { if x.is_inf() || x.is_nan() || x == 0.0 {
#| return x
#| }
#| let b1 : UInt = 715094163 // B1 = (682-0.03306235651)*2**20
#| let b2 : UInt = 696219795 // B2 = (664-0.03306235651)*2**20
#| let c = 5.42857142857142815906e-01 // 19/35 = 0x3FE15F15, 0xF15F15F1
#| let d = -7.05306122448979611050e-01 // -864/1225 = 0xBFE691DE, 0x2532C834
#| let e = 1.41428571428571436819e+00 // 99/70 = 0x3FF6A0EA, 0x0EA0EA0F
#| let f = 1.60714285714285720630e+00 // 45/28 = 0x3FF9B6DB, 0x6DB6DB6E
#| let g = 3.57142857142857150787e-01 // 5/14 = 0x3FD6DB6D, 0xB6DB6DB7
#| let hx = get_high_word(x).reinterpret_as_int()
#| let sign = if x < 0.0 { true } else { false }
#| let x = abs(x)
#| let t = if hx < 0x00100000 {
#| let t : UInt64 = 0x43500000_00000000
#| let t : Double = t.reinterpret_as_double()
#| let t = t * x
#| set_high_word(0, get_high_word(t) / 3 + b2)
#| } else {
#| set_high_word(0, hx.reinterpret_as_uint() / 3 + b1)
#| }
#| let r = t * t / x
#| let s = c + r * t
#| let t = t * (g + f / (s + e + d / s))
#| let t = set_high_word(0, get_high_word(t) + 0x00000001)
#| let s = t * t
#| let r = x / s
#| let w = t + t
#| let r = (r - t) / (w + r)
#| let t = t + t * r
#| if sign {
#| -t
#| } else {
#| t
#| } }
),
),
"hypot": build(
(
#|pub fn hypot(x : Double, y : Double) -> Double { if x.is_nan() || y.is_nan() {
#| return @double.not_a_number
#| }
#| if x.is_inf() || y.is_inf() {
#| return @double.infinity
#| }
#| let x = x.abs()
#| let y = y.abs()
#| let double_epsilon : Double = 0x0.0000000000001P-1022
#| let (x, y) = if y > x { (y, x) } else { (x, y) }
#| if x * double_epsilon >= y {
#| return x
#| }
#| let r = y / x
#| x * (1.0 + r * r).sqrt() }
),
),
"pow": build(
(
#|pub fn pow(x : Double, y : Double) -> Double { fn set_low_word(d : Double, v : UInt) -> Double {
#| let bits : UInt64 = d.reinterpret_as_uint64()
#| let bits = bits & 0xFFFF_FFFF_0000_0000
#| let bits = bits | v.to_uint64()
#| bits.reinterpret_as_double()
#| }
#| fn set_high_word(d : Double, v : UInt) -> Double {
#| let bits : UInt64 = d.reinterpret_as_uint64()
#| let bits = bits & 0x0000_0000_FFFF_FFFF
#| let bits = bits | (v.to_uint64() << 32)
#| bits.reinterpret_as_double()
#| }
#| fn get_high_word(x : Double) -> UInt {
#| (x.reinterpret_as_uint64() >> 32).to_uint()
#| }
#| fn get_low_word(x : Double) -> UInt {
#| x.reinterpret_as_uint64().to_uint()
#| }
#| // double z, ax, z_h, z_l, p_h, p_l;
#| let mut z : Double = 0.0
#| let mut ax : Double = 0.0
#| let mut z_h : Double = 0.0
#| let mut z_l : Double = 0.0
#| let mut p_h : Double = 0.0
#| let mut p_l : Double = 0.0
#| // double y1, t1, t2, r, s, t, u, v, w
#| let mut y1 : Double = 0.0
#| let mut t1 : Double = 0.0
#| let mut t2 : Double = 0.0
#| let mut r : Double = 0.0
#| let mut s : Double = 0.0
#| let mut t : Double = 0.0
#| let mut u : Double = 0.0
#| let mut v : Double = 0.0
#| let mut w : Double = 0.0
#| // int i, j, k, yisint, n
#| let mut i : Int = 0
#| let mut j : Int = 0
#| let mut k : Int = 0
#| let mut yisint : Int = 0
#| let mut n : Int = 0
#| // int hx, hy, ix, iy;
#| // unsigned lx, ly;
#| //
#| // EXTRACT_WORDS(hx, lx, x);
#| // EXTRACT_WORDS(hy, ly, y);
#| // ix = hx & 0x7fffffff;
#| // iy = hy & 0x7fffffff;
#| let hx : Int = (x.reinterpret_as_uint64() >> 32).to_int()
#| let lx : UInt = (x.reinterpret_as_uint64() & 0xFFFFFFFF).to_uint()
#| let hy : Int = (y.reinterpret_as_uint64() >> 32).to_int()
#| let ly : UInt = (y.reinterpret_as_uint64() & 0xFFFFFFFF).to_uint()
#| let mut ix : Int = hx & 0x7FFFFFFF
#| let iy : Int = hy & 0x7FFFFFFF
#| // y==zero: x**0 = 1
#| if (iy.reinterpret_as_uint() | ly) == 0 {
#| return ONE
#| }
#| // +-NaN return x+y
#| if ix > 0x7FF00000 ||
#| (ix == 0x7FF00000 && lx != 0) ||
#| iy > 0x7FF00000 ||
#| (iy == 0x7FF00000 && ly != 0) {
#| return x + y
#| }
#| // determine if y is an odd int when x < 0
#| // yisint = 0 ... y is not an integer
#| // yisint = 1 ... y is an odd int
#| // yisint = 2 ... y is an even int
#| if hx < 0 {
#| if iy >= 0x43400000 {
#| yisint = 2 // even integer y
#| } else if iy >= 0x3ff00000 {
#| k = (iy >> 20) - 0x3ff // exponent
#| if k > 20 {
#| j = (ly >> (52 - k)).reinterpret_as_int()
#| if j << (52 - k) == ly.reinterpret_as_int() {
#| yisint = 2 - (j & 1)
#| }
#| } else if ly == 0 {
#| j = iy >> (20 - k)
#| if j << (20 - k) == iy {
#| yisint = 2 - (j & 1)
#| }
#| }
#| }
#| }
#| // special value of y
#| if ly == 0 {
#| if iy == 0x7ff00000 { // y is +-inf
#| if ((ix.reinterpret_as_uint() - 0x3ff00000) | lx) == 0 {
#| return y - y // inf**+-1 is NaN
#| } else if ix >= 0x3ff00000 { // (|x|>1)**+-inf = inf,0
#| return if hy >= 0 { y } else { ZERO }
#| } else { // (|x|<1)**-,+inf = inf,0
#| return if hy < 0 { -y } else { ZERO }
#| }
#| }
#| if iy == 0x3ff00000 { // y is +-1
#| if hy < 0 {
#| return ONE / x
#| } else {
#| return x
#| }
#| }
#| if hy == 0x40000000 { // y is 2
#| return x * x
#| }
#| if hy == 0x3fe00000 { // y is 0.5
#| if hx >= 0 { // x >= +0
#| return x.sqrt()
#| }
#| }
#| }
#| ax = x.abs()
#| // special value of x
#| if lx == 0 {
#| if ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000 {
#| z = ax // x is +-0,+-inf,+-1 */
#| if hy < 0 {
#| z = ONE / z // z = (1/|x|)
#| }
#| if hx < 0 {
#| if ((ix - 0x3ff00000) | yisint) == 0 {
#| // (-1)**non-int is NaN
#| z = @double.not_a_number
#| } else if yisint == 1 {
#| z = -z // (x<0)**odd = -(|x|**odd)
#| }
#| }
#| return z
#| }
#| }
#| n = (hx >> 31) + 1
#| // (x<0)**(non-int) is NaN
#| if (n | yisint) == 0 {
#| return @double.not_a_number
#| }
#| s = ONE // s (sign of result -ve**odd) = -1 else = 1
#| if (n | (yisint - 1)) == 0 {
#| s = -ONE // (-ve)**(odd int)
#| }
#| // |y| is huge
#| if iy > 0x41e00000 { // if |y| > 2**31 */
#| if iy > 0x43f00000 { // if |y| > 2**64, must o/uflow */
#| if ix <= 0x3fefffff {
#| return if hy < 0 { POW_huge * POW_huge } else { POW_tiny * POW_tiny }
#| }
#| if ix >= 0x3ff00000 {
#| return if hy > 0 { POW_huge * POW_huge } else { POW_tiny * POW_tiny }
#| }
#| }
#| // over/underflow if x is not close to one */
#| if ix < 0x3fefffff {
#| return if hy < 0 {
#| s * POW_huge * POW_huge
#| } else {
#| s * POW_tiny * POW_tiny
#| }
#| }
#| if ix > 0x3ff00000 {
#| return if hy > 0 {
#| s * POW_huge * POW_huge
#| } else {
#| s * POW_tiny * POW_tiny
#| }
#| }
#| // now |1-x| is tiny <= 2**-20, suffice to compute
#| // log(x) by x-x^2/2+x^3/3-x^4/4 */
#| t = ax - ONE // t has 20 trailing zeros */
#| w = t * t * (0.5 - t * (0.3333333333333333333333 - t * 0.25))
#| u = POW_ivln2_h * t // POW_ivln2_h has 21 sig. bits */
#| v = t * POW_ivln2_l - w * POW_ivln2
#| t1 = u + v
#| t1 = set_low_word(t1, 0)
#| t2 = v - (t1 - u)
#| } else {
#| n = 0
#| // take care subnormal number
#| if ix < 0x00100000 {
#| ax *= POW_two53
#| n -= 53
#| ix = get_high_word(ax).reinterpret_as_int()
#| }
#| n += (ix >> 20) - 0x3ff
#| j = ix & 0x000fffff
#| // determine interval
#| ix = j | 0x3ff00000 // normalize ix
#| if j <= 0x3988E {
#| k = 0 // |x|> 1) | 0x20000000) +
#| 0x00080000 +
#| (k.reinterpret_as_uint() << 18),
#| )
#| let mut t_l : Double = ax - (t_h - pow_bp[k])
#| let s_l : Double = v * (u - s_h * t_h - s_h * t_l)
#| // compute log(ax)
#| let mut s2 : Double = ss * ss
#| r = s2 *
#| s2 *
#| (
#| POW_L1 +
#| s2 *
#| (POW_L2 + s2 * (POW_L3 + s2 * (POW_L4 + s2 * (POW_L5 + s2 * POW_L6))))
#| )
#| r += s_l * (s_h + ss)
#| s2 = s_h * s_h
#| t_h = 3.0 + s2 + r
#| t_h = set_low_word(t_h, 0)
#| t_l = r - (t_h - 3.0 - s2)
#| // u+v = ss*(1+...)
#| u = s_h * t_h
#| v = s_l * t_h + t_l * ss
#| // 2/(3log2)*(ss+...)
#| p_h = u + v
#| p_h = set_low_word(p_h, 0)
#| p_l = v - (p_h - u)
#| z_h = POW_cp_h * p_h // cp_h+cp_l = 2/(3*log2)
#| z_l = POW_cp_l * p_h + p_l * POW_cp + pow_dp_l[k]
#| // log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l
#| t = n.to_double()
#| t1 = z_h + z_l + pow_dp_h[k] + t
#| t1 = set_low_word(t1, 0)
#| t2 = z_l - (t1 - t - pow_dp_h[k] - z_h)
#| }
#| // split up y into y1+y2 and compute (y1+y2)*(t1+t2)
#| y1 = y
#| y1 = set_low_word(y1, 0)
#| p_l = (y - y1) * t1 + y * t2
#| p_h = y1 * t1
#| z = p_l + p_h
#| j = get_high_word(z).reinterpret_as_int()
#| i = get_low_word(z).reinterpret_as_int()
#| if j >= 0x40900000 { // z >= 1024
#| if ((j - 0x40900000) | i) != 0 { // if z > 1024
#| return s * POW_huge * POW_huge // overflow
#| } else if p_l + POW_ovt > z - p_h {
#| return s * POW_huge * POW_huge // overflow
#| }
#| } else if (j & 0x7fffffff) >= 0x4090cc00 { // z <= -1075
#| if ((j - 0xc090cc00) | i) != 0 { // z < -1075
#| return s * POW_tiny * POW_tiny // underflow
#| } else if p_l <= z - p_h {
#| return s * POW_tiny * POW_tiny // underflow
#| }
#| }
#| //
#| // compute 2**(p_h+p_l)
#| //
#| i = j & 0x7fffffff
#| k = (i >> 20) - 0x3ff
#| n = 0
#| if i > 0x3fe00000 { // if |z| > 0.5, set n = [z+0.5]
#| n = j + (0x00100000 >> (k + 1))
#| k = ((n & 0x7fffffff) >> 20) - 0x3ff // new k for n
#| t = ZERO
#| t = set_high_word(t, (n & (0x000fffff >> k).lnot()).reinterpret_as_uint())
#| n = ((n & 0x000fffff) | 0x00100000) >> (20 - k)
#| if j < 0 {
#| n = -n
#| }
#| p_h -= t
#| }
#| t = p_l + p_h
#| t = set_low_word(t, 0)
#| u = t * POW_lg2_h
#| v = (p_l - (t - p_h)) * POW_lg2 + t * POW_lg2_l
#| z = u + v
#| w = v - (z - u)
#| t = z * z
#| t1 = z -
#| t * (POW_P1 + t * (POW_P2 + t * (POW_P3 + t * (POW_P4 + t * POW_P5))))
#| r = z * t1 / (t1 - TWO - (w + z * w))
#| z = ONE - (r - z)
#| j = get_high_word(z).reinterpret_as_int()
#| j += (n.reinterpret_as_uint() << 20).reinterpret_as_int()
#| if j >> 20 <= 0 {
#| z = scalbn(z, n)
#| } else { // subnormal output */
#| let tmp = get_high_word(z).reinterpret_as_int()
#| z = set_high_word(
#| z,
#| (tmp + (n.reinterpret_as_uint() << 20).reinterpret_as_int()).reinterpret_as_uint(),
#| )
#| }
#| return s * z }
),
),
"maximum": build(
(
#|pub fn[T : Compare] maximum(x : T, y : T) -> T { if x > y {
#| x
#| } else {
#| y
#| } }
),
),
"minimum": build(
(
#|pub fn[T : Compare] minimum(x : T, y : T) -> T { if x > y {
#| y
#| } else {
#| x
#| } }
),
),
"cbrtf": build(
(
#|pub fn cbrtf(x : Float) -> Float { let b1 : UInt = 709958130 // B1 = (127-127.0/3-0.03306235651)*2**23 */
#| let b2 : UInt = 642849266 // B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */
#| let mut ui : UInt = x.reinterpret_as_uint()
#| let mut hx : UInt = ui & 0x7fffffff
#| if hx >= 0x7f800000 {
#| // cbrt(NaN,INF) is itx
#| return x + x
#| }
#| // rough cbrt to 5 bits
#| if hx < 0x00800000 {
#| // zero or subnormal?
#| if hx == 0 {
#| return x
#| } // cbrt(+-0) is itx
#| ui = (x * (0x1.0p24 : Float)).reinterpret_as_uint()
#| hx = ui & 0x7fffffff
#| hx = hx / 3 + b2
#| } else {
#| hx = hx / 3 + b1
#| }
#| ui = ui & 0x80000000
#| ui = ui | hx
#| //
#| // First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In
#| // double precision so that its terms can be arranged for efficiency
#| // without causing overflow or underflow.
#| //
#| let dx = x.to_double()
#| let t = ui.reinterpret_as_float().to_double()
#| let r = t * t * t
#| let t = t * (dx + dx + r) / (dx + r + r)
#| //
#| // Second step Newton iteration to 47 bits. In double precision for
#| // efficiency and accuracy.
#| //
#| let r = t * t * t
#| let t = t * (dx + dx + r) / (dx + r + r)
#| // rounding to 24 bits is perfect in round-to-nearest mode
#| t.to_float() }
),
),
"hypotf": build(
(
#|pub fn hypotf(x : Float, y : Float) -> Float { let epsilon : Float = 1.1920928955078125e-7
#| let x = x.abs()
#| let y = y.abs()
#| if x.is_inf() || y.is_inf() {
#| return @float.infinity
#| }
#| let (x, y) = if y > x { (y, x) } else { (x, y) }
#| if x * epsilon >= y {
#| return x
#| }
#| let rat = y / x
#| x * (rat * rat + 1.0).sqrt() }
),
),
"pi": (None, String("0x3.243F6A8885A308CA8A54")),
"exp": build(
(
#|pub fn exp(x : Double) -> Double { fn get_high_word(x : Double) -> UInt {
#| (x.reinterpret_as_uint64() >> 32).to_uint()
#| }
#| fn get_low_word(x : Double) -> UInt {
#| x.reinterpret_as_uint64().to_uint()
#| }
#| fn insert_words(ix0 : UInt64, ix1 : UInt64) -> Double {
#| let mut bits : UInt64 = 0
#| bits = bits | (ix0 << 32)
#| bits = bits | ix1
#| bits.reinterpret_as_double()
#| }
#| let ori_x = x
#| let mut x = x
#| let one = 1.0
#| let halF = [0.5, -0.5]
#| let o_threshold = 7.09782712893383973096e+02
#| let u_threshold = -7.45133219101941108420e+02
#| let ln2HI = [6.93147180369123816490e-01, -6.93147180369123816490e-01]
#| let ln2LO = [1.90821492927058770002e-10, -1.90821492927058770002e-10]
#| let invln2 = 1.44269504088896338700e+00
#| let p1 = 1.66666666666666019037e-01
#| let p2 = -2.77777777770155933842e-03
#| let p3 = 6.61375632143793436117e-05
#| let p4 = -1.65339022054652515390e-06
#| let p5 = 4.13813679705723846039e-08
#| let e = 2.718281828459045
#| let mut hi = 0.0
#| let mut lo = 0.0
#| let huge = 1.0e+300
#| let twom1000 = 9.33263618503218878990e-302
#| let two1023 = 8.988465674311579539e307
#| let mut k : Int = 0
#| let mut hx : UInt = get_high_word(ori_x)
#| let xsb : Int = ((hx >> 31) & 1).reinterpret_as_int()
#| hx = hx & 0x7FFFFFFF
#| if hx >= 0x40862E42 {
#| if hx >= 0x7FF00000 {
#| let lx : UInt = get_low_word(ori_x)
#| if ((hx & 0xFFFFF) | lx) != 0 {
#| return ori_x + ori_x
#| } else if xsb == 0 {
#| return ori_x
#| } else {
#| return 0.0
#| }
#| }
#| if ori_x > o_threshold {
#| return huge * huge
#| }
#| if ori_x < u_threshold {
#| return twom1000 * twom1000
#| }
#| }
#| if hx > 0x3FD62E42 {
#| if hx < 0x3FF0A2B2 {
#| if ori_x == 1.0 {
#| return e
#| }
#| hi = ori_x - ln2HI[xsb]
#| lo = ln2LO[xsb]
#| k = 1 - xsb - xsb
#| } else {
#| k = (invln2 * ori_x + halF[xsb]).to_int()
#| let t = k.to_double()
#| hi = ori_x - t * ln2HI[0]
#| lo = t * ln2LO[0]
#| }
#| x = hi - lo
#| } else if hx < 0x3E300000 {
#| if huge + x > one {
#| return one + x
#| }
#| } else {
#| k = 0
#| }
#| let t = x * x
#| let twopk = if k >= -1021 {
#| insert_words(
#| (0x3FF00000 + (k.reinterpret_as_uint() << 20).reinterpret_as_int())
#| .to_int64()
#| .reinterpret_as_uint64(),
#| 0,
#| )
#| } else {
#| insert_words(
#| 0x3FF00000UL + ((k + 1000).reinterpret_as_uint() << 20).to_uint64(),
#| 0,
#| )
#| }
#| let c = x - t * (p1 + t * (p2 + t * (p3 + t * (p4 + t * p5))))
#| if k == 0 {
#| return one - (x * c / (c - 2.0) - x)
#| }
#| let y = one - (lo - x * c / (2.0 - c) - hi)
#| if k >= -1021 {
#| if k == 1024 {
#| return y * 2.0 * two1023
#| } else {
#| return y * twopk
#| }
#| } else {
#| return y * twopk * twom1000
#| } }
),
),
"expm1": build(
(
#|pub fn expm1(x : Double) -> Double { if x.is_nan() {
#| return @double.not_a_number
#| }
#| let o_threshold = 7.09782712893383973096e+02
#| if x > o_threshold {
#| return @double.infinity
#| }
#| if x.is_inf() {
#| return -1.0
#| }
#| let huge = 1.0e+300
#| let tiny = 1.0e-300
#| let ln2_hi = 6.93147180369123816490e-01
#| let ln2_lo = 1.90821492927058770002e-10
#| let invln2 = 1.44269504088896338700e+00
#| let q1 = -3.33333333333331316428e-02
#| let q2 = 1.58730158725481460165e-03
#| let q3 = -7.93650757867487942473e-05
#| let q4 = 4.00821782732936239552e-06
#| let q5 = -2.01099218183624371326e-07
#| let mut x = x
#| let mut hx = get_high_word(x)
#| let xsb : Int = (hx & 0x80000000).reinterpret_as_int()
#| let mut y : Double = if xsb == 0 { x } else { -x }
#| hx = hx & 0x7fffffff
#| if hx >= 0x4043687A {
#| if xsb != 0 {
#| if x + tiny < 0.0 {
#| return tiny - 1.0
#| }
#| }
#| }
#| let mut hi = 0.0
#| let mut lo = 0.0
#| let mut k = 0
#| let mut c = 0.0
#| let mut t = 0.0
#| if hx > 0x3fd62e42 {
#| if hx < 0x3FF0A2B2 {
#| hi = if xsb == 0 { x - ln2_hi } else { x + ln2_hi }
#| lo = if xsb == 0 { ln2_lo } else { -ln2_lo }
#| k = if xsb == 0 { 1 } else { -1 }
#| } else {
#| k = (invln2 * x + (if xsb == 0 { 0.5 } else { -0.5 })).to_int()
#| t = k.to_double()
#| hi = x - t * ln2_hi
#| lo = t * ln2_lo
#| }
#| x = hi - lo
#| c = hi - x - lo
#| } else if hx < 0x3c900000 {
#| t = huge + x
#| return x - (t - (huge + x))
#| } else {
#| k = 0
#| }
#| let hfx : Double = 0.5 * x
#| let hxs : Double = x * hfx
#| let r1 : Double = 1.0 +
#| hxs * (q1 + hxs * (q2 + hxs * (q3 + hxs * (q4 + hxs * q5))))
#| let t : Double = 3.0 - r1 * hfx
#| let e : Double = hxs * ((r1 - t) / (6.0 - x * t))
#| if k == 0 {
#| return x - (x * e - hxs)
#| } else {
#| let e : Double = x * (e - c) - c
#| let e : Double = e - hxs
#| if k == -1 {
#| return 0.5 * (x - e) - 0.5
#| }
#| if k == 1 {
#| return if x < -0.25 {
#| -2.0 * (e - (x + 0.5))
#| } else {
#| 1.0 + 2.0 * (x - e)
#| }
#| }
#| if k <= -2 || k > 56 {
#| y = 1.0 - (e - x)
#| y = set_high_word(y, get_high_word(y) + (k << 20).reinterpret_as_uint())
#| return y - 1.0
#| }
#| let mut t : Double = 1.0
#| if k < 20 {
#| t = set_high_word(0, (0x3ff00000 - (0x200000 >> k)).reinterpret_as_uint())
#| y = t - (e - x)
#| y = set_high_word(y, get_high_word(y) + (k << 20).reinterpret_as_uint())
#| } else {
#| t = set_high_word(0, ((0x3ff - k) << 20).reinterpret_as_uint())
#| y = x - (e + t) + 1.0
#| y = set_high_word(y, get_high_word(y) + (k << 20).reinterpret_as_uint())
#| }
#| }
#| y }
),
),
"abs": build(
(
#|fn abs(x : Double) -> Double { if x < 0.0 {
#| -x
#| } else {
#| x
#| } }
),
),
"set_low_word": build(
(
#|fn set_low_word(d : Double, v : UInt) -> Double { let bits : UInt64 = d.reinterpret_as_uint64()
#| let bits = bits & 0xFFFF_FFFF_0000_0000
#| let bits = bits | v.to_uint64()
#| bits.reinterpret_as_double() }
),
),
"set_high_word": build(
(
#|fn set_high_word(d : Double, v : UInt) -> Double { let bits : UInt64 = d.reinterpret_as_uint64()
#| let bits = bits & 0x0000_0000_FFFF_FFFF
#| let bits = bits | (v.to_uint64() << 32)
#| bits.reinterpret_as_double() }
),
),
"get_high_word": build(
(
#|fn get_high_word(x : Double) -> UInt { (x.reinterpret_as_uint64() >> 32).to_uint() }
),
),
"get_low_word": build(
(
#|fn get_low_word(x : Double) -> UInt { x.reinterpret_as_uint64().to_uint() }
),
),
"normalize": build(
(
#|fn normalize(f : Double) -> (Double, Int) { if f.abs() < @double.min_positive {
#| return (f * (1L << 52).to_double(), -52)
#| }
#| (f, 0) }
),
),
"frexp": build(
(
#|fn frexp(f : Double) -> (Double, Int) { if f == 0.0 || f.is_inf() || f.is_nan() {
#| return (f, 0)
#| }
#| let (norm_f, exp) = normalize(f)
#| let u = norm_f.reinterpret_as_uint64()
#| let exp = exp + ((u >> 52) & 0x7FF).to_int() - 1022
#| let frac = ((u & (0x7FFUL << 52).lnot()) | (1022UL << 52)).reinterpret_as_double()
#| return (frac, exp) }
),
),
"logf_off": (None, UInt(0x3f330000U)),
"logf_table_bits": (None, Int(4)),
"lnf": build(
(
#|pub fn lnf(x : Float) -> Float { let mut ix : UInt = x.reinterpret_as_uint()
#| if ix == 0x3f800000U {
#| return 0.0
#| }
#| if ix - 0x00800000U >= 0x7f800000U - 0x00800000U {
#| if ix * 2 == 0 {
#| return @float.neg_infinity
#| }
#| if ix == 0x7f800000U {
#| return x
#| }
#| if (ix & 0x80000000U) != 0 || ix * 2 >= 0xff000000U {
#| return @float.not_a_number
#| }
#| ix = (x * 0x1.0p23).reinterpret_as_uint()
#| ix -= (23 << 23).reinterpret_as_uint()
#| }
#| let tmp = ix - logf_off
#| let i = ((tmp >> (23 - logf_table_bits)) % logf_n).reinterpret_as_int()
#| let k = tmp.reinterpret_as_int() >> 23
#| let iz = ix - (tmp & 0xff800000U)
#| let invc = logf_data.invc[i]
#| let logc = logf_data.logc[i]
#| let z = iz.reinterpret_as_float().to_double()
#| let r = z * invc - 1
#| let y0 = logc + k.to_double() * logf_data.ln2
#| let r2 = r * r
#| let y = logf_data.poly[1] * r + logf_data.poly[2]
#| let y = logf_data.poly[0] * r2 + y
#| let y = y * r2 + (y0 + r)
#| y.to_float() }
),
),
"ln_1pf": build(
(
#|pub fn ln_1pf(x : Float) -> Float { let lg1_f : Float = 0.66666662693
#| let lg2_f : Float = 0.40000972152
#| let lg3_f : Float = 0.28498786688
#| let lg4_f : Float = 0.24279078841
#| let float_ln2_hi : Float = 6.9314575195e-01 // 0x3f317200
#| let float_ln2_lo : Float = 1.4286067653e-06 // 0x35bfbe8e
#| let mut ui : UInt = x.reinterpret_as_uint()
#| let mut f : Float = 0
#| let mut c : Float = 0
#| let mut iu : UInt = 0
#| let one : Float = 1.0
#| let mut k = 1
#| if ui < 0x3ed413d0 || ui >> 31 > 0 {
#| if ui >= 0xbf800000 {
#| if x == -1.0 {
#| return x / 0.0
#| }
#| return (x - x) / 0.0
#| }
#| if ui << 1 < 0x33800000U << 1 {
#| return x
#| }
#| if ui <= 0xbe95f619 {
#| k = 0
#| c = 0.0
#| f = x
#| }
#| } else if ui >= 0x7f800000 {
#| return x
#| }
#| if k > 0 {
#| ui = (one + x).reinterpret_as_uint()
#| iu = ui
#| iu += 0x3f800000U - 0x3f3504f3U
#| k = (iu >> 23).reinterpret_as_int() - 0x7f
#| if k < 25 {
#| let fui = ui.reinterpret_as_float()
#| c = if k >= 2 { one - (fui - x) } else { x - (fui - 1.0) }
#| c /= ui.reinterpret_as_float()
#| } else {
#| c = 0.0
#| }
#| iu = (iu & 0x007fffff) + 0x3f3504f3
#| ui = iu
#| f = ui.reinterpret_as_float() - 1.0
#| }
#| let s = f / (f + 2.0)
#| let z = s * s
#| let w = z * z
#| let t1 = w * (lg2_f + w * lg4_f)
#| let t2 = z * (lg1_f + w * lg3_f)
#| let r = t2 + t1
#| let hfsq = f * f * 0.5
#| let dk = k.to_float()
#| s * (hfsq + r) + (dk * float_ln2_lo + c) - hfsq + f + dk * float_ln2_hi }
),
),
"k_expo2f": build(
(
#|fn k_expo2f(x : Float) -> Float { let k = 235
#| let k_ln2 = (0x4322e3bc).reinterpret_as_float()
#| // note that k is odd and scale*scale overflows */
#| let scale = ((0x7f + k / 2) << 23).reinterpret_as_float()
#| // exp(x - k ln2) * 2**(k-1) */
#| expf(x - k_ln2) * scale * scale }
),
),
"sinhf": build(
(
#|pub fn sinhf(x : Float) -> Float { let mut h : Float = 0.5
#| let mut ix = x.reinterpret_as_uint()
#| if ix >> 31 != 0 {
#| h = -h
#| }
#| // |x|
#| ix = ix & 0x7fffffff
#| let absx = ix.reinterpret_as_float()
#| let w = ix
#| // |x| < log(FLT_MAX)
#| if w < 0x42b17217 {
#| let t = expm1f(absx)
#| if w < 0x3f800000 {
#| if w < 0x3f800000U - (12U << 23) {
#| return x
#| }
#| return h * ((2.0 : Float) * t - t * t / (t + 1.0))
#| }
#| return h * (t + t / (t + 1.0))
#| }
#| // |x| > logf(FLT_MAX) or nan
#| h * k_expo2f(absx) * 2.0 }
),
),
"coshf": build(
(
#|pub fn coshf(x : Float) -> Float { let mut x = x
#| let mut ix = x.reinterpret_as_uint()
#| ix = ix & 0x7fffffff
#| x = ix.reinterpret_as_float()
#| let w = ix
#| // |x| < log(2)
#| if w < 0x3f317217 {
#| if w < 0x3f800000U - (12U << 23) {
#| return 1.0
#| }
#| let t = expm1f(x)
#| return (1.0 : Float) + t * t / ((2.0 : Float) * (t + 1.0))
#| }
#| // |x| < log(FLT_MAX)
#| if w < 0x42b17217 {
#| let t = expf(x)
#| return (t + (1.0 : Float) / t) * 0.5
#| }
#| // |x| > log(FLT_MAX) or nan
#| k_expo2f(x) }
),
),
"tanhf": build(
(
#|pub fn tanhf(x : Float) -> Float { let mut ix = x.reinterpret_as_uint()
#| let sign = ix >> 31 != 0
#| ix = ix & 0x7fffffff
#| let x = ix.reinterpret_as_float()
#| let w = ix
#| let tt = if w > 0x3f0c9f54 {
#| // |x| > log(3)/2 ~= 0.5493 or nan
#| if w > 0x41200000 {
#| // |x| > 10
#| (1.0 : Float) + (0.0 : Float) / x
#| } else {
#| let t = expm1f(x * 2.0)
#| (1.0 : Float) - (2.0 : Float) / (t + 2.0)
#| }
#| } else if w > 0x3e82c578 {
#| // |x| > log(5/3)/2 ~= 0.2554
#| let t = expm1f(x * 2.0)
#| t / (t + 2.0)
#| } else if w >= 0x00800000 {
#| // |x| >= 0x1p-126
#| let t = expm1f(x * -2.0)
#| -t / (t + 2.0)
#| } else {
#| // |x| is subnormal
#| x
#| }
#| if sign {
#| -tt
#| } else {
#| tt
#| } }
),
),
"asinhf": build(
(
#|pub fn asinhf(x : Float) -> Float { let u = x.reinterpret_as_uint()
#| let i = u & 0x7fffffff
#| let sign = u >> 31 != 0
#| let ln2 : Float = 0.693147180559945309417232121458176568
#| let x = i.reinterpret_as_float()
#| let x = if i >= 0x3f800000U + (12U << 23) {
#| // |x| >= 0x1p12 or inf or nan
#| lnf(x) + ln2
#| } else if i >= 0x3f800000U + (1U << 23) {
#| // |x| >= 2
#| lnf(x * 2.0 + (1.0 : Float) / ((x * x + 1.0).sqrt() + x))
#| } else if i >= 0x3f800000U - (12U << 23) {
#| // |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5]
#| ln_1pf(x + x * x / ((x * x + 1.0).sqrt() + 1.0))
#| } else {
#| // |x| < 0x1p-12, raise inexact if x!=0
#| // x + 0x1.0p120
#| x
#| }
#| if sign {
#| -x
#| } else {
#| x
#| } }
),
),
"acoshf": build(
(
#|pub fn acoshf(x : Float) -> Float { let ln2 : Float = 693147180559945309417232121458176568
#| let u = x.reinterpret_as_uint()
#| let a = u & 0x7fffffffU
#| if a < 0x3f800000U + (1U << 23) {
#| // |x| < 2, invalid if x < 1 or nan
#| // up to 2ulp error in [1,1.125]
#| return ln_1pf(
#| x - 1.0 + ((x - 1.0) * (x - 1.0) + (2.0 : Float) * (x - 1.0)).sqrt(),
#| )
#| }
#| if a < 0x3f800000U + (12U << 23) {
#| // |x| < 0x1p12
#| return lnf(x * 2.0 - (1.0 : Float) / (x + (x * x - 1.0).sqrt()))
#| }
#| // x >= 0x1p12
#| return lnf(x) + ln2 }
),
),
"atanhf": build(
(
#|pub fn atanhf(x : Float) -> Float { let u = x.reinterpret_as_uint()
#| let sign = u >> 31 != 0
#| let u = u & 0x7fffffff
#| let x = u.reinterpret_as_float()
#| let x = if u < 0x3f800000U - (1U << 23) {
#| if u < 0x3f800000U - (32U << 23) {
#| x
#| } else {
#| // |x| < 0.5, up to 1.7ulp error
#| ln_1pf(x * 2.0 + x * 2.0 * x / ((1.0 : Float) - x)) * 0.5
#| }
#| } else {
#| // avoid overflow
#| ln_1pf(x / ((1.0 : Float) - x) * 2.0) * 0.5
#| }
#| if sign {
#| -x
#| } else {
#| x
#| } }
),
),
"mulh": build(
(
#|fn mulh(a : UInt, b : UInt) -> UInt { let a = a.to_uint64()
#| let b = b.to_uint64()
#| let res = a * b
#| (res >> 32).to_uint() }
),
),
"mul": build(
(
#|fn mul(a : UInt, b : UInt) -> (UInt, UInt) { let a = a.to_uint64()
#| let b = b.to_uint64()
#| let res = a * b
#| ((res >> 32).to_uint(), res.to_uint()) }
),
),
"trig_reduce": build(
(
#|fn trig_reduce(x : Float, switch_over : Float) -> (Float, Int) { if x.abs() <= switch_over {
#| let mut j : Float = 0.0
#| let mut r : Float = 0.0
#| j = x * (0x3f22f983).reinterpret_as_float() +
#| (0x4b40_0000).reinterpret_as_float()
#| j = (j.reinterpret_as_int() - 0x4b40_0000).to_float()
#| r = x - j * (0x3fc90f80).reinterpret_as_float()
#| r = r - j * (0x37354440).reinterpret_as_float()
#| r = r - j * (0x2c34611a).reinterpret_as_float()
#| return (r, j.to_int())
#| }
#| let xispos = x > 0.0
#| let mut exp : Int = ((x.reinterpret_as_int() >> 23) & 0xff) - 126
#| let ix = ((x.reinterpret_as_uint() & 0x007fffff) << 8) | 0x80000000
#| let ind = exp >> 5
#| exp = exp & 0x1f
#| let two_over_pi : Array[UInt] = [
#| 0x00000000, 0x28be60db, 0x9391054a, 0x7f09d5f4, 0x7d4d3770, 0x36d8a566, 0x4f10e410,
#| 0000000000,
#| ]
#| let mut hi = two_over_pi[ind]
#| let mut mi = two_over_pi[ind + 1]
#| let mut lo = two_over_pi[ind + 2]
#| let tp = two_over_pi[ind + 3]
#| if exp > 0 {
#| hi = (hi << exp) | (mi >> (32 - exp))
#| mi = (mi << exp) | (lo >> (32 - exp))
#| lo = (lo << exp) | (tp >> (32 - exp))
#| }
#| let phi = 0U
#| let (h, l) = mul(ix, lo)
#| let plo = phi + l
#| let phi = h + (if plo < l { 1 } else { 0 })
#| let (h, l) = mul(ix, mi)
#| let mut plo = phi + l
#| let phi = h + (if plo < l { 1 } else { 0 })
#| let l = ix * hi
#| let mut phi = phi + l
#| let mut q : Int = (phi >> 30).reinterpret_as_int()
#| phi = phi & 0x3fffffff
#| if (phi & 0x2000_0000) != 0 {
#| phi = phi - 0x4000_0000
#| q = q + 1
#| }
#| let s : UInt = phi & 0x8000_0000
#| if phi >= 0x8000_0000 {
#| phi = phi.lnot()
#| plo = 0U - plo
#| //phi += (plo == 0).to_uint()
#| phi += if plo == 0 { 1 } else { 0 }
#| }
#| exp = 0
#| while phi < 0x8000_0000 {
#| phi = (phi << 1) | (plo >> 31)
#| plo = plo << 1
#| exp = exp - 1
#| }
#| phi = mulh(phi, 0xc90f_daa2)
#| if phi < 0x8000_0000 {
#| phi = phi << 1
#| exp = exp - 1
#| }
#| let mut r = s +
#| ((exp + 128) << 23).reinterpret_as_uint() +
#| (phi >> 8) +
#| (if (phi & 0xff) > 0x7e { 1 } else { 0 })
#| if !xispos {
#| r = r ^ 0x8000_0000
#| q = -q
#| }
#| let r = r.reinterpret_as_float()
#| return (r, q) }
),
),
"sinf_poly": build(
(
#|fn sinf_poly(x : Float) -> Float { let s = x * x
#| let mut r = (0x3640_5000).reinterpret_as_float()
#| r = r * s - (0x3950_3486).reinterpret_as_float()
#| r = r * s + (0x3c08_88c1).reinterpret_as_float()
#| r = r * s - (0x3e2a_aaab).reinterpret_as_float()
#| let t = x * s
#| r = r * t + x
#| r }
),
),
"cosf_poly": build(
(
#|fn cosf_poly(x : Float) -> Float { let s = x * x
#| let mut r = (0x37cd_4000).reinterpret_as_float()
#| r = r * s - (0x3ab6_077d).reinterpret_as_float()
#| r = r * s + (0x3d2a_aaa8).reinterpret_as_float()
#| r = r * s - (0x3f00_0000).reinterpret_as_float()
#| r = r * s + (0x3f80_0000).reinterpret_as_float()
#| r }
),
),
"sin_cos_core": build(
(
#|fn sin_cos_core(x : Float, q : Int) -> Float { let mut r = if (q & 1) != 0 { cosf_poly(x) } else { sinf_poly(x) }
#| if (q & 2) != 0 {
#| r = -r
#| }
#| r }
),
),
"tanf_poly": build(
(
#|fn tanf_poly(x : Float, odd : Bool) -> Float { let x = x.to_double()
#| let coef : FixedArray[Double] = [
#| 0.333331395030791399758, // 0x15554d3418c99f.0p-54 */
#| 0.133392002712976742718, // 0x1112fd38999f72.0p-55 */
#| 0.0533812378445670393523, // 0x1b54c91d865afe.0p-57 */
#| 0.0245283181166547278873, // 0x191df3908c33ce.0p-58 */
#| 0.00297435743359967304927, // 0x185dadfcecf44e.0p-61 */
#| 0.00946564784943673166728, // 0x1362b9bf971bcd.0p-59 */
#| ]
#| let z = x * x
#| let mut r = coef[4] + z * coef[5]
#| let t = coef[2] + z * coef[3]
#| let w = z * z
#| let s = z * x
#| let u = coef[0] + z * coef[1]
#| r = x + s * u + s * w * (t + w * r)
#| (if odd { -1.0 / r } else { r }).to_float() }
),
),
"sinf": build(
(
#|pub fn sinf(x : Float) -> Float { if x.is_nan() || x.is_inf() {
#| return @float.not_a_number
#| }
#| if x == 0.0 {
#| return x
#| }
#| let (x, q) = trig_reduce(x, SIN_SWITCHOVER)
#| sin_cos_core(x, q) }
),
),
"cosf": build(
(
#|pub fn cosf(x : Float) -> Float { if x.is_nan() || x.is_inf() {
#| return @float.not_a_number
#| }
#| if x == 0.0 {
#| return 1.0
#| }
#| let (x, q) = trig_reduce(x, COS_SWITCHOVER)
#| sin_cos_core(x, q + 1) }
),
),
"tanf": build(
(
#|pub fn tanf(x : Float) -> Float { if x.is_nan() || x.is_inf() {
#| return @float.not_a_number
#| }
#| if x == 0.0 {
#| return x
#| }
#| let (x, q) = trig_reduce(x, COS_SWITCHOVER)
#| tanf_poly(x, (q & 1) != 0) }
),
),
"asinf": build(
(
#|pub fn asinf(x : Float) -> Float { let x1p120 = 0x3870000000000000UL.reinterpret_as_double()
#| let pio2 : Double = 1.570796326794896558e+00
#| // coefficients for R(x^2)
#| let ps0 : Float = 1.6666586697e-01
#| let ps1 : Float = -4.2743422091e-02
#| let ps2 : Float = -8.6563630030e-03
#| let qs2 : Float = -7.0662963390e-01
#| fn r(z : Float) -> Float {
#| let p = z * (ps0 + z * (ps1 + z * ps2))
#| let q = z * qs2 + 1.0
#| p / q
#| }
#| let hx = x.reinterpret_as_uint()
#| let ix = hx & 0x7fffffff
#| if ix >= 0x3f800000 {
#| if ix == 0x3f800000 {
#| return (x.to_double() * pio2 + x1p120).to_float()
#| }
#| return @float.not_a_number // asin(|x|>1) is NaN
#| }
#| if ix < 0x3f000000 {
#| if ix is (0x00800000..=0x39800000) {
#| return x
#| }
#| return x + x * r(x * x)
#| }
#| let z = ((1.0 : Float) - x.abs()) * 0.5
#| let s = z.to_double().sqrt()
#| let x = (pio2 - 2.0 * (s + s * r(z).to_double())).to_float()
#| if hx >> 31 != 0 {
#| -x
#| } else {
#| x
#| } }
),
),
"acosf": build(
(
#|pub fn acosf(x : Float) -> Float { let pio2_hi : Float = 1.5707962513
#| let pio2_lo : Float = 7.5497894159e-08
#| let ps0 : Float = 1.6666586697e-01
#| let ps1 : Float = -4.2743422091e-02
#| let ps2 : Float = -8.6563630030e-03
#| let qs1 : Float = -7.0662963390e-01
#| let one : Float = 1.0
#| let two : Float = 2.0
#| fn r(z : Float) -> Float {
#| let p = z * (ps0 + z * (ps1 + z * ps2))
#| let q = z * qs1 + 1.0
#| p / q
#| }
#| let hx = x.reinterpret_as_int()
#| let ix = hx & 0x7fffffff
#| if ix >= 0x3f800000 {
#| if ix == 0x3f800000 {
#| if hx >> 31 != 0 {
#| return two * pio2_hi + 0x1.0p-120
#| }
#| return 0.0
#| }
#| return @float.not_a_number
#| }
#| if ix < 0x3f000000 {
#| if ix <= 0x32800000 {
#| return pio2_hi + 0x1.0p-120
#| }
#| return pio2_hi - (x - (pio2_lo - x * r(x * x)))
#| }
#| if hx >> 31 != 0 {
#| let z = (x + 1.0) * 0.5
#| let s = z.sqrt()
#| let w = r(z) * s - pio2_lo
#| return two * (pio2_hi - (s + w))
#| }
#| let z = (one - x) * 0.5
#| let s = z.sqrt()
#| let df = s
#| let c = (z - df * df) / (s + df)
#| let w = r(z) * s + c
#| two * (df + w) }
),
),
"atanf": build(
(
#|pub fn atanf(x : Float) -> Float { let atanhi : Array[Float] = [
#| 4.6364760399e-01, 7.8539812565e-01, 9.8279368877e-01, 1.5707962513e+00,
#| ]
#| let atanlo : Array[Float] = [
#| 5.0121582440e-09, 3.7748947079e-08, 3.4473217170e-08, 7.5497894159e-08,
#| ]
#| let a_t : Array[Float] = [
#| 3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02,
#| ]
#| let ix = x.reinterpret_as_int()
#| let sign = ix >> 31
#| let ix = ix & 0x7fffffff
#| let mut id = 0
#| let mut x = x
#| let one : Float = 1.0
#| let two : Float = 2.0
#| if ix >= 0x4c800000 {
#| if x.is_nan() {
#| return x
#| }
#| let z = atanhi[3] + 0x1.0p-120
#| let z = if sign != 0 { -z } else { z }
#| return z
#| }
#| if ix < 0x3ee00000 {
#| if ix < 0x39800000 {
#| return x
#| }
#| id = -1
#| } else {
#| x = x.abs()
#| if ix < 0x3f980000 {
#| if ix < 0x3f300000 {
#| id = 0
#| x = (two * x - one) / (two + x)
#| } else {
#| id = 1
#| x = (x - one) / (x + one)
#| }
#| } else if ix < 0x401c0000 {
#| id = 2
#| x = (x - 1.5) / (one + x * 1.5)
#| } else {
#| id = 3
#| x = -one / x
#| }
#| }
#| let z = x * x
#| let w = z * z
#| let s1 = z * (a_t[0] + w * (a_t[2] + w * a_t[4]))
#| let s2 = w * (a_t[1] + w * a_t[3])
#| if id < 0 {
#| return x - x * (s1 + s2)
#| }
#| let z = atanhi[id] - (x * (s1 + s2) - atanlo[id] - x)
#| if sign != 0 {
#| -z
#| } else {
#| z
#| } }
),
),
"atan2f": build(
(
#|pub fn atan2f(y : Float, x : Float) -> Float { if x.is_nan() || y.is_nan() {
#| return @float.not_a_number
#| }
#| let pi : Float = 3.1415927410e+00
#| let pi_lo : Float = -8.7422776573e-08
#| let zero : Float = 0.0
#| let ix = x.reinterpret_as_uint()
#| let iy = y.reinterpret_as_uint()
#| if ix == 0x3f800000 {
#| return atanf(y)
#| }
#| let m = ((iy >> 31) & 1) | ((ix >> 30) & 2)
#| let ix = ix & 0x7fffffff
#| let iy = iy & 0x7fffffff
#| if iy == 0 {
#| match m {
#| 0 | 1 => return y
#| 2 => return pi
#| _ => return -pi
#| }
#| }
#| if ix == 0 {
#| let res = if (m & 1) != 0 { -pi / 2 } else { pi / 2 }
#| return res
#| }
#| if ix == 0x7f800000 {
#| if iy == 0x7f800000 {
#| match m {
#| 0 => return pi / 4
#| 1 => return -pi / 4
#| 2 => return pi * 3.0 / 4
#| _ => return -pi * 3.0 / 4
#| }
#| } else {
#| match m {
#| 0 => return 0.0
#| 1 => return -0.0
#| 2 => return pi
#| _ => return -pi
#| }
#| }
#| }
#| if ix + (26U << 23) < iy || iy == 0x7f800000 {
#| let res = if (m & 1) != 0 { -pi / 2 } else { pi / 2 }
#| return res
#| }
#| let z = if (m & 2) != 0 && iy + (26U << 23) < ix {
#| zero
#| } else {
#| atanf(y / x)
#| }
#| match m {
#| 0 => z
#| 1 => -z
#| 2 => pi - (z - pi_lo)
#| _ => z - pi_lo - pi
#| } }
),
),
"scalbn": build(
(
#|pub fn scalbn(x : Double, exp : Int) -> Double { let mut n = exp
#| let mut y : Double = x
#| if n > 1023 {
#| y *= 0x1.0p1023
#| n -= 1023
#| if n > 1023 {
#| y *= 0x1.0p1023
#| n -= 1023
#| if n > 1023 {
#| n = 1023
#| }
#| }
#| } else if n < -1022 {
#| // make sure final n < -53 to avoid double
#| // rounding in the subnormal range
#| y *= 0x1.0p-1022 * 0x1.0p53
#| n += 1022 - 53
#| if n < -1022 {
#| y *= 0x1.0p-1022 * 0x1.0p53
#| n += 1022 - 53
#| if n < -1022 {
#| n = -1022
#| }
#| }
#| }
#| let ui = (0x3ff + n).to_uint64() << 52
#| return y * ui.reinterpret_as_double() }
),
),
"scalbnf": build(
(
#|pub fn scalbnf(y : Float, exp : Int) -> Float { let mut y = y
#| let mut n = exp
#| if n > 127 {
#| y *= (0x1.0p127 : Float)
#| n -= 127
#| if n > 127 {
#| y *= (0x1.0p127 : Float)
#| n -= 127
#| if n > 127 {
#| n = 127
#| }
#| }
#| } else if n < -126 {
#| y *= (0x1.0p-126 : Float) * 0x1.0p24
#| n += 126 - 24
#| if n < -126 {
#| y *= (0x1.0p-126 : Float) * 0x1.0p24
#| n += 126 - 24
#| if n < -126 {
#| n = -126
#| }
#| }
#| }
#| let u = (0x7f + n) << 23
#| return y * u.reinterpret_as_float() }
),
),
"top12": build(
(
#|fn top12(x : Float) -> UInt { x.reinterpret_as_uint() >> 20 }
),
),
"__math_xflowf": build(
(
#|fn __math_xflowf(sign : UInt, y : Float) -> Float { return (if sign != 0 { -y } else { y }) * y }
),
),
"__math_oflowf": build(
(
#|fn __math_oflowf(sign : UInt) -> Float { return __math_xflowf(sign, 0x1.0p97) }
),
),
"__math_uflowf": build(
(
#|fn __math_uflowf(sign : UInt) -> Float { return __math_xflowf(sign, 0x1.0p-95) }
),
),
"exp2f_table_bits": (None, Int(5)),
"expf": build(
(
#|pub fn expf(x : Float) -> Float { let xd = x.to_double()
#| let abstop = top12(x) & 0x7ff
#| if abstop >= top12(88.0) {
#| if x.reinterpret_as_uint() == @float.neg_infinity.reinterpret_as_uint() {
#| return 0.0
#| }
#| if abstop >= top12(@float.infinity) {
#| return x + x
#| }
#| if x > 0x1.62e42ep6 {
#| return __math_oflowf(0)
#| }
#| if x < -0x1.9fe368p6 {
#| return __math_uflowf(0)
#| }
#| }
#| let z = exp2f_data.invln2_scaled * xd
#| let kd = z + exp2f_data.shift
#| let ki = kd.reinterpret_as_uint64()
#| let kd = kd - exp2f_data.shift
#| let r = z - kd
#| let t = exp2f_data.tab[(ki % expf_n).to_int()]
#| let t = t + (ki << (52 - exp2f_table_bits))
#| let s = t.reinterpret_as_double()
#| let z = exp2f_data.poly_scaled[0] * r + exp2f_data.poly_scaled[1]
#| let r2 = r * r
#| let y = exp2f_data.poly_scaled[2] * r + 1
#| let y = z * r2 + y
#| let y = y * s
#| y.to_float() }
),
),
"expm1f": build(
(
#|pub fn expm1f(x : Float) -> Float { let float_ln2_hi : Float = 6.9314575195e-01 // 0x3f317200
#| let float_ln2_lo : Float = 1.4286067653e-06 // 0x35bfbe8e
#| let inv_ln2 : Float = 1.4426950216e+00 // 0x3fb8aa3b
#| let mut x = x
#| let q1 : Float = -3.3333212137e-2 // -0x888868.0p-28
#| let q2 : Float = 1.5807170421e-3 // 0xcf3010.0p-33
#| let mut hx = x.reinterpret_as_uint()
#| let sign = hx >> 31 != 0
#| hx = hx & 0x7fffffff
#| // filter out huge and non-finite argument
#| if hx >= 0x4195b844 {
#| // if |x|>=27*ln2
#| if hx > 0x7f800000 {
#| // NaN
#| return x
#| }
#| if sign {
#| return -1.0
#| }
#| if hx > 0x42b17217 {
#| x *= (0x1.0p127 : Float)
#| return x
#| }
#| }
#| let mut k : Int = 0
#| let mut hi : Float = 0
#| let mut lo : Float = 0
#| let mut c : Float = 0
#| // argument reduction
#| if hx > 0x3eb17218 {
#| // if |x| > 0.5 ln2
#| if hx < 0x3F851592 {
#| // and |x| < 1.5 ln2
#| if !sign {
#| hi = x - float_ln2_hi
#| lo = float_ln2_lo
#| k = 1
#| } else {
#| hi = x + float_ln2_hi
#| lo = -float_ln2_lo
#| k = -1
#| }
#| } else {
#| k = (inv_ln2 * x + (if sign { -0.5 } else { 0.5 })).to_int()
#| let t = k.to_float()
#| hi = x - t * float_ln2_hi // t*ln2_hi is exact here
#| lo = t * float_ln2_lo
#| }
#| x = hi - lo
#| c = hi - x - lo
#| } else if hx < 0x33000000 {
#| // when |x|<2**-25, return x
#| //if hx < 0x00800000 {
#| // force_eval(x * x);
#| //}
#| return x
#| } else {
#| k = 0
#| }
#| // x is now in primary range
#| let hfx = (0.5 : Float) * x
#| let hxs = x * hfx
#| let r1 = (1.0 : Float) + hxs * (q1 + hxs * q2)
#| let t = (3.0 : Float) - r1 * hfx
#| let mut e = hxs * ((r1 - t) / ((6.0 : Float) - x * t))
#| if k == 0 {
#| // c is 0
#| return x - (x * e - hxs)
#| }
#| e = x * (e - c) - c
#| e -= hxs
#| // exp(x) ~ 2^k (x_reduced - e + 1)
#| if k == -1 {
#| return (0.5 : Float) * (x - e) - 0.5
#| }
#| if k == 1 {
#| if x < -0.25 {
#| return -(2.0 : Float) * (e - (x + 0.5))
#| }
#| return (1.0 : Float) + (2.0 : Float) * (x - e)
#| }
#| let twopk = ((0x7f + k) << 23).reinterpret_as_float() // 2^k
#| if !(k is (0..=56)) {
#| // suffice to return exp(x)-1
#| let mut y = x - e + 1.0
#| if k == 128 {
#| y = y * 2.0 * (0x1.0p127 : Float)
#| } else {
#| y = y * twopk
#| }
#| return y - 1.0
#| }
#| let uf = ((0x7f - k) << 23).reinterpret_as_float() // 2^-k
#| if k < 23 {
#| (x - e + ((1.0 : Float) - uf)) * twopk
#| } else {
#| (x - (e + uf) + 1.0) * twopk
#| } }
),
),
"powf": build(
(
#|pub fn powf(base : Float, exponent : Float) -> Float { let huge : Float = 1.0e30
#| let tiny : Float = 1.0e-30
#| let cp : Float = 9.6179670095e-01 // 0x3f76384f =2/(3ln2) */
#| let cp_h : Float = 9.6191406250e-01 // 0x3f764000 =12b cp */
#| let cp_l : Float = -1.1736857402e-04 // 0xb8f623c6 =tail of cp_h */
#| let lg2 : Float = 6.9314718246e-01 // 0x3f317218 */
#| let lg2_h : Float = 6.93145752e-01 // 0x3f317200 */
#| let lg2_l : Float = 1.4286067653e-06 // 0x35bfbe8c */
#| let ovt : Float = 8.0085662595e-08 // -(2**-28)/(log(2)**2) */
#| let ivln2 : Float = 1.4426950216e+00 // 0x3f317218 */
#| let ivln2_h : Float = 1.4426879883e+00 // 0x3f317218 */
#| let ivln2_l : Float = 7.0526075433e-06 // 0x35bfbe8c */
#| let l1 : Float = 6.0000002384e-01 // 0x3f19999a */
#| let l2 : Float = 4.2857143283e-01 // 0x3edb6db7 */
#| let l3 : Float = 3.3333334327e-01 // 0x3eaaaaab */
#| let l4 : Float = 2.7272811532e-01 // 0x3e8ba305 */
#| let l5 : Float = 2.3066075146e-01 // 0x3e6c3255 */
#| let l6 : Float = 2.0697501302e-01 // 0x3e53f142 */
#| let p1 : Float = 1.6666667163e-01 // 0x3e2aaaab */
#| let p2 : Float = -2.7777778450e-03 // 0xbb360b61 */
#| let p3 : Float = 6.6137559770e-05 // 0x388ab355 */
#| let p4 : Float = -1.6533901999e-06 // 0xb5ddea0e */
#| let p5 : Float = 4.1381369442e-08 // 0x3331bb4c */
#| let mut z : Float = 0
#| let mut ax : Float = 0
#| let mut z_h : Float = 0
#| let mut z_l : Float = 0
#| let mut p_h : Float = 0
#| let mut p_l : Float = 0
#| let mut y1 : Float = 0
#| let mut t1 : Float = 0
#| let mut t2 : Float = 0
#| let mut r : Float = 0
#| let mut s : Float = 0
#| let mut sn : Float = 0
#| let mut t : Float = 0
#| let mut u : Float = 0
#| let mut v : Float = 0
#| let mut w : Float = 0
#| let mut i : Int = 0
#| let mut j : Int = 0
#| let mut k : Int = 0
#| let mut yisint : Int = 0
#| let mut n : Int = 0
#| let mut hx : Int = 0
#| let mut hy : Int = 0
#| let mut ix : Int = 0
#| let mut iy : Int = 0
#| let mut i_s : Int = 0
#| let (x, y) = (base, exponent)
#| let bp : Array[Float] = [1.0, 1.5]
#| let dp_h : Array[Float] = [0.0, 5.84960938e-01] // 0x3f15c000 */
#| let dp_l : Array[Float] = [0.0, 1.56322085e-06] // 0x35d1cfdc */
#| let two24 : Float = 16777216.0
#| hx = x.reinterpret_as_int()
#| hy = y.reinterpret_as_int()
#| ix = hx & 0x7fffffff
#| iy = hy & 0x7fffffff
#| // x**0 = 1, even if x is NaN
#| if iy == 0 {
#| return 1.0
#| }
#| // 1**y = 1, even if y is NaN
#| if hx == 0x3f800000 {
#| return 1.0
#| }
#| // NaN if either arg is NaN
#| if ix > 0x7f800000 || iy > 0x7f800000 {
#| return x + y
#| }
#| // determine if y is an odd int when x < 0
#| // yisint = 0 ... y is not an integer
#| // yisint = 1 ... y is an odd int
#| // yisint = 2 ... y is an even int
#| //
#| yisint = 0
#| if hx < 0 {
#| if iy >= 0x4b800000 {
#| yisint = 2 // even integer y
#| } else if iy >= 0x3f800000 {
#| k = (iy >> 23) - 0x7f // exponent
#| j = iy >> (23 - k)
#| if j << (23 - k) == iy {
#| yisint = 2 - (j & 1)
#| }
#| }
#| }
#| // special value of y
#| if iy == 0x7f800000 {
#| if ix == 0x3f800000 {
#| // (-1)**+-inf is 1
#| return 1.0
#| } else if ix > 0x3f800000 {
#| // (|x|>1)**+-inf = inf,0
#| return if hy >= 0 { y } else { 0.0 }
#| } else {
#| // (|x|<1)**+-inf = 0,inf
#| return if hy >= 0 { 0.0 } else { -y }
#| }
#| }
#| if iy == 0x3f800000 {
#| // y is +-1
#| return if hy >= 0 { x } else { (1.0 : Float) / x }
#| }
#| if hy == 0x40000000 {
#| // y is 2
#| return x * x
#| }
#| // y is 0.5
#| if hy == 0x3f000000 && hx >= 0 {
#| // x >= +0
#| return x.sqrt()
#| }
#| ax = x.abs()
#| // special value of x
#| if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 {
#| // x is +-0,+-inf,+-1
#| z = ax
#| if hy < 0 {
#| // z = (1/|x|)
#| z = (1.0 : Float) / z
#| }
#| if hx < 0 {
#| if ((ix - 0x3f800000) | yisint) == 0 {
#| z = (z - z) / (z - z) // (-1)**non-int is NaN
#| } else if yisint == 1 {
#| z = -z
#| }
#| } // (x<0)**odd = -(|x|**odd)
#| return z
#| }
#| sn = 1.0 // sign of result
#| if hx < 0 {
#| if yisint == 0 {
#| // (x<0)**(non-int) is NaN
#| return @float.not_a_number
#| }
#| if yisint == 1 {
#| // (x<0)**(odd int)
#| sn = -1.0
#| }
#| }
#| // |y| is huge
#| if iy > 0x4d000000 {
#| // if |y| > 2**27
#| // over/underflow if x is not close to one
#| if ix < 0x3f7ffff8 {
#| return if hy < 0 { sn * huge * huge } else { sn * tiny * tiny }
#| }
#| if ix > 0x3f800007 {
#| return if hy > 0 { sn * huge * huge } else { sn * tiny * tiny }
#| }
#| // now |1-x| is tiny <= 2**-20, suffice to compute
#| // log(x) by x-x^2/2+x^3/3-x^4/4
#| t = ax - 1.0 // t has 20 trailing zeros
#| w = t * t * ((0.5 : Float) - t * ((0.333333333333 : Float) - t * 0.25))
#| u = ivln2_h * t // IVLN2_H has 16 sig. bits
#| v = t * ivln2_l - w * ivln2
#| t1 = u + v
#| i_s = t1.reinterpret_as_int()
#| t1 = (i_s & 0xfffff000).reinterpret_as_float()
#| t2 = v - (t1 - u)
#| } else {
#| let mut s2 : Float = 0
#| let mut s_h : Float = 0
#| let mut s_l : Float = 0
#| let mut t_h : Float = 0
#| let mut t_l : Float = 0
#| n = 0
#| // take care subnormal number
#| if ix < 0x00800000 {
#| ax *= two24
#| n -= 24
#| ix = ax.reinterpret_as_int()
#| }
#| n += (ix >> 23) - 0x7f
#| j = ix & 0x007fffff
#| // determine interval
#| ix = j | 0x3f800000 // normalize ix
#| if j <= 0x1cc471 {
#| // |x|> 1) & 0xfffff000) | 0x20000000).reinterpret_as_int()
#| t_h = (i_s.reinterpret_as_uint() +
#| 0x00400000 +
#| (k.reinterpret_as_uint() << 21)).reinterpret_as_float()
#| t_l = ax - (t_h - bp[k])
#| s_l = v * (u - s_h * t_h - s_h * t_l)
#| // compute log(ax) */
#| s2 = s * s
#| r = s2 * s2 * (l1 + s2 * (l2 + s2 * (l3 + s2 * (l4 + s2 * (l5 + s2 * l6)))))
#| r += s_l * (s_h + s)
#| s2 = s_h * s_h
#| t_h = (3.0 : Float) + s2 + r
#| i_s = t_h.reinterpret_as_int()
#| t_h = (i_s & 0xfffff000).reinterpret_as_float()
#| t_l = r - (t_h - 3.0 - s2)
#| // u+v = s*(1+...)
#| u = s_h * t_h
#| v = s_l * t_h + t_l * s
#| // 2/(3log2)*(s+...)
#| p_h = u + v
#| i_s = p_h.reinterpret_as_int()
#| p_h = (i_s & 0xfffff000).reinterpret_as_float()
#| p_l = v - (p_h - u)
#| z_h = cp_h * p_h // cp_h+cp_l = 2/(3*log2)
#| z_l = cp_l * p_h + p_l * cp + dp_l[k]
#| // log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l
#| t = n.to_float()
#| t1 = z_h + z_l + dp_h[k] + t
#| i_s = t1.reinterpret_as_int()
#| t1 = (i_s & 0xfffff000).reinterpret_as_float()
#| t2 = z_l - (t1 - t - dp_h[k] - z_h)
#| }
#| // split up y into y1+y2 and compute (y1+y2)*(t1+t2)
#| i_s = y.reinterpret_as_int()
#| y1 = (i_s & 0xfffff000).reinterpret_as_float()
#| p_l = (y - y1) * t1 + y * t2
#| p_h = y1 * t1
#| z = p_l + p_h
#| j = z.reinterpret_as_int()
#| if j > 0x43000000 {
#| // if z > 128
#| return sn * huge * huge // overflow
#| } else if j == 0x43000000 {
#| // if z == 128
#| if p_l + ovt > z - p_h {
#| return sn * huge * huge
#| }
#| } else if ( // overflow
#| j & 0x7fffffff
#| ) >
#| 0x43160000 {
#| // z < -150
#| return sn * tiny * tiny // underflow
#| // z == -150
#| } else if j.reinterpret_as_uint() == 0xc3160000 && p_l <= z - p_h {
#| return sn * tiny * tiny
#| } // underflow
#| //
#| // compute 2**(p_h+p_l)
#| //
#| i = j & 0x7fffffff
#| k = (i >> 23) - 0x7f
#| n = 0
#| if i > 0x3f000000 {
#| // if |z| > 0.5, set n = [z+0.5]
#| n = j + (0x00800000 >> (k + 1))
#| k = ((n & 0x7fffffff) >> 23) - 0x7f // new k for n
#| t = (n & (0x007fffff >> k).lnot()).reinterpret_as_float()
#| n = ((n & 0x007fffff) | 0x00800000) >> (23 - k)
#| if j < 0 {
#| n = -n
#| }
#| p_h -= t
#| }
#| t = p_l + p_h
#| i_s = t.reinterpret_as_int()
#| t = (i_s & 0xffff8000).reinterpret_as_float()
#| u = t * lg2_h
#| v = (p_l - (t - p_h)) * lg2 + t * lg2_l
#| z = u + v
#| w = v - (z - u)
#| t = z * z
#| t1 = z - t * (p1 + t * (p2 + t * (p3 + t * (p4 + t * p5))))
#| r = z * t1 / (t1 - 2.0) - (w + z * w)
#| z = (1.0 : Float) - (r - z)
#| j = z.reinterpret_as_int()
#| j += n << 23
#| if j >> 23 <= 0 {
#| // subnormal output
#| z = scalbnf(z, n)
#| } else {
#| z = j.reinterpret_as_float()
#| }
#| sn * z }
),
),
}
},
)
///|
let moonbitlang_core_option_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/option",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module,
},
fn(_env, build) {
{
"map": build(
(
#|pub fn[T, U] map(self : T?, f : (T) -> U) -> U? { match self {
#| Some(t) => Some(f(t))
#| None => None
#| } }
),
),
"map_or": build(
(
#|pub fn[T, U] map_or(self : T?, default : U, f : (T) -> U) -> U { match self {
#| None => default
#| Some(x) => f(x)
#| } }
),
),
"map_or_else": build(
(
#|pub fn[T, U] map_or_else(self : T?, default : () -> U, f : (T) -> U) -> U { match self {
#| None => default()
#| Some(x) => f(x)
#| } }
),
),
"bind": build(
(
#|pub fn[T, U] bind(self : T?, f : (T) -> U?) -> U? { match self {
#| Some(t) => f(t)
#| None => None
#| } }
),
),
"flatten": build(
(
#|pub fn[T] flatten(self : T??) -> T? { match self {
#| Some(inner) => inner
#| None => None
#| } }
),
),
"is_empty": build(
(
#|pub fn[T] is_empty(self : T?) -> Bool { self is None }
),
),
"filter": build(
(
#|pub fn[T] filter(self : T?, f : (T) -> Bool) -> T? { match self {
#| Some(t) => if f(t) { self } else { None }
#| None => None
#| } }
),
),
"unwrap_or": build(
(
#|pub fn[T] Option::unwrap_or(self : T?, default : T) -> T { match self {
#| None => default
#| Some(t) => t
#| } }
),
),
"unwrap_or_else": build(
(
#|pub fn[T] Option::unwrap_or_else(self : T?, default : () -> T) -> T { match self {
#| None => default()
#| Some(t) => t
#| } }
),
),
"unwrap_or_default": build(
(
#|pub fn[T : Default] Option::unwrap_or_default(self : T?) -> T { match self {
#| None => T::default()
#| Some(t) => t
#| } }
),
),
"iter": build(
(
#|pub fn[T] iter(self : T?) -> Iter[T] { match self {
#| Some(v) => Iter::singleton(v)
#| None => Iter::empty()
#| } }
),
),
"or_error": build(
(
#|pub fn[T, Err : Error] or_error(self : T?, err : Err) -> T raise Err { match self {
#| Some(v) => v
#| None => raise err
#| } }
),
),
"when": build(
(
#|pub fn[T] when(condition : Bool, value : () -> T) -> T? { if condition {
#| Some(value())
#| } else {
#| None
#| } }
),
),
"unless": build(
(
#|pub fn[T] unless(condition : Bool, value : () -> T) -> T? { when(!condition, value) }
),
),
"empty": build(
(
#|pub fn[T] empty() -> T? { None }
),
),
"some": build(
(
#|pub fn[T] some(value : T) -> T? { Some(value) }
),
),
"or": build(
(
#|pub fn[T] Option::or(self : T?, default : T) -> T { match self {
#| None => default
#| Some(t) => t
#| } }
),
),
"or_else": build(
(
#|pub fn[T] Option::or_else(self : T?, default : () -> T) -> T { match self {
#| None => default()
#| Some(t) => t
#| } }
),
),
"or_default": build(
(
#|pub fn[T : Default] Option::or_default(self : T?) -> T { match self {
#| None => T::default()
#| Some(t) => t
#| } }
),
),
"is_some": build(
(
#|pub fn[T] is_some(self : T?) -> Bool { self is Some(_) }
),
),
"is_none": build(
(
#|pub fn[T] is_none(self : T?) -> Bool { self is None }
),
),
}
},
)
///|
let moonbitlang_core_prelude_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/prelude",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/bigint": moonbitlang_core_bigint_module,
"moonbitlang/core/set": moonbitlang_core_set_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
},
fn(_env, build) {
{
"tap": build(
(
#|pub fn[T] tap(value : T, f : (T) -> Unit) -> T { f(value)
#| value }
),
),
"then": build(
(
#|pub fn[T, R] then(value : T, f : (T) -> R) -> R { f(value) }
),
),
}
},
)
///|
let moonbitlang_core_priority_queue_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/priority_queue",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
},
fn(_env, build) {
{
"new": build(
(
#|pub fn[A] new() -> T[A] { { len: 0, top: Nil } }
),
),
"from_array": build(
(
#|pub fn[A : Compare] from_array(arr : Array[A]) -> T[A] { // CR: bad formatting
#| let len = arr.length()
#| for i = 0, acc = Node::Nil {
#| if i < len {
#| continue i + 1, meld(acc, Cons(content=arr[i], sibling=Nil, child=Nil))
#| } else {
#| break { len, top: acc }
#| }
#| } }
),
),
"copy_node": build(
(
#|fn[A] copy_node(x : Node[A]) -> Node[A] { match x {
#| Nil => Nil
#| Cons(_) as node =>
#| Cons(
#| content=node.content,
#| sibling=copy_node(node.sibling),
#| child=copy_node(node.child),
#| )
#| } }
),
),
"copy": build(
(
#|pub fn[A] copy(self : T[A]) -> T[A] { let new_que : T[A] = { len: self.len, top: copy_node(self.top) }
#| new_que }
),
),
"to_array": build(
(
#|pub fn[A : Compare] to_array(self : T[A]) -> Array[A] { let arr = Array::new(capacity=self.len)
#| fn go(x : Node[A]) {
#| match x {
#| Cons(_) as x => {
#| arr.push(x.content)
#| go(x.sibling)
#| go(x.child)
#| }
#| Nil => ()
#| }
#| }
#| go(self.top)
#| arr.sort_by((x, y) => y.compare(x))
#| arr }
),
),
"iter": build(
(
#|pub fn[A : Compare] iter(self : T[A]) -> Iter[A] { Iter::new(yield_ => {
#| let arr = self.to_array()
#| for i in 0.. T[K] { let s = new()
#| iter.each(e => s.push(e))
#| s }
),
),
"meld": build(
(
#|fn[A : Compare] meld(x : Node[A], y : Node[A]) -> Node[A] { match (x, y) {
#| (Nil, _) => y
#| (_, Nil) => x
#| (Cons(_) as x_top, Cons(_) as y_top) =>
#| if x_top.content > y_top.content {
#| y_top.sibling = x_top.child
#| x_top.child = y
#| x
#| } else {
#| x_top.sibling = y_top.child
#| y_top.child = x
#| y
#| }
#| } }
),
),
"merges": build(
(
#|fn[A : Compare] merges(x : Node[A]) -> Node[A] { loop (x, Nil) {
#| (Nil, acc) => acc
#| (Cons(sibling=Nil, ..) as x, acc) => meld(acc, x)
#| (Cons(sibling=Cons(sibling=s2, ..) as s1, ..) as x, acc) => {
#| x.sibling = Nil
#| s1.sibling = Nil
#| continue (s2, meld(acc, meld(x, s1)))
#| }
#| } }
),
),
"length": build(
(
#|pub fn[A] length(self : T[A]) -> Int { self.len }
),
),
"unsafe_pop": build(
(
#|pub fn[A : Compare] unsafe_pop(self : T[A]) -> Unit { self.top = match self.top {
#| Nil => abort(\"The PriorityQueue is empty!\")
#| Cons(child~, ..) => merges(child)
#| }
#| self.len -= 1 }
),
),
"pop": build(
(
#|pub fn[A : Compare] pop(self : T[A]) -> A? { let result = self.peek()
#| self.top = match self.top {
#| Nil => Nil
#| Cons(child~, ..) => {
#| self.len -= 1
#| merges(child)
#| }
#| }
#| result }
),
),
"push": build(
(
#|pub fn[A : Compare] push(self : T[A], value : A) -> Unit { self.top = meld(self.top, Cons(content=value, sibling=Nil, child=Nil))
#| self.len += 1 }
),
),
"peek": build(
(
#|pub fn[A] peek(self : T[A]) -> A? { match self.top {
#| Nil => None
#| Cons(content~, ..) => Some(content)
#| } }
),
),
"clear": build(
(
#|pub fn[A] clear(self : T[A]) -> Unit { self.top = Nil
#| self.len = 0 }
),
),
"is_empty": build(
(
#|pub fn[A] is_empty(self : T[A]) -> Bool { self.len == 0 }
),
),
"of": build(
(
#|pub fn[A : Compare] of(arr : FixedArray[A]) -> T[A] { // CR: bad formatting
#| let len = arr.length()
#| for i = 0, acc = Node::Nil {
#| if i < len {
#| continue i + 1, meld(acc, Cons(content=arr[i], sibling=Nil, child=Nil))
#| } else {
#| break { len, top: acc }
#| }
#| } }
),
),
}
},
)
///|
let moonbitlang_core_queue_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/queue",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
},
fn(_env, build) {
{
"new": build(
(
#|pub fn[A] new() -> T[A] { { length: 0, first: None, last: None } }
),
),
"from_array": build(
(
#|pub fn[A] from_array(arr : Array[A]) -> T[A] { guard arr.length() > 0 else { return new() }
#| let length = arr.length()
#| let last = { content: arr[length - 1], next: None }
#| let first = for i = length - 2, x = last; i >= 0; {
#| continue i - 1, { content: arr[i], next: Some(x) }
#| } else {
#| x
#| }
#| { length, first: Some(first), last: Some(last) } }
),
),
"clear": build(
(
#|pub fn[A] clear(self : T[A]) -> Unit { self.length = 0
#| self.first = None
#| self.last = None }
),
),
"length": build(
(
#|pub fn[A] length(self : T[A]) -> Int { self.length }
),
),
"is_empty": build(
(
#|pub fn[A] is_empty(self : T[A]) -> Bool { self.length == 0 }
),
),
"push": build(
(
#|pub fn[A] push(self : T[A], x : A) -> Unit { let cell = Some({ content: x, next: None })
#| match self.last {
#| None => {
#| self.length = 1
#| self.first = cell
#| self.last = cell
#| }
#| Some(last) => {
#| last.next = cell
#| self.length += 1
#| self.last = cell
#| }
#| } }
),
),
"unsafe_peek": build(
(
#|pub fn[A] unsafe_peek(self : T[A]) -> A { match self.first {
#| None => abort(\"Queue is empty\")
#| Some(first) => first.content
#| } }
),
),
"peek": build(
(
#|pub fn[A] peek(self : T[A]) -> A? { match self.first {
#| None => None
#| Some(first) => Some(first.content)
#| } }
),
),
"unsafe_pop": build(
(
#|pub fn[A] unsafe_pop(self : T[A]) -> A { match self.first {
#| None => abort(\"Queue is empty\")
#| Some({ content, next: None }) => {
#| self.clear()
#| content
#| }
#| Some({ content, next }) => {
#| self.length -= 1
#| self.first = next
#| content
#| }
#| } }
),
),
"pop": build(
(
#|pub fn[A] pop(self : T[A]) -> A? { match self.first {
#| None => None
#| Some({ content, next: None }) => {
#| self.clear()
#| Some(content)
#| }
#| Some({ content, next }) => {
#| self.length -= 1
#| self.first = next
#| Some(content)
#| }
#| } }
),
),
"each": build(
(
#|pub fn[A] each(self : T[A], f : (A) -> Unit) -> Unit { loop self.first {
#| Some({ content, next }) => {
#| f(content)
#| continue next
#| }
#| None => ()
#| } }
),
),
"eachi": build(
(
#|pub fn[A] eachi(self : T[A], f : (Int, A) -> Unit) -> Unit { loop (self.first, 0) {
#| (Some({ content, next }), index) => {
#| f(index, content)
#| continue (next, index + 1)
#| }
#| (None, _) => ()
#| } }
),
),
"fold": build(
(
#|pub fn[A, B] fold(self : T[A], init~ : B, f : (B, A) -> B) -> B { loop (self.first, init) {
#| (None, acc) => acc
#| (Some({ content, next }), acc) => continue (next, f(acc, content))
#| } }
),
),
"copy": build(
(
#|pub fn[A] copy(self : T[A]) -> T[A] { guard self.first is Some({ content, next }) else { return new() }
#| let first = { content, next: None }
#| let last = loop (first, next) {
#| (pre, Some({ content, next })) => {
#| let curr = { content, next: None }
#| pre.next = Some(curr)
#| continue (curr, next)
#| }
#| (pre, None) => pre
#| }
#| { length: self.length, first: Some(first), last: Some(last) } }
),
),
"transfer": build(
(
#|pub fn[A] transfer(self : T[A], dst : T[A]) -> Unit { if self.length > 0 {
#| match dst.last {
#| None => {
#| dst.length = self.length
#| dst.first = self.first
#| dst.last = self.last
#| self.clear()
#| }
#| Some(last) => {
#| last.next = self.first
#| dst.length = dst.length + self.length
#| dst.last = self.last
#| self.clear()
#| }
#| }
#| } }
),
),
"iter": build(
(
#|pub fn[A] iter(self : T[A]) -> Iter[A] { Iter::new(yield_ => loop self.first {
#| Some({ content, next }) => {
#| if yield_(content) == IterEnd {
#| break IterEnd
#| }
#| continue next
#| }
#| None => IterContinue
#| }) }
),
),
"from_iter": build(
(
#|pub fn[A] from_iter(iter : Iter[A]) -> T[A] { let q = new()
#| iter.each(e => q.push(e))
#| q }
),
),
"of": build(
(
#|pub fn[A] of(arr : FixedArray[A]) -> T[A] { guard arr.length() > 0 else { return new() }
#| let length = arr.length()
#| let last = { content: arr[length - 1], next: None }
#| let first = for i = length - 2, x = last; i >= 0; {
#| continue i - 1, { content: arr[i], next: Some(x) }
#| } else {
#| Some(x)
#| }
#| { length, first, last: Some(last) } }
),
),
"peek_exn": build(
(
#|pub fn[A] peek_exn(self : T[A]) -> A { self.unsafe_peek() }
),
),
"pop_exn": build(
(
#|pub fn[A] pop_exn(self : T[A]) -> A { self.unsafe_pop() }
),
),
}
},
)
///|
let moonbitlang_core_quickcheck_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/quickcheck",
deps={
"moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module,
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/char": moonbitlang_core_char_module,
},
fn(_env, build) {
{
"gen": build(
(
#|pub fn[T : Arbitrary] gen(size? : Int, state? : @splitmix.RandomState) -> T { let size = match size {
#| None => 0
#| Some(x) => x
#| }
#| let state = match state {
#| None => @splitmix.RandomState::default()
#| Some(x) => x
#| }
#| Arbitrary::arbitrary(size, state) }
),
),
"samples": build(
(
#|pub fn[X : Arbitrary] samples(x : Int) -> Array[X] { let rs = @splitmix.new()
#| let array = Array::make(x, X::arbitrary(0, rs))
#| for i in 1.. RandomState { new(seed~) }
),
),
"new": build(
(
#|pub fn new(seed~ : UInt64 = 37) -> RandomState { { seed: mix64(seed), gamma: mix_gamma(seed + golden_gamma) } }
),
),
"clone": build(
(
#|pub fn clone(self : RandomState) -> RandomState { { ..self } }
),
),
"next": build(
(
#|pub fn next(self : RandomState) -> Unit { self.next_uint64() |> ignore }
),
),
"next_uint64": build(
(
#|pub fn next_uint64(self : RandomState) -> UInt64 { let { seed, gamma } = self
#| self.seed = seed + gamma
#| mix64(self.seed) }
),
),
"next_uint": build(
(
#|pub fn next_uint(self : RandomState) -> UInt { self.next_uint64().to_uint() }
),
),
"next_int64": build(
(
#|pub fn next_int64(self : RandomState) -> Int64 { self.next_uint64().reinterpret_as_int64() }
),
),
"next_two_uint": build(
(
#|pub fn next_two_uint(self : RandomState) -> (UInt, UInt) { let g = self.next_uint64()
#| ((g >> 32).to_uint(), g.to_uint()) }
),
),
"next_int": build(
(
#|pub fn next_int(self : RandomState) -> Int { self.next_uint().reinterpret_as_int() }
),
),
"next_positive_int": build(
(
#|pub fn next_positive_int(self : RandomState) -> Int { let r = self.next_int()
#| match r {
#| -2147483648 => 2147483647
#| 0 => 1
#| r if r < 0 => -r
#| r => r
#| } }
),
),
"next_float": build(
(
#|pub fn next_float(self : RandomState) -> Float { let u = self.next_uint64()
#| (u >> 11).to_float() * float_ulp }
),
),
"next_double": build(
(
#|pub fn next_double(self : RandomState) -> Double { let u = self.next_uint64()
#| (u >> 11).to_double() * double_ulp }
),
),
"split": build(
(
#|pub fn split(self : RandomState) -> RandomState { let seed1 = self.seed + self.gamma
#| self.seed = seed1 + self.gamma
#| { seed: mix64(seed1), gamma: mix_gamma(self.seed) } }
),
),
"shift_xor": build(
(
#|fn shift_xor(n : Int, w : UInt64) -> UInt64 { w ^ (w >> n) }
),
),
"shift_xor_mul": build(
(
#|fn shift_xor_mul(n : Int, k : UInt64, w : UInt64) -> UInt64 { shift_xor(n, w) * k }
),
),
"mix64": build(
(
#|fn mix64(z0 : UInt64) -> UInt64 { let z1 = shift_xor_mul(30, 0xff51afd7ed558ccd, z0)
#| let z2 = shift_xor_mul(33, 0xc4ceb9fe1a85ec53, z1)
#| shift_xor(33, z2) }
),
),
"mix64variant13": build(
(
#|fn mix64variant13(z0 : UInt64) -> UInt64 { let z1 = shift_xor_mul(30, 0xbf58476d1ce4e5b9, z0)
#| let z2 = shift_xor_mul(27, 0x94d049bb133111eb, z1)
#| shift_xor(31, z2) }
),
),
"mix_gamma": build(
(
#|fn mix_gamma(z0 : UInt64) -> UInt64 { let z1 = mix64variant13(z0 | 1)
#| let n = (z1 | (z1 >> 1)).popcnt()
#| if n >= 24 {
#| z1
#| } else {
#| z1 ^ 0xaaaaaaaaaaaaaaaa
#| } }
),
),
}
},
)
///|
let moonbitlang_core_random_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/random",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/double": moonbitlang_core_double_module,
"moonbitlang/core/random/internal/random_source": moonbitlang_core_random_internal_random_source_module,
"moonbitlang/core/bigint": moonbitlang_core_bigint_module,
},
fn(_env, build) {
{
"new": build(
(
#|pub fn new(seed~ : Bytes = b\"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456\") -> Rand { if seed.length() != 32 {
#| abort(\"seed must be 32 bytes long\")
#| }
#| @random_source.ChaCha8::new(seed) as &Source }
),
),
"chacha8": build(
(
#|pub fn chacha8(seed~ : Bytes = b\"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456\") -> &Source { @random_source.ChaCha8::new(seed) }
),
),
"new": build(
(
#|pub fn Rand::new(generator? : &Source) -> Rand { match generator {
#| None => chacha8()
#| Some(gen) => Rand(gen)
#| } }
),
),
"next": build(
(
#|fn next(self : Rand) -> UInt64 { let Rand(s) = self
#| s.next() }
),
),
"int": build(
(
#|pub fn int(self : Rand, limit~ : Int = 0) -> Int { if limit == 0 {
#| // Range [0, 2^31)
#| (self.next() >> 33).to_int()
#| } else {
#| self.uint(limit=limit.reinterpret_as_uint()).reinterpret_as_int()
#| } }
),
),
"int64": build(
(
#|pub fn int64(self : Rand, limit~ : Int64 = 0) -> Int64 { if limit == 0 {
#| // range [0, 2^63)
#| // Create a mask that keeps the lower 63 bits
#| let mask : UInt64 = (1UL << 63) - 1UL
#| return (self.next() & mask).reinterpret_as_int64()
#| } else {
#| self.uint64(limit=limit.reinterpret_as_uint64()).reinterpret_as_int64()
#| } }
),
),
"uint": build(
(
#|pub fn uint(self : Rand, limit~ : UInt = 0) -> UInt { if limit == 0 {
#| // Range: [0, 2^32)
#| return self.next().to_uint()
#| }
#| self.uint64(limit=limit.to_uint64()).to_uint() }
),
),
"uint64": build(
(
#|pub fn uint64(self : Rand, limit~ : UInt64 = 0) -> UInt64 { if limit == 0 {
#| // Range: [0, 2^64)
#| return self.next()
#| } else if (limit & (limit - 1)) == 0 {
#| // limit is a power of 2, mask to get the unbiased result.
#| return self.next() & (limit - 1)
#| }
#| let mut r = umul128(self.next(), limit)
#| if r.lo < limit {
#| let thresh = limit.lnot() % limit
#| while r.lo < thresh {
#| r = umul128(self.next(), limit)
#| }
#| }
#| r.hi }
),
),
"double": build(
(
#|pub fn double(self : Rand) -> Double { Double::convert_uint64(self.next() << 11 >> 11) /
#| Double::convert_uint64(1UL << 53) }
),
),
"float": build(
(
#|pub fn float(self : Rand) -> Float { (self.uint() << 8 >> 8).to_float() / (1U << 24).to_float() }
),
),
"bigint": build(
(
#|pub fn bigint(self : Rand, bits : Int) -> @bigint.BigInt { let mod = bits % 8
#| let len = if mod == 0 { bits / 8 } else { bits / 8 + 1 }
#| let bytes = Bytes::makei(len, i => if i == 0 && mod != 0 {
#| let mask = (1U << mod) - 1U
#| (self.uint(limit=256) & mask).to_byte()
#| } else {
#| self.uint(limit=256).to_byte()
#| })
#| @bigint.BigInt::from_octets(bytes) }
),
),
"umul128": build(
(
#|fn umul128(a : UInt64, b : UInt64) -> UInt128 { let aLo = a & 0xffffffff
#| let aHi = a >> 32
#| let bLo = b & 0xffffffff
#| let bHi = b >> 32
#| let x = aLo * bLo
#| let y = aHi * bLo + (x >> 32)
#| let z = aLo * bHi + (y & 0xffffffff)
#| let w = aHi * bHi + (y >> 32) + (z >> 32)
#| { hi: w, lo: a * b } }
),
),
"shuffle": build(
(
#|pub fn shuffle(self : Rand, limit : Int, swap : (Int, Int) -> Unit) -> Unit { if limit < 0 {
#| abort(\"Rand::shuffle: invalid argument limit\")
#| }
#| for i = limit - 1; i > 0; i = i - 1 {
#| let j = self.int(limit=i + 1)
#| swap(i, j)
#| } }
),
),
}
},
)
///|
let moonbitlang_core_random_internal_random_source_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/random/internal/random_source",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
"moonbitlang/core/bytes": moonbitlang_core_bytes_module,
},
fn(_env, build) {
{
"new": build(
(
#|pub fn ChaCha8::new(seed : Bytes) -> ChaCha8 { let seed = FixedArray::makei(SEED_CHUNK_NUM * 2, i => seed[i * 4:i * 4 + 4].to_uint_le())
#| let buffer = FixedArray::make(BUFFER_CHUNK_NUM * 2, 0U)
#| chacha_block(seed, buffer, 0)
#| { seed, buffer, counter: 0, i: 0, n: BUFFER_CHUNK_NUM.reinterpret_as_uint() } }
),
),
"next": build(
(
#|pub fn ChaCha8::next(self : ChaCha8) -> UInt64? { let i = self.i
#| if i >= self.n {
#| return None
#| }
#| self.i = i + 1
#| let index = i.reinterpret_as_int() & (BUFFER_CHUNK_NUM - 1)
#| let lo = self.buffer[index * 2].to_uint64()
#| let hi = self.buffer[index * 2 + 1].to_uint64()
#| Some((hi << 32) | lo) }
),
),
"refill": build(
(
#|pub fn ChaCha8::refill(self : ChaCha8) -> Unit { self.counter += COUNTER_INC
#| if self.counter == COUNTER_MAX {
#| // reseed
#| // 1 chunk = 64 bits = number of bits in UInt * 2
#| self.buffer.blit_to(
#| self.seed,
#| len=SEED_CHUNK_NUM * 2,
#| src_offset=(BUFFER_CHUNK_NUM - SEED_CHUNK_NUM) * 2,
#| )
#| self.counter = 0
#| }
#| chacha_block(self.seed, self.buffer, self.counter)
#| self.i = 0
#| self.n = if self.counter == COUNTER_MAX - COUNTER_INC {
#| (BUFFER_CHUNK_NUM - SEED_CHUNK_NUM).reinterpret_as_uint()
#| } else {
#| BUFFER_CHUNK_NUM.reinterpret_as_uint()
#| } }
),
),
}
},
)
///|
let moonbitlang_core_rational_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/rational",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/double": moonbitlang_core_double_module,
"moonbitlang/core/int64": moonbitlang_core_int64_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
},
fn(_env, build) {
{
"gcd": build(
(
#|fn gcd(a : Int64, b : Int64) -> Int64 { for a = a, b = b {
#| if b == 0L {
#| break a
#| }
#| continue b, a % b
#| } }
),
),
"new": build(
(
#|pub fn new(numerator : Int64, denominator : Int64) -> T? { if denominator == 0L {
#| None
#| } else {
#| let sign = if (numerator < 0L && denominator < 0L) ||
#| (numerator > 0L && denominator > 0L) {
#| 1L
#| } else {
#| -1L
#| }
#| let numerator = numerator.abs()
#| let denominator = denominator.abs()
#| let gcd = gcd(numerator, denominator)
#| Some({ numerator: sign * numerator / gcd, denominator: denominator / gcd })
#| } }
),
),
"new_unchecked": build(
(
#|fn new_unchecked(numerator : Int64, denominator : Int64) -> T { let gcd = gcd(numerator.abs(), denominator)
#| { numerator: numerator / gcd, denominator: denominator / gcd } }
),
),
"reciprocal": build(
(
#|pub fn reciprocal(self : T) -> T { if self.numerator < 0L {
#| new_unchecked(-self.denominator, -self.numerator)
#| } else {
#| new_unchecked(self.denominator, self.numerator)
#| } }
),
),
"neg": build(
(
#|pub fn T::neg(self : T) -> T { new_unchecked(-self.numerator, self.denominator) }
),
),
"abs": build(
(
#|pub fn T::abs(self : T) -> T { new_unchecked(self.numerator.abs(), self.denominator) }
),
),
"to_double": build(
(
#|pub fn to_double(self : T) -> Double { // TODO: complete algorithm
#| self.numerator.to_double() / self.denominator.to_double() }
),
),
"nan_error": build(
(
#|fn[T] nan_error() -> T raise RationalError { raise RationalError(\"Rational::from_double: cannot convert NaN\") }
),
),
"overflow_error": build(
(
#|fn[T] overflow_error() -> T raise RationalError { raise RationalError(\"Rational::from_double: overflow\") }
),
),
"from_double": build(
(
#|pub fn from_double(value : Double) -> T raise RationalError { // continued fraction algorithm
#| // Ported from https://github.com/rust-num/num
#| if value.is_nan() {
#| nan_error()
#| }
#| let sign = if value < 0.0 { -1L } else { 1L }
#| let value = value.abs()
#| let mut q = value
#| let mut n0 = 0L
#| let mut d0 = 1L
#| let mut n1 = 1L
#| let mut d1 = 0L
#| let t_max = @int64.max_value
#| let t_max_f = t_max.to_double()
#| let epsilon = 1.0 / t_max_f
#| let max_iteration = 30
#| let max_error = 10.0e-20
#| // Overflow
#| if q > t_max_f {
#| overflow_error()
#| }
#| for i in 0..= -9223372036854775808.0 && q < 9223372036854775808.0) {
#| break // overflow
#| }
#| let a = q.to_int64()
#| let a_f = a.to_double()
#| let f = q - a_f
#| // Prevent overflow
#| if !(a == 0L) &&
#| (
#| n1 > t_max / a ||
#| d1 > t_max / a ||
#| a * n1 > t_max - n0 ||
#| a * d1 > t_max - d0
#| ) {
#| break
#| }
#| let n = a * n1 + n0
#| let d = a * d1 + d0
#| n0 = n1
#| d0 = d1
#| n1 = n
#| d1 = d
#| let g = gcd(n1, d1)
#| if !(g == 0L) {
#| n1 = n1 / g
#| d1 = d1 / g
#| }
#| // Close enough?
#| let (n_f, d_f) = (n.to_double(), d.to_double())
#| if (n_f / d_f - value).abs() < max_error {
#| break
#| }
#| // Prevent division by ~0
#| if f < epsilon {
#| break
#| }
#| q = 1.0 / f
#| }
#| // Overflow
#| if d1 == 0L {
#| overflow_error()
#| }
#| match new(sign * n1, d1) {
#| Some(r) => r
#| None => abort(\"Impossible to reach\")
#| } }
),
),
"ceil": build(
(
#|pub fn T::ceil(self : T) -> Int64 { let sign = if self.numerator < 0L { -1L } else { 1L }
#| let quotient = self.numerator / self.denominator
#| if self.numerator % self.denominator == 0L {
#| quotient
#| } else {
#| quotient + (1L + sign) / 2L
#| } }
),
),
"floor": build(
(
#|pub fn T::floor(self : T) -> Int64 { let sign = if self.numerator < 0L { -1L } else { 1L }
#| let quotient = self.numerator / self.denominator
#| if self.numerator % self.denominator == 0L {
#| quotient
#| } else {
#| quotient + (-1L + sign) / 2L
#| } }
),
),
"trunc": build(
(
#|pub fn T::trunc(self : T) -> Int64 { if self.numerator < 0L {
#| -(-self.numerator / self.denominator)
#| } else {
#| self.numerator / self.denominator
#| } }
),
),
"fract": build(
(
#|pub fn fract(self : T) -> T { new_unchecked(self.numerator % self.denominator, self.denominator) }
),
),
"is_integer": build(
(
#|pub fn is_integer(self : T) -> Bool { self.denominator == 1L }
),
),
}
},
)
///|
let moonbitlang_core_ref_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/ref",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
},
fn(_env, build) {
{
"new": build(
(
#|pub fn[T] Ref::new(x : T) -> Ref[T] { { val: x } }
),
),
"new": build(
(
#|pub fn[T] new(x : T) -> Ref[T] { { val: x } }
),
),
"map": build(
(
#|pub fn[T, R] map(self : Ref[T], f : (T) -> R raise?) -> Ref[R] raise? { { val: f(self.val) } }
),
),
"protect": build(
(
#|pub fn[T, R] protect(self : Ref[T], a : T, f : () -> R raise?) -> R raise? { let old = self.val
#| self.val = a
#| try f() catch {
#| err => {
#| self.val = old
#| raise err
#| }
#| } noraise {
#| r => {
#| self.val = old
#| r
#| }
#| } }
),
),
"swap": build(
(
#|pub fn[T] Ref::swap(self : Ref[T], that : Ref[T]) -> Unit { let tmp = self.val
#| self.val = that.val
#| that.val = tmp }
),
),
"update": build(
(
#|pub fn[T] update(self : Ref[T], f : (T) -> T raise?) -> Unit raise? { self.val = f(self.val) }
),
),
}
},
)
///|
let moonbitlang_core_result_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/result",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
},
fn(_env, build) {
{
"map": build(
(
#|pub fn[T, E, U] map(self : Result[T, E], f : (T) -> U) -> Result[U, E] { match self {
#| Ok(value) => Ok(f(value))
#| Err(err) => Err(err)
#| } }
),
),
"map_err": build(
(
#|pub fn[T, E, F] map_err(self : Result[T, E], f : (E) -> F) -> Result[T, F] { match self {
#| Ok(value) => Ok(value)
#| Err(err) => Err(f(err))
#| } }
),
),
"err": build(
(
#|pub fn[T, E] err(value : E) -> Result[T, E] { Err(value) }
),
),
"ok": build(
(
#|pub fn[T, E] ok(value : T) -> Result[T, E] { Ok(value) }
),
),
"is_ok": build(
(
#|pub fn[T, E] is_ok(self : Result[T, E]) -> Bool { self is Ok(_) }
),
),
"is_err": build(
(
#|pub fn[T, E] is_err(self : Result[T, E]) -> Bool { self is Err(_) }
),
),
"or": build(
(
#|pub fn[T, E] or(self : Result[T, E], default : T) -> T { match self {
#| Ok(value) => value
#| Err(_) => default
#| } }
),
),
"or_else": build(
(
#|pub fn[T, E] or_else(self : Result[T, E], default : () -> T) -> T { match self {
#| Ok(value) => value
#| Err(_) => default()
#| } }
),
),
"flatten": build(
(
#|pub fn[T, E] flatten(self : Result[Result[T, E], E]) -> Result[T, E] { match self {
#| Ok(value) => value
#| Err(err) => Err(err)
#| } }
),
),
"fold": build(
(
#|pub fn[T, E, V] fold(self : Result[T, E], ok : (T) -> V, err : (E) -> V) -> V { match self {
#| Ok(value) => ok(value)
#| Err(error) => err(error)
#| } }
),
),
"to_option": build(
(
#|pub fn[T, E] to_option(self : Result[T, E]) -> T? { match self {
#| Ok(value) => Some(value)
#| Err(_) => None
#| } }
),
),
"unwrap": build(
(
#|pub fn[T, E] unwrap(self : Result[T, E]) -> T { match self {
#| Ok(x) => x
#| Err(_) => abort(\"called `Result::unwrap()` on an `Err` value\")
#| } }
),
),
"unwrap_err": build(
(
#|pub fn[T, E] unwrap_err(self : Result[T, E]) -> E { match self {
#| Ok(_) => abort(\"called `Result::unwrap_err()` on an `Ok` value\")
#| Err(e) => e
#| } }
),
),
"unwrap_or_error": build(
(
#|pub fn[T, E : Error] unwrap_or_error(self : Result[T, E]) -> T raise E { match self {
#| Ok(x) => x
#| Err(e) => raise e
#| } }
),
),
"wrap0": build(
(
#|pub fn[T, E : Error] wrap0(f~ : () -> T raise E) -> Result[T, E] { try f() |> Ok catch {
#| e => Err(e)
#| } }
),
),
"wrap1": build(
(
#|pub fn[T, A, E : Error] wrap1(f~ : (A) -> T raise E, a : A) -> Result[T, E] { try f(a) |> Ok catch {
#| e => Err(e)
#| } }
),
),
}
},
)
///|
let moonbitlang_core_set_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/set",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/int": moonbitlang_core_int_module,
},
fn(_env, build) {
{
"calc_grow_threshold": build(
(
#|fn calc_grow_threshold(capacity : Int) -> Int { capacity * 13 / 16 }
),
),
"new": build(
(
#|pub fn[K] Set::new(capacity~ : Int = 8) -> Set[K] { let capacity = capacity.next_power_of_two()
#| {
#| size: 0,
#| capacity,
#| capacity_mask: capacity - 1,
#| grow_at: calc_grow_threshold(capacity),
#| entries: FixedArray::make(capacity, None),
#| list: FixedArray::make(capacity, { prev: None, next: None }),
#| head: None,
#| tail: None,
#| } }
),
),
"from_array": build(
(
#|pub fn[K : Hash + Eq] Set::from_array(arr : Array[K]) -> Set[K] { let m = Set::new(capacity=arr.length())
#| arr.each(e => m.add(e))
#| m }
),
),
"add_and_check": build(
(
#|pub fn[K : Hash + Eq] add_and_check(self : Set[K], key : K) -> Bool { if self.size >= self.grow_at {
#| self.grow()
#| }
#| let hash = key.hash()
#| let insert_entry = { idx: -1, psl: 0, hash, key }
#| let list_node : SListNode[K] = { prev: None, next: None }
#| for i = 0, idx = hash & self.capacity_mask, entry = insert_entry, node = list_node {
#| match self.entries[idx] {
#| None => {
#| self.entries[idx] = Some(entry)
#| self.list[idx] = node
#| entry.idx = idx
#| self.add_entry_to_tail(insert_entry)
#| self.size += 1
#| break true
#| }
#| Some(curr_entry) => {
#| let curr_node = self.list[curr_entry.idx]
#| if curr_entry.hash == entry.hash && curr_entry.key == entry.key {
#| break false
#| }
#| if entry.psl > curr_entry.psl {
#| self.entries[idx] = Some(entry)
#| self.list[idx] = node
#| entry.idx = idx
#| curr_entry.psl += 1
#| continue i + 1, (idx + 1) & self.capacity_mask, curr_entry, curr_node
#| } else {
#| entry.psl += 1
#| continue i + 1, (idx + 1) & self.capacity_mask, entry, node
#| }
#| }
#| }
#| } }
),
),
"add": build(
(
#|pub fn[K : Hash + Eq] add(self : Set[K], key : K) -> Unit { if self.size >= self.grow_at {
#| self.grow()
#| }
#| let hash = key.hash()
#| let insert_entry = { idx: -1, psl: 0, hash, key }
#| let list_node : SListNode[K] = { prev: None, next: None }
#| for i = 0, idx = hash & self.capacity_mask, entry = insert_entry, node = list_node {
#| match self.entries[idx] {
#| None => {
#| self.entries[idx] = Some(entry)
#| self.list[idx] = node
#| entry.idx = idx
#| self.add_entry_to_tail(insert_entry)
#| self.size += 1
#| break
#| }
#| Some(curr_entry) => {
#| let curr_node = self.list[curr_entry.idx]
#| if curr_entry.hash == entry.hash && curr_entry.key == entry.key {
#| break
#| }
#| if entry.psl > curr_entry.psl {
#| self.entries[idx] = Some(entry)
#| self.list[idx] = node
#| entry.idx = idx
#| curr_entry.psl += 1
#| continue i + 1, (idx + 1) & self.capacity_mask, curr_entry, curr_node
#| } else {
#| entry.psl += 1
#| continue i + 1, (idx + 1) & self.capacity_mask, entry, node
#| }
#| }
#| }
#| } }
),
),
"contains": build(
(
#|pub fn[K : Hash + Eq] contains(self : Set[K], key : K) -> Bool { let hash = key.hash()
#| for i = 0, idx = hash & self.capacity_mask {
#| match self.entries[idx] {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| break true
#| }
#| if i > entry.psl {
#| break false
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#| None => break false
#| }
#| } }
),
),
"remove": build(
(
#|pub fn[K : Hash + Eq] remove(self : Set[K], key : K) -> Unit { let hash = key.hash()
#| for i = 0, idx = hash & self.capacity_mask {
#| match self.entries[idx] {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| self.entries[idx] = None
#| self.remove_entry(entry)
#| self.shift_back(idx)
#| self.size -= 1
#| break
#| }
#| if i > entry.psl {
#| break
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#| None => break
#| }
#| } }
),
),
"remove_and_check": build(
(
#|pub fn[K : Hash + Eq] remove_and_check(self : Set[K], key : K) -> Bool { let hash = key.hash()
#| for i = 0, idx = hash & self.capacity_mask {
#| match self.entries[idx] {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| self.entries[idx] = None
#| self.remove_entry(entry)
#| self.shift_back(idx)
#| self.size -= 1
#| break true
#| }
#| if i > entry.psl {
#| break false
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#| None => break false
#| }
#| } }
),
),
"add_entry_to_tail": build(
(
#|fn[K] add_entry_to_tail(self : Set[K], entry : SEntry[K]) -> Unit { match self.tail {
#| None => {
#| self.head = Some(entry)
#| self.tail = Some(entry)
#| }
#| Some(tail) => {
#| self.list[tail.idx].next = Some(entry)
#| self.list[entry.idx].prev = Some(tail)
#| self.tail = Some(entry)
#| }
#| } }
),
),
"remove_entry": build(
(
#|fn[K : Eq] remove_entry(self : Set[K], entry : SEntry[K]) -> Unit { let node = self.list[entry.idx]
#| if self.is_empty() {
#| self.head = None
#| self.tail = None
#| } else {
#| if self.head.unwrap() == entry {
#| self.head = node.next
#| }
#| if self.tail.unwrap() == entry {
#| self.tail = node.prev
#| }
#| if node.prev is Some(prev) {
#| self.list[prev.idx].next = node.next
#| }
#| if node.next is Some(next) {
#| self.list[next.idx].prev = node.prev
#| }
#| }
#| node.prev = None
#| node.next = None }
),
),
"shift_back": build(
(
#|fn[K] shift_back(self : Set[K], start_index : Int) -> Unit { for prev = start_index, curr = (start_index + 1) & self.capacity_mask {
#| match (self.entries[curr], self.list[curr]) {
#| (Some(entry), currNode) => {
#| if entry.psl == 0 {
#| break
#| }
#| entry.psl -= 1
#| entry.idx = prev
#| self.entries[prev] = Some(entry)
#| self.entries[curr] = None
#| self.list[prev].prev = currNode.prev
#| self.list[prev].next = currNode.next
#| currNode.prev = None
#| currNode.next = None
#| continue curr, (curr + 1) & self.capacity_mask
#| }
#| (None, _) => break
#| }
#| } }
),
),
"grow": build(
(
#|fn[K : Hash + Eq] grow(self : Set[K]) -> Unit { let old_head = self.head
#| let old_list = self.list
#| let new_capacity = self.capacity << 1
#| self.entries = FixedArray::make(new_capacity, None)
#| self.list = FixedArray::make(new_capacity, { prev: None, next: None })
#| self.capacity = new_capacity
#| self.capacity_mask = new_capacity - 1
#| self.grow_at = calc_grow_threshold(self.capacity)
#| self.size = 0
#| self.head = None
#| self.tail = None
#| loop old_head {
#| Some({ idx, key, .. }) => {
#| self.add(key)
#| continue old_list[idx].next
#| }
#| None => break
#| } }
),
),
"size": build(
(
#|pub fn[K] size(self : Set[K]) -> Int { self.size }
),
),
"capacity": build(
(
#|pub fn[K] capacity(self : Set[K]) -> Int { self.capacity }
),
),
"is_empty": build(
(
#|pub fn[K] is_empty(self : Set[K]) -> Bool { self.size == 0 }
),
),
"each": build(
(
#|pub fn[K] each(self : Set[K], f : (K) -> Unit raise?) -> Unit raise? { loop self.head {
#| Some({ key, idx, .. }) => {
#| f(key)
#| continue self.list[idx].next
#| }
#| None => break
#| } }
),
),
"eachi": build(
(
#|pub fn[K] eachi(self : Set[K], f : (Int, K) -> Unit raise?) -> Unit raise? { loop (0, self.head) {
#| (i, Some({ key, idx, .. })) => {
#| f(i, key)
#| continue (i + 1, self.list[idx].next)
#| }
#| (_, None) => break
#| } }
),
),
"clear": build(
(
#|pub fn[K] clear(self : Set[K]) -> Unit { self.entries.fill(None)
#| self.size = 0
#| self.head = None
#| self.tail = None }
),
),
"iter": build(
(
#|pub fn[K] iter(self : Set[K]) -> Iter[K] { Iter::new(yield_ => loop self.head {
#| Some({ key, idx, .. }) => {
#| if yield_(key) == IterEnd {
#| break IterEnd
#| }
#| continue self.list[idx].next
#| }
#| None => break IterContinue
#| }) }
),
),
"to_array": build(
(
#|pub fn[K] to_array(self : Set[K]) -> Array[K] { let res = Array::new(capacity=self.size)
#| loop self.head {
#| Some({ key, idx, .. }) => {
#| res.push(key)
#| continue self.list[idx].next
#| }
#| None => break
#| }
#| res }
),
),
"of": build(
(
#|pub fn[K : Hash + Eq] Set::of(arr : FixedArray[K]) -> Set[K] { let length = arr.length()
#| let m = Set::new(capacity=length)
#| // arr.iter((e) => { m.set(e.0, e.1) })
#| for i in 0.. Set[K] { let m = Set::new()
#| iter.each(e => m.add(e))
#| m }
),
),
"difference": build(
(
#|pub fn[K : Hash + Eq] difference(self : Set[K], other : Set[K]) -> Set[K] { let m = Set::new()
#| self.each(k => if !other.contains(k) { m.add(k) })
#| m }
),
),
"union": build(
(
#|pub fn[K : Hash + Eq] union(self : Set[K], other : Set[K]) -> Set[K] { let m = Set::new()
#| self.each(k => m.add(k))
#| other.each(k => m.add(k))
#| m }
),
),
"intersection": build(
(
#|pub fn[K : Hash + Eq] intersection(self : Set[K], other : Set[K]) -> Set[K] { let m = Set::new()
#| self.each(k => if other.contains(k) { m.add(k) })
#| m }
),
),
"insert": build(
(
#|pub fn[K : Hash + Eq] insert(self : Set[K], key : K) -> Unit { self.add(key) }
),
),
}
},
)
///|
let moonbitlang_core_sorted_map_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/sorted_map",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/option": moonbitlang_core_option_module,
"moonbitlang/core/tuple": moonbitlang_core_tuple_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
},
fn(_env, build) {
{
"op_set": build(
(
#|pub fn[K : Compare, V] op_set(self : T[K, V], key : K, value : V) -> Unit { self.add(key, value) }
),
),
"new": build(
(
#|pub fn[K, V] new() -> T[K, V] { { root: None, size: 0 } }
),
),
"from_array": build(
(
#|pub fn[K : Compare, V] from_array(entries : Array[(K, V)]) -> T[K, V] { let map = { root: None, size: 0 }
#| entries.each(e => map.add(e.0, e.1))
#| map }
),
),
"add": build(
(
#|pub fn[K : Compare, V] add(self : T[K, V], key : K, value : V) -> Unit { let (new_root, inserted) = add_node(self.root, key, value)
#| if self.root != new_root {
#| self.root = new_root
#| }
#| if inserted {
#| self.size += 1
#| } }
),
),
"remove": build(
(
#|pub fn[K : Compare, V] remove(self : T[K, V], key : K) -> Unit { if self.root is Some(old_root) {
#| let (new_root, deleted) = delete_node(old_root, key)
#| if self.root != new_root {
#| self.root = new_root
#| }
#| if deleted {
#| self.size -= 1
#| }
#| } }
),
),
"get": build(
(
#|pub fn[K : Compare, V] get(self : T[K, V], key : K) -> V? { loop self.root {
#| Some(node) => {
#| let cmp = key.compare(node.key)
#| if cmp == 0 {
#| break Some(node.value)
#| } else if cmp > 0 {
#| continue node.right
#| } else {
#| continue node.left
#| }
#| }
#| None => break None
#| } }
),
),
"contains": build(
(
#|pub fn[K : Compare, V] contains(self : T[K, V], key : K) -> Bool { match self.get(key) {
#| Some(_) => true
#| None => false
#| } }
),
),
"is_empty": build(
(
#|pub fn[K, V] is_empty(self : T[K, V]) -> Bool { self.size == 0 }
),
),
"size": build(
(
#|pub fn[K, V] size(self : T[K, V]) -> Int { self.size }
),
),
"clear": build(
(
#|pub fn[K, V] clear(self : T[K, V]) -> Unit { self.root = None
#| self.size = 0 }
),
),
"each": build(
(
#|pub fn[K, V] each(self : T[K, V], f : (K, V) -> Unit raise?) -> Unit raise? { fn dfs(root : Node[K, V]?) -> Unit raise? {
#| if root is Some(root) {
#| dfs(root.left)
#| f(root.key, root.value)
#| dfs(root.right)
#| }
#| }
#| dfs(self.root) }
),
),
"keys": build(
(
#|pub fn[K, V] keys(self : T[K, V]) -> Array[K] { let keys = Array::new(capacity=self.size)
#| self.each((k, _v) => keys.push(k))
#| keys }
),
),
"values": build(
(
#|pub fn[K, V] values(self : T[K, V]) -> Array[V] { let values = Array::new(capacity=self.size)
#| self.each((_k, v) => values.push(v))
#| values }
),
),
"to_array": build(
(
#|pub fn[K, V] to_array(self : T[K, V]) -> Array[(K, V)] { let arr = Array::new(capacity=self.size)
#| self.each((k, v) => arr.push((k, v)))
#| arr }
),
),
"iter": build(
(
#|pub fn[K, V] iter(self : T[K, V]) -> Iter[(K, V)] { Iter::new(yield_ => {
#| fn go(x : Node[K, V]?) {
#| match x {
#| None => IterContinue
#| Some({ left, right, key, value, .. }) =>
#| if go(left) is IterEnd {
#| IterEnd
#| } else if yield_((key, value)) is IterEnd {
#| IterEnd
#| } else {
#| go(right)
#| }
#| }
#| }
#| go(self.root)
#| }) }
),
),
"iter2": build(
(
#|pub fn[K, V] iter2(self : T[K, V]) -> Iter2[K, V] { Iter2::new(yield_ => {
#| fn go(x : Node[K, V]?) {
#| match x {
#| None => IterContinue
#| Some({ left, right, key, value, .. }) =>
#| if go(left) is IterEnd {
#| IterEnd
#| } else if yield_(key, value) is IterEnd {
#| IterEnd
#| } else {
#| go(right)
#| }
#| }
#| }
#| go(self.root)
#| }) }
),
),
"from_iter": build(
(
#|pub fn[K : Compare, V] from_iter(iter : Iter[(K, V)]) -> T[K, V] { let m = new()
#| iter.each(e => m[e.0] = e.1)
#| m }
),
),
"range": build(
(
#|pub fn[K : Compare, V] range(self : T[K, V], low : K, high : K) -> Iter2[K, V] { Iter2::new(yield_ => {
#| fn go(x : Node[K, V]?) {
#| match x {
#| None => IterContinue
#| Some({ left, right, key, value, .. }) => {
#| let cmp_key_low = key.compare(low)
#| let cmp_key_high = key.compare(high)
#| if cmp_key_low > 0 && go(left) is IterEnd {
#| IterEnd
#| } else if cmp_key_low >= 0 &&
#| cmp_key_high <= 0 &&
#| yield_(key, value) is IterEnd {
#| IterEnd
#| } else if cmp_key_high < 0 {
#| go(right)
#| } else {
#| IterContinue
#| }
#| }
#| }
#| }
#| go(self.root)
#| }) }
),
),
"update_height": build(
(
#|fn[K, V] update_height(self : Node[K, V]) -> Unit { self.height = 1 + max(height(self.left), height(self.right)) }
),
),
"height_ge": build(
(
#|fn[K, V] height_ge(x1 : Node[K, V]?, x2 : Node[K, V]?) -> Bool { match x2 {
#| None => true
#| Some(n2) =>
#| match x1 {
#| None => false
#| Some(n1) => n1.height >= n2.height
#| }
#| } }
),
),
"balance": build(
(
#|fn[K, V] balance(root : Node[K, V]) -> Node[K, V] { let (l, r) = (root.left, root.right)
#| let (hl, hr) = (height(l), height(r))
#| let new_root = if hl > hr + 1 {
#| let { left: ll, right: lr, .. } = l.unwrap()
#| if height_ge(ll, lr) {
#| rotate_r(root)
#| } else {
#| rotate_lr(root)
#| }
#| } else if hr > hl + 1 {
#| let { left: rl, right: rr, .. } = r.unwrap()
#| if height_ge(rr, rl) {
#| rotate_l(root)
#| } else {
#| rotate_rl(root)
#| }
#| } else {
#| root
#| }
#| new_root.update_height()
#| new_root }
),
),
"rotate_l": build(
(
#|fn[K, V] rotate_l(n : Node[K, V]) -> Node[K, V] { let r = n.right.unwrap()
#| n.right = r.left
#| r.left = Some(n)
#| n.update_height()
#| r.update_height()
#| r }
),
),
"rotate_r": build(
(
#|fn[K, V] rotate_r(n : Node[K, V]) -> Node[K, V] { let l = n.left.unwrap()
#| n.left = l.right
#| l.right = Some(n)
#| n.update_height()
#| l.update_height()
#| l }
),
),
"rotate_lr": build(
(
#|fn[K, V] rotate_lr(n : Node[K, V]) -> Node[K, V] { let l = n.left.unwrap()
#| let v = rotate_l(l)
#| n.left = Some(v)
#| rotate_r(n) }
),
),
"rotate_rl": build(
(
#|fn[K, V] rotate_rl(n : Node[K, V]) -> Node[K, V] { let r = n.right.unwrap()
#| let v = rotate_r(r)
#| n.right = Some(v)
#| rotate_l(n) }
),
),
"op_get": build(
(
#|pub fn[K : Compare, V] op_get(self : T[K, V], key : K) -> V? { self.get(key) }
),
),
"of": build(
(
#|pub fn[K : Compare, V] of(entries : Array[(K, V)]) -> T[K, V] { let map = { root: None, size: 0 }
#| entries.each(e => map.add(e.0, e.1))
#| map }
),
),
"new_node": build(
(
#|fn[K, V] new_node(key : K, value : V) -> Node[K, V] { { key, value, left: None, right: None, height: 1 } }
),
),
"max": build(
(
#|fn max(x : Int, y : Int) -> Int { if x > y {
#| x
#| } else {
#| y
#| } }
),
),
"height": build(
(
#|fn[K, V] height(node : Node[K, V]?) -> Int { match node {
#| None => 0
#| Some(n) => n.height
#| } }
),
),
"debug_node": build(
(
#|fn[K : Show, V : Show] debug_node(self : Node[K, V]) -> String { let l = match self.left {
#| Some(left) => left.debug_node()
#| None => \"_\"
#| }
#| let r = match self.right {
#| Some(right) => right.debug_node()
#| None => \"_\"
#| }
#| \"([\\{self.height}]\\{self.key},\\{self.value},\\{l},\\{r})\" }
),
),
"debug_tree": build(
(
#|fn[K : Show, V : Show] debug_tree(self : T[K, V]) -> String { match self.root {
#| Some(root) => root.debug_node()
#| None => \"_\"
#| } }
),
),
}
},
)
///|
let moonbitlang_core_sorted_set_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/sorted_set",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/option": moonbitlang_core_option_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
},
fn(_env, build) {
{
"from_iter": build(
(
#|pub fn[V : Compare] T::from_iter(iter : Iter[V]) -> T[V] { from_iter(iter) }
),
),
"of": build(
(
#|pub fn[V : Compare] of(array : Array[V]) -> T[V] { let set = new()
#| for i in 0.. T[V] { self.copy() }
),
),
"diff": build(
(
#|pub fn[V : Compare] diff(self : T[V], src : T[V]) -> T[V] { let ret = new()
#| self.each(x => if !src.contains(x) { ret.add(x) })
#| ret }
),
),
"intersect": build(
(
#|pub fn[V : Compare] intersect(self : T[V], src : T[V]) -> T[V] { self.intersection(src) }
),
),
"max": build(
(
#|fn max(x : Int, y : Int) -> Int { if x > y {
#| x
#| } else {
#| y
#| } }
),
),
"height": build(
(
#|fn[V] height(node : Node[V]?) -> Int { match node {
#| None => 0
#| Some(n) => n.height
#| } }
),
),
"debug_node": build(
(
#|fn[V : Show] debug_node(self : Node[V]) -> String { let l = match self.left {
#| Some(left) => left.debug_node()
#| None => \"_\"
#| }
#| let r = match self.right {
#| Some(right) => right.debug_node()
#| None => \"_\"
#| }
#| let value = self.value
#| let height = self.height
#| \"([\\{height}]\\{value},\\{l},\\{r})\" }
),
),
"debug_tree": build(
(
#|fn[V : Show] debug_tree(self : T[V]) -> String { match self.root {
#| Some(root) => root.debug_node()
#| None => \"_\"
#| } }
),
),
"new": build(
(
#|pub fn[V] new() -> T[V] { { root: None, size: 0 } }
),
),
"singleton": build(
(
#|pub fn[V] singleton(value : V) -> T[V] { { root: Some({ value, left: None, right: None, height: 1 }), size: 1 } }
),
),
"from_array": build(
(
#|pub fn[V : Compare] from_array(array : Array[V]) -> T[V] { let set = new()
#| for i in 0.. T[V] { match self.root {
#| None => new()
#| Some(_) => { root: copy_tree(self.root), size: self.size }
#| } }
),
),
"copy_tree": build(
(
#|fn[V] copy_tree(node : Node[V]?) -> Node[V]? { match node {
#| None => None
#| Some(node) => {
#| let left = copy_tree(node.left)
#| let right = copy_tree(node.right)
#| let new_node = new_node(node.value, left~, right~, height=node.height)
#| Some(new_node)
#| }
#| } }
),
),
"add": build(
(
#|pub fn[V : Compare] add(self : T[V], value : V) -> Unit { let (new_root, inserted) = add_node(self.root, value)
#| if self.root != new_root {
#| self.root = new_root
#| }
#| if inserted {
#| self.size += 1
#| } }
),
),
"remove": build(
(
#|pub fn[V : Compare] remove(self : T[V], value : V) -> Unit { if self.root is Some(old_root) {
#| let (new_root, deleted) = delete_node(old_root, value)
#| if self.root != new_root {
#| self.root = new_root
#| }
#| if deleted {
#| self.size -= 1
#| }
#| } }
),
),
"contains": build(
(
#|pub fn[V : Compare] contains(self : T[V], value : V) -> Bool { loop (self.root, value) {
#| (None, _) => false
#| (Some(node), value) => {
#| let compare_result = value.compare(node.value)
#| if compare_result == 0 {
#| true
#| } else if compare_result < 0 {
#| continue (node.left, value)
#| } else {
#| continue (node.right, value)
#| }
#| }
#| } }
),
),
"union": build(
(
#|pub fn[V : Compare] union(self : T[V], src : T[V]) -> T[V] { fn aux(a : Node[V]?, b : Node[V]?) -> Node[V]? {
#| match (a, b) {
#| (Some(_), None) => a
#| (None, Some(_)) => b
#| (Some({ value: va, left: la, right: ra, .. }), Some(_)) => {
#| let (l, r) = split(b, va)
#| Some(join(aux(la, l), va, aux(ra, r)))
#| }
#| (None, None) => None
#| }
#| }
#| match (self.root, src.root) {
#| (Some(_), Some(_)) => {
#| let t1 = copy_tree(self.root)
#| let t2 = copy_tree(src.root)
#| let t = aux(t1, t2)
#| let mut ct = 0
#| let ret = { root: t, size: 0 }
#| // TODO: optimize this. Avoid counting the size of the set.
#| ret.each(_x => ct = ct + 1)
#| ret.size = ct
#| ret
#| }
#| (Some(_), None) => { root: copy_tree(self.root), size: self.size }
#| (None, Some(_)) => { root: copy_tree(src.root), size: src.size }
#| (None, None) => new()
#| } }
),
),
"split": build(
(
#|fn[V : Compare] split(root : Node[V]?, value : V) -> (Node[V]?, Node[V]?) { match root {
#| None => (None, None)
#| Some(node) => {
#| let comp = value.compare(node.value)
#| if comp == 0 {
#| (node.left, node.right)
#| } else if comp < 0 {
#| let (l, r) = split(node.left, value)
#| (l, Some(join(r, node.value, node.right)))
#| } else {
#| let (l, r) = split(node.right, value)
#| (Some(join(node.left, node.value, l)), r)
#| }
#| }
#| } }
),
),
"join": build(
(
#|fn[V : Compare] join(left : Node[V]?, value : V, right : Node[V]?) -> Node[V] { let (hl, hr) = (height(left), height(right))
#| if hl > hr + 1 {
#| join_right(left, value, right)
#| } else if hr > hl + 1 {
#| join_left(left, value, right)
#| } else {
#| new_node_update_height(value, left~, right~)
#| } }
),
),
"join_left": build(
(
#|fn[V : Compare] join_left(l : Node[V]?, v : V, r : Node[V]?) -> Node[V] { let { value: rv, left: rl, right: rr, .. } = r.unwrap()
#| let node = if height(rl) <= height(l) + 1 {
#| let new_l = new_node_update_height(left=l, v, right=rl)
#| if height(Some(new_l)) <= height(rr) + 1 {
#| new_node_update_height(left=Some(new_l), rv, right=rr)
#| } else {
#| let new_l = rotate_l(new_l)
#| let new = new_node_update_height(left=Some(new_l), rv, right=rr)
#| rotate_r(new)
#| }
#| } else {
#| let new_l = join_left(l, v, rl)
#| let new = new_node_update_height(left=Some(new_l), rv, right=rr)
#| if height(Some(new_l)) <= height(rr) + 1 {
#| new
#| } else {
#| rotate_r(new)
#| }
#| }
#| node.update_height()
#| node }
),
),
"join_right": build(
(
#|fn[V : Compare] join_right(l : Node[V]?, v : V, r : Node[V]?) -> Node[V] { let { value: lv, left: ll, right: lr, .. } = l.unwrap()
#| let node = if height(lr) <= height(r) + 1 {
#| let new_r = new_node_update_height(left=lr, v, right=r)
#| if height(Some(new_r)) <= height(ll) + 1 {
#| new_node_update_height(left=ll, lv, right=Some(new_r))
#| } else {
#| let new_r = rotate_r(new_r)
#| let new = new_node_update_height(left=ll, lv, right=Some(new_r))
#| rotate_l(new)
#| }
#| } else {
#| let new_r = join_right(lr, v, r)
#| let new = new_node_update_height(left=ll, lv, right=Some(new_r))
#| if height(Some(new_r)) <= height(ll) + 1 {
#| new
#| } else {
#| rotate_l(new)
#| }
#| }
#| node.update_height()
#| node }
),
),
"difference": build(
(
#|pub fn[V : Compare] difference(self : T[V], src : T[V]) -> T[V] { let ret = new()
#| self.each(x => if !src.contains(x) { ret.add(x) })
#| ret }
),
),
"symmetric_difference": build(
(
#|pub fn[V : Compare] symmetric_difference(self : T[V], other : T[V]) -> T[V] { // TODO: Optimize this function to avoid creating two intermediate sets.
#| let set1 = self.difference(other)
#| let set2 = other.difference(self)
#| set1.union(set2) }
),
),
"intersection": build(
(
#|pub fn[V : Compare] intersection(self : T[V], src : T[V]) -> T[V] { let ret = new()
#| self.each(x => if src.contains(x) { ret.add(x) })
#| ret }
),
),
"subset": build(
(
#|pub fn[V : Compare] subset(self : T[V], src : T[V]) -> Bool { let mut ret = true
#| self.each(x => if !src.contains(x) { ret = false })
#| ret }
),
),
"disjoint": build(
(
#|pub fn[V : Compare] disjoint(self : T[V], src : T[V]) -> Bool { let mut ret = true
#| self.each(x => if src.contains(x) { ret = false })
#| ret }
),
),
"is_empty": build(
(
#|pub fn[V] is_empty(self : T[V]) -> Bool { self.root is None }
),
),
"size": build(
(
#|pub fn[V] size(self : T[V]) -> Int { self.size }
),
),
"each": build(
(
#|pub fn[V] each(self : T[V], f : (V) -> Unit raise?) -> Unit raise? { fn dfs(root : Node[V]?) -> Unit raise? {
#| if root is Some(root) {
#| dfs(root.left)
#| f(root.value)
#| dfs(root.right)
#| }
#| }
#| dfs(self.root) }
),
),
"eachi": build(
(
#|pub fn[V] eachi(self : T[V], f : (Int, V) -> Unit raise?) -> Unit raise? { let mut i = 0
#| self.each(v => {
#| f(i, v)
#| i = i + 1
#| }) }
),
),
"to_array": build(
(
#|pub fn[V] to_array(self : T[V]) -> Array[V] { if self.size == 0 {
#| []
#| } else {
#| let padding = self.root.unwrap().value
#| let arr = Array::make(self.size, padding)
#| let mut i = 0
#| fn dfs(root : Node[V]?) -> Unit {
#| if root is Some(root) {
#| dfs(root.left)
#| arr[i] = root.value
#| i = i + 1
#| dfs(root.right)
#| }
#| }
#| dfs(self.root)
#| arr
#| } }
),
),
"iter": build(
(
#|pub fn[V] iter(self : T[V]) -> Iter[V] { Iter::new(yield_ => {
#| fn go(x : Node[V]?) {
#| match x {
#| None => IterContinue
#| Some({ left, right, value, .. }) =>
#| if go(left) is IterEnd {
#| IterEnd
#| } else if yield_(value) is IterEnd {
#| IterEnd
#| } else {
#| go(right)
#| }
#| }
#| }
#| go(self.root)
#| }) }
),
),
"from_iter": build(
(
#|pub fn[V : Compare] from_iter(iter : Iter[V]) -> T[V] { let s = new()
#| iter.each(e => s.add(e))
#| s }
),
),
"range": build(
(
#|pub fn[V : Compare] range(self : T[V], low : V, high : V) -> Iter[V] { Iter::new(yield_ => {
#| fn go(x : Node[V]?) {
#| match x {
#| None => IterContinue
#| Some({ left, right, value, .. }) => {
#| let cmp_key_low = value.compare(low)
#| let cmp_key_high = value.compare(high)
#| if cmp_key_low > 0 && go(left) is IterEnd {
#| IterEnd
#| } else if cmp_key_low >= 0 &&
#| cmp_key_high <= 0 &&
#| yield_(value) is IterEnd {
#| IterEnd
#| } else if cmp_key_high < 0 {
#| go(right)
#| } else {
#| IterContinue
#| }
#| }
#| }
#| }
#| go(self.root)
#| }) }
),
),
"update_height": build(
(
#|fn[V] update_height(self : Node[V]) -> Unit { self.height = 1 + max(height(self.left), height(self.right)) }
),
),
"height_ge": build(
(
#|fn[V] height_ge(x1 : Node[V]?, x2 : Node[V]?) -> Bool { match x2 {
#| None => true
#| Some(n2) =>
#| match x1 {
#| None => false
#| Some(n1) => n1.height >= n2.height
#| }
#| } }
),
),
"balance": build(
(
#|fn[V] balance(root : Node[V]) -> Node[V] { let (l, r) = (root.left, root.right)
#| let (hl, hr) = (height(l), height(r))
#| let new_root = if hl > hr + 1 {
#| let { left: ll, right: lr, .. } = l.unwrap()
#| if height_ge(ll, lr) {
#| rotate_r(root)
#| } else {
#| rotate_lr(root)
#| }
#| } else if hr > hl + 1 {
#| let { left: rl, right: rr, .. } = r.unwrap()
#| if height_ge(rr, rl) {
#| rotate_l(root)
#| } else {
#| rotate_rl(root)
#| }
#| } else {
#| root
#| }
#| new_root.update_height()
#| new_root }
),
),
"rotate_l": build(
(
#|fn[V] rotate_l(n : Node[V]) -> Node[V] { let r = n.right.unwrap()
#| n.right = r.left
#| r.left = Some(n)
#| n.update_height()
#| r.update_height()
#| r }
),
),
"rotate_r": build(
(
#|fn[V] rotate_r(n : Node[V]) -> Node[V] { let l = n.left.unwrap()
#| n.left = l.right
#| l.right = Some(n)
#| n.update_height()
#| l.update_height()
#| l }
),
),
"rotate_lr": build(
(
#|fn[V] rotate_lr(n : Node[V]) -> Node[V] { let l = n.left.unwrap()
#| let v = rotate_l(l)
#| n.left = Some(v)
#| rotate_r(n) }
),
),
"rotate_rl": build(
(
#|fn[V] rotate_rl(n : Node[V]) -> Node[V] { let r = n.right.unwrap()
#| let v = rotate_r(r)
#| n.right = Some(v)
#| rotate_l(n) }
),
),
"add_node": build(
(
#|fn[V : Compare] add_node(root : Node[V]?, value : V) -> (Node[V]?, Bool) { match root {
#| None => (Some(new_node(value)), true)
#| Some(n) => {
#| let comp = value.compare(n.value)
#| if comp == 0 {
#| n.value = value
#| (Some(n), false)
#| } else {
#| let (l, r) = (n.left, n.right)
#| if comp < 0 {
#| let (nl, inserted) = add_node(l, value)
#| n.left = nl
#| (Some(balance(n)), inserted)
#| } else {
#| let (nr, inserted) = add_node(r, value)
#| n.right = nr
#| (Some(balance(n)), inserted)
#| }
#| }
#| }
#| } }
),
),
"delete_node": build(
(
#|fn[V : Compare] delete_node(root : Node[V], value : V) -> (Node[V]?, Bool) { let comp = value.compare(root.value)
#| if comp == 0 {
#| let (l, r) = (root.left, root.right)
#| let n = match (l, r) {
#| (Some(_), Some(nr)) => {
#| root.right = replace_root_with_min(root, nr)
#| Some(balance(root))
#| }
#| (None, Some(_)) => r
#| (Some(_), None) | (None, None) => l
#| }
#| (n, true)
#| } else if comp < 0 {
#| match root.left {
#| None => (Some(root), false)
#| Some(l) => {
#| let (nl, deleted) = delete_node(l, value)
#| root.left = nl
#| (Some(balance(root)), deleted)
#| }
#| }
#| } else {
#| match root.right {
#| None => (Some(root), false)
#| Some(r) => {
#| let (nr, deleted) = delete_node(r, value)
#| root.right = nr
#| (Some(balance(root)), deleted)
#| }
#| }
#| } }
),
),
}
},
)
///|
let moonbitlang_core_strconv_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/strconv",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/double": moonbitlang_core_double_module,
"moonbitlang/core/uint64": moonbitlang_core_uint64_module,
"moonbitlang/core/string": moonbitlang_core_string_module,
"moonbitlang/core/char": moonbitlang_core_char_module,
},
fn(_env, build) {
{
"parse": build(
(
#|pub fn[A : FromStr] parse(str : String) -> A raise StrConvError { A::from_string(str) }
),
),
"parse_bool": build(
(
#|pub fn parse_bool(str : @string.View) -> Bool raise StrConvError { match str {
#| \"1\" | \"t\" | \"T\" | \"true\" | \"TRUE\" | \"True\" => true
#| \"0\" | \"f\" | \"F\" | \"false\" | \"FALSE\" | \"False\" => false
#| _ => syntax_err()
#| } }
),
),
"mantissa_explicit_bits": (None, Int(52)),
"parse_double": build(
(
#|pub fn parse_double(str : @string.View) -> Double raise StrConvError { if str.length() == 0 {
#| syntax_err()
#| }
#| if !check_underscore(str) {
#| syntax_err()
#| }
#| // validate its a number
#| let (num, consumed) = match parse_number(str) {
#| Some(r) => r
#| None =>
#| match parse_inf_nan(str) {
#| Some((num, consumed)) =>
#| if str.length() != consumed {
#| syntax_err()
#| } else {
#| return num
#| }
#| None => syntax_err()
#| }
#| }
#| if str.length() != consumed {
#| syntax_err()
#| }
#| // Clinger's fast path (How to read floating point numbers accurately)[https://doi.org/10.1145/989393.989430]
#| match num.try_fast_path() {
#| Some(value) => value
#| None => {
#| // fallback to slow path
#| let ret = parse_decimal_priv(str)
#| ret.to_double_priv()
#| }
#| } }
),
),
"is_fast_path": build(
(
#|fn is_fast_path(self : Number) -> Bool { min_exponent_fast_path <= self.exponent &&
#| self.exponent <= max_exponent_disguised_fast_path &&
#| self.mantissa <= max_mantissa_fast_path &&
#| !self.many_digits }
),
),
"pow10_fast_path": build(
(
#|fn pow10_fast_path(exponent : Int) -> Double { table[exponent & 31] }
),
),
"try_fast_path": build(
(
#|fn try_fast_path(self : Number) -> Double? { if self.is_fast_path() {
#| let mut value = if self.exponent <= max_exponent_fast_path {
#| // normal fast path
#| let value = Double::convert_uint64(self.mantissa)
#| if self.exponent < 0L {
#| value / pow10_fast_path(-self.exponent.to_int())
#| } else {
#| value * pow10_fast_path(self.exponent.to_int())
#| }
#| } else {
#| // disguised fast path
#| let shift = self.exponent - max_exponent_fast_path
#| let mantissa = match
#| checked_mul(self.mantissa, int_pow10[shift.to_int()]) {
#| Some(m) => m
#| None => return None
#| }
#| if mantissa > max_mantissa_fast_path {
#| return None
#| }
#| Double::convert_uint64(mantissa) *
#| pow10_fast_path(max_exponent_fast_path.to_int())
#| }
#| if self.negative {
#| value = -value
#| }
#| Some(value)
#| } else {
#| None
#| } }
),
),
"parse_digits": build(
(
#|fn parse_digits(s : @string.View, x : UInt64) -> (@string.View, UInt64, Int) { s.fold_digits(x, (digit, acc : UInt64) => acc * 10UL +
#| UInt64::extend_uint(digit.reinterpret_as_uint())) }
),
),
"parse_scientific": build(
(
#|fn parse_scientific(s : @string.View) -> (@string.View, Int64)? { // the first character is 'e'/'E' and scientific mode is enabled
#| let mut s = match s.step(1) {
#| Some(s) => s
#| None => return None
#| }
#| let exp_num = 0L
#| let mut neg_exp = false
#| if s is ['+' | '-' as ch, .. rest] {
#| neg_exp = ch == '-'
#| s = rest
#| }
#| if s is ['0'..='9', ..] {
#| let (s, exp_num, _) = s.fold_digits(exp_num, (digit, exp_num : Int64) => if exp_num <
#| 0x10000L {
#| 10L * exp_num + digit.to_int64() // no overflows here
#| } else {
#| exp_num
#| })
#| if neg_exp {
#| Some((s, -exp_num))
#| } else {
#| Some((s, exp_num))
#| }
#| } else {
#| None
#| } }
),
),
"parse_number": build(
(
#|fn parse_number(s : @string.View) -> (Number, Int)? { let mut s = s
#| let start = s
#| // handle optional +/- sign
#| let mut negative = false
#| if s is ['-', .. rest] {
#| negative = true
#| s = rest
#| } else if s is ['+', .. rest] {
#| s = rest
#| }
#| if s.is_empty() {
#| return None
#| }
#| // parse initial digits before dot
#| let (s, mantissa, consumed) = parse_digits(s, 0UL)
#| let mut mantissa = mantissa
#| let mut s = s
#| let mut n_digits = consumed
#| // handle dot with the following digits
#| let mut n_after_dot = 0
#| let mut exponent = 0L
#| if s is ['.', .. rest] {
#| s = rest
#| // TODO: optimization chance. In the original Rust implementation,
#| // the the digits are stored as consecutive bytes in the string.
#| // It directly reads 8 bytes to `u64`.
#| let (new_s, new_mantissa, consumed_digit) = parse_digits(s, mantissa)
#| s = new_s
#| mantissa = new_mantissa
#| n_after_dot = consumed_digit
#| exponent = -n_after_dot.to_int64()
#| }
#| n_digits += n_after_dot
#| if n_digits == 0 {
#| return None
#| }
#| // handle scientific format
#| let exp_number = 0L
#| if s is ['e' | 'E', ..] {
#| let (new_s, exp_number) = match parse_scientific(s) {
#| Some(res) => res
#| None => return None
#| }
#| s = new_s
#| exponent += exp_number
#| }
#| let len = start.length() - s.length()
#| // handle uncommon case with many digits
#| if n_digits <= 19 {
#| return Some(({ exponent, mantissa, negative, many_digits: false }, len))
#| }
#| n_digits -= 19
#| let mut many_digits = false
#| let mut p = start
#| while p is ['0' | '.' as ch, .. rest] {
#| n_digits -= (ch.to_int() - 46) / 2 // '0' = b'.' + 2
#| p = rest
#| }
#| let mut mantissa = mantissa
#| if n_digits > 0 {
#| // at this point we have more than 19 significant digits, let's try again
#| many_digits = true
#| mantissa = 0UL
#| let s = start
#| let (s, new_mantissa, consumed_digit) = try_parse_19digits(s, mantissa)
#| mantissa = new_mantissa
#| exponent = (if mantissa >= min_19digit_int {
#| consumed_digit // big int
#| } else {
#| let s = match s.step(1) {
#| Some(s) => s
#| None => return None
#| } // fractional component, skip the '.'
#| let (_, new_mantissa, consumed_digit) = try_parse_19digits(s, mantissa)
#| mantissa = new_mantissa
#| consumed_digit
#| }).to_int64()
#| exponent += exp_number
#| } // add back the explicit part
#| Some(({ exponent, mantissa, negative, many_digits }, len)) }
),
),
"parse_inf_nan": build(
(
#|fn parse_inf_nan(s : @string.View) -> (Double, Int)? { let mut s = s
#| let mut pos = true
#| let mut len = 0
#| if s is ['-' | '+' as ch, .. rest] {
#| pos = ch == '+'
#| s = rest
#| len += 1
#| }
#| if s is ['n' | 'N', 'a' | 'A', 'n' | 'N', ..] {
#| Some((@double.not_a_number, len + 3))
#| } else if s is ['i' | 'I', 'n' | 'N', 'f' | 'F', .. rest] {
#| len += 3
#| if rest is ['i' | 'I', 'n' | 'N', 'i' | 'I', 't' | 'T', 'y' | 'Y', ..] {
#| len += 5
#| }
#| if pos {
#| Some((@double.infinity, len))
#| } else {
#| Some((@double.neg_infinity, len))
#| }
#| } else {
#| None
#| } }
),
),
"checked_mul": build(
(
#|fn checked_mul(a : UInt64, b : UInt64) -> UInt64? { if a == 0UL || b == 0UL {
#| return Some(0UL)
#| }
#| if a == 1UL {
#| return Some(b)
#| }
#| if b == 1UL {
#| return Some(a)
#| }
#| // Can only multiply by 1 or 0, which is handled above.
#| if b.clz() == 0 || a.clz() == 0 {
#| return None
#| }
#| let quotient : UInt64 = @uint64.max_value / b
#| if a > quotient {
#| return None
#| }
#| Some(a * b) }
),
),
"range_err_str": (None, String("value out of range")),
"syntax_err_str": (None, String("invalid syntax")),
"base_err_str": (None, String("invalid base")),
"range_err": build(
(
#|fn[T] range_err() -> T raise StrConvError { raise StrConvError(range_err_str) }
),
),
"syntax_err": build(
(
#|fn[T] syntax_err() -> T raise StrConvError { raise StrConvError(syntax_err_str) }
),
),
"base_err": build(
(
#|fn[T] base_err() -> T raise StrConvError { raise StrConvError(base_err_str) }
),
),
"max_shift": (None, Int(59)),
"powtab": (None, String("[")),
"new_priv": build(
(
#|fn Decimal::new_priv() -> Decimal { {
#| digits: FixedArray::make(800, Byte::default()),
#| digits_num: 0,
#| decimal_point: 0,
#| negative: false,
#| truncated: false,
#| } }
),
),
"from_int64_priv": build(
(
#|fn Decimal::from_int64_priv(v : Int64) -> Decimal { let d = Decimal::new_priv()
#| d.assign(v)
#| d }
),
),
"parse_decimal_priv": build(
(
#|fn parse_decimal_priv(str : @string.View) -> Decimal raise StrConvError { parse_decimal_from_view(str) }
),
),
"parse_decimal_from_view": build(
(
#|fn parse_decimal_from_view(str : @string.View) -> Decimal raise StrConvError { let d = Decimal::new_priv()
#| let mut has_dp = false
#| let mut has_digits = false
#| // read sign
#| let rest = match str {
#| ['-', .. rest] => {
#| d.negative = true
#| rest
#| }
#| ['+', .. rest] => rest
#| _ => str
#| }
#| // read digits
#| let rest = loop rest {
#| ['_', .. rest] => continue rest
#| ['.', .. rest] => {
#| guard !has_dp else { syntax_err() }
#| has_dp = true
#| d.decimal_point = d.digits_num
#| continue rest
#| }
#| ['0'..='9' as digit, .. rest] => {
#| has_digits = true
#| if digit == '0' && d.digits_num == 0 {
#| // ignore leading zeros
#| d.decimal_point -= 1
#| continue rest
#| }
#| if d.digits_num < d.digits.length() {
#| d.digits[d.digits_num] = (digit.to_int() - '0').to_byte()
#| d.digits_num += 1
#| } else if digit != '0' {
#| d.truncated = true
#| }
#| continue rest
#| }
#| rest => rest
#| }
#| guard has_digits else { syntax_err() }
#| if !has_dp {
#| d.decimal_point = d.digits_num
#| }
#| // read exponent part
#| let rest = match rest {
#| ['e' | 'E', .. rest] => {
#| let mut exp_sign = 1
#| let rest = match rest {
#| ['+', .. rest] => rest
#| ['-', .. rest] => {
#| exp_sign = -1
#| rest
#| }
#| rest => rest
#| }
#| guard rest is ['0'..='9', ..] else { syntax_err() }
#| let mut exp = 0
#| let rest = loop rest {
#| ['_', .. rest] => continue rest
#| ['0'..='9' as digit, .. rest] => {
#| exp = exp * 10 + (digit.to_int() - '0')
#| continue rest
#| }
#| rest => rest
#| }
#| d.decimal_point += exp_sign * exp
#| rest
#| }
#| rest => rest
#| }
#| // finish
#| guard rest is [] else { syntax_err() }
#| d.trim()
#| d }
),
),
"to_double_priv": build(
(
#|fn to_double_priv(self : Decimal) -> Double raise StrConvError { let mut exponent = 0
#| let mut mantissa = 0L
#| // check the underflow and overflow
#| // Double: 1.79769e+308 (10^308) - 2.22507e-308 (10^-308)
#| if self.digits_num == 0 || self.decimal_point < -330 {
#| // zero
#| mantissa = 0
#| exponent = double_info.bias
#| let bits = assemble_bits(mantissa, exponent, self.negative)
#| return bits.reinterpret_as_double()
#| }
#| if self.decimal_point > 310 {
#| // overflow
#| range_err()
#| }
#| // scale by powers of 2 until in range [0.5 .. 1]
#| // right shift
#| while self.decimal_point > 0 {
#| let mut n = 0
#| if self.decimal_point >= powtab.length() {
#| n = 60
#| } else {
#| n = powtab[self.decimal_point]
#| }
#| self.shift_priv(-n)
#| exponent += n
#| }
#| // left shift
#| while self.decimal_point < 0 ||
#| (self.decimal_point == 0 && self.digits[0].to_int() < 5) {
#| let mut n = 0
#| if -self.decimal_point >= powtab.length() {
#| n = 60
#| } else {
#| n = powtab[-self.decimal_point]
#| }
#| self.shift_priv(n)
#| exponent -= n
#| }
#| // normalized floating point range is [1, 2), current [0.5, 1)
#| // should decrease the exponent by 1
#| exponent -= 1
#| // minimum representable exponent is bias + 1
#| // if the exponent is smaller, move it up and shift decimal accordingly
#| if exponent < double_info.bias + 1 {
#| let n = double_info.bias + 1 - exponent
#| self.shift_priv(-n)
#| exponent += n
#| }
#| if exponent - double_info.bias >= (1 << double_info.exponent_bits) - 1 {
#| // overflow
#| range_err()
#| }
#| // multiply by (2 ** precision) and round to get mantissa
#| // extract mantissa_bits + 1 bits
#| self.shift_priv(double_info.mantissa_bits + 1)
#| mantissa = self.rounded_integer()
#| // rounding might have added a bit, shift down.
#| if mantissa == 2L << double_info.mantissa_bits {
#| mantissa = mantissa << 1
#| exponent += 1
#| if exponent - double_info.bias >= (1 << double_info.exponent_bits) - 1 {
#| // overflow
#| range_err()
#| }
#| }
#| // denormalized
#| if (mantissa & (1L << double_info.mantissa_bits)) == 0L {
#| exponent = double_info.bias
#| }
#| // combining the 52 mantissa bits with the 11 exponent bits and 1 sign bit
#| let bits = assemble_bits(mantissa, exponent, self.negative)
#| bits.reinterpret_as_double() }
),
),
"shift_priv": build(
(
#|fn shift_priv(self : Decimal, s : Int) -> Unit { if self.digits_num == 0 {
#| return
#| }
#| let mut s = s
#| if s > 0 {
#| while s > max_shift {
#| self.left_shift(max_shift)
#| s -= max_shift
#| }
#| self.left_shift(s)
#| }
#| if s < 0 {
#| while s < -max_shift {
#| self.right_shift(max_shift)
#| s += max_shift
#| }
#| self.right_shift(-s)
#| } }
),
),
"assemble_bits": build(
(
#|fn assemble_bits(mantissa : Int64, exponent : Int, negative : Bool) -> Int64 { let biased_exp = exponent - double_info.bias
#| // set the mantissa bits
#| let mut bits = mantissa & ((1L << double_info.mantissa_bits) - 1L)
#| // set the exponent bits
#| let exp_bits = (biased_exp & ((1 << double_info.exponent_bits) - 1)).to_int64()
#| bits = bits | (exp_bits << double_info.mantissa_bits)
#| // set the sign bit
#| if negative {
#| bits = bits | (1L << double_info.mantissa_bits << double_info.exponent_bits)
#| }
#| bits }
),
),
"rounded_integer": build(
(
#|fn rounded_integer(self : Decimal) -> Int64 { if self.decimal_point > 20 {
#| return 0xFFFFFFFFFFFFFFFFL
#| }
#| let mut n = 0L
#| let mut i = 0
#| while i < self.decimal_point && i < self.digits_num {
#| n = n * 10L + self.digits[i].to_int64()
#| i += 1
#| }
#| while i < self.decimal_point {
#| n *= 10L
#| i += 1
#| }
#| if self.should_round_up(self.decimal_point) {
#| n += 1L
#| }
#| n }
),
),
"should_round_up": build(
(
#|fn should_round_up(self : Decimal, d : Int) -> Bool { if d < 0 || d >= self.digits_num {
#| return false
#| }
#| if self.digits[d].to_int() == 5 && d + 1 == self.digits_num {
#| // half-way between two integers
#| // if truncated, the real value is higher than stored value, round up.
#| if self.truncated {
#| return true
#| }
#| // round to even
#| return d > 0 && self.digits[d - 1].to_int() % 2 != 0
#| }
#| // normal case
#| self.digits[d].to_int() >= 5 }
),
),
"assign": build(
(
#|fn assign(self : Decimal, v : Int64) -> Unit { let buf = FixedArray::make(24, Byte::default())
#| // write value to buf
#| let mut n = 0
#| let mut v = v
#| while v > 0 {
#| let v1 = v / 10
#| buf[n] = (v - v1 * 10).to_byte()
#| n += 1
#| v = v1
#| }
#| // reverse the buf
#| self.digits_num = 0
#| for i = n - 1; i >= 0; i = i - 1 {
#| self.digits[self.digits_num] = buf[i]
#| self.digits_num += 1
#| }
#| self.decimal_point = self.digits_num
#| self.trim() }
),
),
"right_shift": build(
(
#|fn right_shift(self : Decimal, s : Int) -> Unit { let mut read_index = 0
#| let mut write_index = 0
#| // read enough leading digits to start a shift
#| let mut acc = 0UL
#| while acc >> s == 0 {
#| if read_index >= self.digits_num {
#| while acc >> s == 0 {
#| acc *= 10
#| read_index += 1
#| }
#| break
#| }
#| let d = self.digits[read_index]
#| acc = acc * 10 + d.to_int64().reinterpret_as_uint64()
#| read_index += 1
#| }
#| self.decimal_point -= read_index - 1
#| // read a digit and output a shifted digit
#| let mask = (1UL << s) - 1
#| while read_index < self.digits_num {
#| // output (acc >> s)
#| let out = acc >> s
#| self.digits[write_index] = out.to_byte()
#| write_index += 1
#| // contract
#| acc = acc & mask
#| // expand
#| let d = self.digits[read_index]
#| acc = acc * 10 + d.to_int64().reinterpret_as_uint64()
#| read_index += 1
#| }
#| // output extra digits
#| while acc > 0 {
#| let out = acc >> s
#| if write_index < self.digits.length() {
#| self.digits[write_index] = out.to_byte()
#| write_index += 1
#| } else if out > 0 {
#| self.truncated = true
#| }
#| acc = acc & mask
#| acc = acc * 10
#| }
#| // update and trim
#| self.digits_num = write_index
#| self.trim() }
),
),
"left_shift_cheats": (None, String("[")),
"new_digits": build(
(
#|fn new_digits(self : Decimal, s : Int) -> Int { let new_digits = left_shift_cheats[s].0
#| let cheat_num = left_shift_cheats[s].1
#| // check if the leading digits lexicographically less than cheats num.
#| let mut less = false
#| for i in 0..= self.digits_num {
#| less = true
#| break
#| }
#| let d = cheat_num.unsafe_charcode_at(i) - '0'
#| if self.digits[i].to_int() != d {
#| less = self.digits[i].to_int() < d
#| break
#| }
#| }
#| if less {
#| new_digits - 1
#| } else {
#| new_digits
#| } }
),
),
"left_shift": build(
(
#|fn left_shift(self : Decimal, s : Int) -> Unit { let new_digits = self.new_digits(s)
#| // from right to left
#| let mut read_index = self.digits_num
#| let mut write_index = self.digits_num + new_digits
#| // read a digit and output a shifted digit
#| let mut acc = 0L
#| read_index -= 1
#| while read_index >= 0 {
#| let d = self.digits[read_index].to_int64()
#| acc += d << s
#| let quo = acc / 10L
#| let rem = (acc - quo * 10L).to_int()
#| write_index -= 1
#| if write_index < self.digits.length() {
#| self.digits[write_index] = rem.to_byte()
#| } else if rem != 0 {
#| self.truncated = true
#| }
#| acc = quo
#| read_index -= 1
#| }
#| // output extra digits
#| while acc > 0L {
#| let quo = acc / 10L
#| let rem = (acc - 10L * quo).to_int()
#| write_index -= 1
#| if write_index < self.digits.length() {
#| self.digits[write_index] = rem.to_byte()
#| } else if rem != 0 {
#| self.truncated = true
#| }
#| acc = quo
#| }
#| // update and trim
#| self.digits_num += new_digits
#| if self.digits_num > self.digits.length() {
#| self.digits_num = self.digits.length()
#| }
#| self.decimal_point += new_digits
#| self.trim() }
),
),
"trim": build(
(
#|fn trim(self : Decimal) -> Unit { while self.digits_num > 0 && self.digits[self.digits_num - 1] == 0 {
#| self.digits_num -= 1
#| }
#| if self.digits_num == 0 {
#| self.decimal_point = 0
#| } }
),
),
"to_string": build(
(
#|fn Decimal::to_string(self : Decimal) -> String { Show::to_string(self) }
),
),
"new": build(
(
#|pub fn Decimal::new() -> Decimal { Decimal::new_priv() }
),
),
"from_int64": build(
(
#|pub fn Decimal::from_int64(v : Int64) -> Decimal { Decimal::from_int64_priv(v) }
),
),
"parse_decimal": build(
(
#|pub fn parse_decimal(str : @string.View) -> Decimal raise StrConvError { parse_decimal_from_view(str) }
),
),
"parse_decimal": build(
(
#|pub fn Decimal::parse_decimal(str : @string.View) -> Decimal raise StrConvError { parse_decimal_from_view(str) }
),
),
"to_double": build(
(
#|pub fn to_double(self : Decimal) -> Double raise StrConvError { self.to_double_priv() }
),
),
"shift": build(
(
#|pub fn shift(self : Decimal, s : Int) -> Unit { self.shift_priv(s) }
),
),
"parse_int": build(
(
#|pub fn parse_int(str : @string.View, base~ : Int = 0) -> Int raise StrConvError { let n = parse_int64(str, base~)
#| if n < INT_MIN.to_int64() || n > INT_MAX.to_int64() {
#| range_err()
#| }
#| n.to_int() }
),
),
"check_underscore": build(
(
#|fn check_underscore(str : @string.View) -> Bool { // skip the sign
#| let rest = match str {
#| ['+' | '-', .. rest] => rest
#| rest => rest
#| // CR: the type maybe a bit confusing?
#| }
#| // base prefix
#| let (rest, allow_underscore, hex) = match rest {
#| ['0', 'x' | 'X', .. rest] => (rest, true, true)
#| ['0', 'o' | 'O', .. rest] => (rest, true, false)
#| ['0', 'b' | 'B', .. rest] => (rest, true, false)
#| rest => (rest, false, false)
#| }
#| // 'e' and 'E' are valid hex digits
#| // but are not treated as digits in decimal strings since they're used for scientific notation
#| fn is_digit(c : Char) -> Bool {
#| c is ('0'..='9') || (hex && c is ('a'..='f' | 'A'..='F'))
#| }
#| // Track whether the previous character was an underscore
#| let follow_underscore = false
#| loop (rest, allow_underscore, follow_underscore) {
#| // Empty string is valid
#| ([], _, _) => true
#| // String ending with underscore is invalid
#| (['_'], _, _) => false
#| // Underscore not allowed in current position (e.g., between non-digits)
#| (['_', ..], false, _) => false
#| // Valid underscore - continue but mark that next char must be a digit
#| (['_', .. rest], true, _) => continue (rest, false, true)
#| // Handle non-underscore character
#| ([c, .. rest], _, follow_underscore) =>
#| if is_digit(c) {
#| // Digit found - allow underscore in next position
#| continue (rest, true, false)
#| } else if follow_underscore {
#| // Non-digit found after underscore - invalid
#| false
#| } else {
#| // Non-digit found (not after underscore) - continue but don't allow underscores
#| continue (rest, false, false)
#| }
#| } }
),
),
"determine_base": build(
(
#|fn determine_base(s : String) -> Int { match s {
#| ['0', 'x' | 'X', ..] => 16
#| ['0', 'o' | 'O', ..] => 8
#| ['0', 'b' | 'B', ..] => 2
#| _ => 10
#| } }
),
),
"overflow_threshold": build(
(
#|fn overflow_threshold(base : Int, neg : Bool) -> Int64 { if !neg {
#| if base == 10 {
#| INT64_MAX / 10L + 1L
#| } else if base == 16 {
#| INT64_MAX / 16L + 1L
#| } else {
#| INT64_MAX / base.to_int64() + 1L
#| }
#| } else if base == 10 {
#| INT64_MIN / 10L
#| } else if base == 16 {
#| INT64_MIN / 16L
#| } else {
#| INT64_MIN / base.to_int64()
#| } }
),
),
}
},
)
///|
let moonbitlang_core_string_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/string",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/char": moonbitlang_core_char_module,
},
fn(_env, build) {
{
"concat": build(
(
#|pub fn String::concat(self : Array[String], separator~ : String = \"\") -> String { concat(self, separator~) }
),
),
"concat": build(
(
#|pub fn concat(strings : Array[String], separator~ : String = \"\") -> String { match strings {
#| [] => \"\"
#| [hd, .. tl] => {
#| let mut size_hint = hd.length()
#| for s in tl {
#| size_hint += s.length() + separator.length()
#| }
#| size_hint = size_hint << 1
#| let buf = StringBuilder::new(size_hint~)
#| buf.write_string(hd)
#| if separator == \"\" {
#| for s in tl {
#| buf.write_string(s)
#| }
#| } else {
#| for s in tl {
#| buf.write_string(separator)
#| buf.write_string(s)
#| }
#| }
#| buf.to_string()
#| }
#| } }
),
),
"index_of": build(
(
#|pub fn index_of(self : String, str : String, from~ : Int = 0) -> Int { if from <= 0 {
#| if self.find(str.view()) is Some(idx) {
#| idx
#| } else {
#| -1
#| }
#| } else if from > self.length() {
#| if str.length() == 0 {
#| self.length()
#| } else {
#| -1
#| }
#| } else if self.view(start_offset=from).find(str.view()) is Some(idx) {
#| idx + from
#| } else {
#| -1
#| } }
),
),
"last_index_of": build(
(
#|pub fn last_index_of(self : String, str : String, from? : Int) -> Int { let from = if from is Some(f) { f } else { self.length() }
#| if from >= self.length() {
#| if self.rev_find(str.view()) is Some(idx) {
#| idx
#| } else {
#| -1
#| }
#| } else if from < 0 {
#| if str.length() == 0 {
#| self.length()
#| } else {
#| -1
#| }
#| } else if self.view(end_offset=from).rev_find(str.view()) is Some(idx) {
#| idx
#| } else {
#| -1
#| } }
),
),
"charcode_at": build(
(
#|pub fn View::charcode_at(self : View, index : Int) -> Int { guard index >= 0 && index < self.length() else {
#| abort(\"Index out of bounds\")
#| }
#| self.str().unsafe_charcode_at(self.start() + index) }
),
),
"char_at": build(
(
#|pub fn View::char_at(self : View, index : Int) -> Char { self.get_char(index).unwrap() }
),
),
"char_at": build(
(
#|pub fn String::char_at(self : String, offset : Int) -> Char { match self.get_char(offset) {
#| Some(c) => c
#| None => '�'
#| } }
),
),
"code_point_of_surrogate_pair": build(
(
#|fn code_point_of_surrogate_pair(leading : Int, trailing : Int) -> Char { ((leading - 0xD800) * 0x400 + trailing - 0xDC00 + 0x10000).unsafe_to_char() }
),
),
"find": build(
(
#|pub fn View::find(self : View, str : View) -> Int? { if str.length() <= 4 {
#| brute_force_find(self, str)
#| } else {
#| boyer_moore_horspool_find(self, str)
#| }
#| // TODO: When the pattern string is long (>= 256),
#| // consider using Two-Way algorithm to ensure linear time complexity. }
),
),
"brute_force_find": build(
(
#|fn brute_force_find(haystack : View, needle : View) -> Int? { let haystack_len = haystack.length()
#| let needle_len = needle.length()
#| guard needle_len > 0 else { return Some(0) }
#| guard haystack_len >= needle_len else { return None }
#| let needle_first = needle.unsafe_charcode_at(0)
#| let forward_len = haystack_len - needle_len
#| let mut i = 0
#| while i <= forward_len {
#| // Skip positions where first charcode doesn't match
#| while i <= forward_len && haystack.unsafe_charcode_at(i) != needle_first {
#| i += 1
#| }
#| if i <= forward_len {
#| // Check remaining charcodes for full match
#| for j in 1.. Int? { let haystack_len = haystack.length()
#| let needle_len = needle.length()
#| guard needle_len > 0 else { return Some(0) }
#| guard haystack_len >= needle_len else { return None }
#| // Build skip table
#| let skip_table = FixedArray::make(1 << 8, needle_len)
#| for i in 0..<(needle_len - 1) {
#| skip_table[needle.unsafe_charcode_at(i) & 0xFF] = needle_len - 1 - i
#| }
#| for i = 0
#| i <= haystack_len - needle_len
#| i = i + skip_table[haystack.unsafe_charcode_at(i + needle_len - 1) & 0xFF] {
#| // Check all charcodes for match at current position
#| for j in 0..=(needle_len - 1) {
#| if haystack.unsafe_charcode_at(i + j) != needle.unsafe_charcode_at(j) {
#| break
#| }
#| } else {
#| return Some(i)
#| }
#| }
#| None }
),
),
"find": build(
(
#|pub fn String::find(self : String, str : View) -> Int? { self[:].find(str) }
),
),
"find_by": build(
(
#|pub fn View::find_by(self : View, pred : (Char) -> Bool) -> Int? { for i, c in self {
#| if pred(c) {
#| return Some(i)
#| }
#| }
#| None }
),
),
"find_by": build(
(
#|pub fn String::find_by(self : String, pred : (Char) -> Bool) -> Int? { self[:].find_by(pred) }
),
),
"rev_find": build(
(
#|pub fn View::rev_find(self : View, str : View) -> Int? { if str.length() <= 4 {
#| brute_force_rev_find(self, str)
#| } else {
#| boyer_moore_horspool_rev_find(self, str)
#| }
#| // TODO: When the pattern string is long (>= 256),
#| // consider using Two-Way algorithm to ensure linear time complexity. }
),
),
"brute_force_rev_find": build(
(
#|fn brute_force_rev_find(haystack : View, needle : View) -> Int? { let haystack_len = haystack.length()
#| let needle_len = needle.length()
#| guard needle_len > 0 else { return Some(haystack_len) }
#| guard haystack_len >= needle_len else { return None }
#| let needle_first = needle.unsafe_charcode_at(0)
#| let mut i = haystack_len - needle_len
#| while i >= 0 {
#| // Skip positions where first charcode doesn't match
#| while i >= 0 && haystack.unsafe_charcode_at(i) != needle_first {
#| i -= 1
#| }
#| if i >= 0 {
#| // Check remaining charcodes for full match
#| for j in 1.. Int? { let haystack_len = haystack.length()
#| let needle_len = needle.length()
#| guard needle_len > 0 else { return Some(haystack_len) }
#| guard haystack_len >= needle_len else { return None }
#| let skip_table = FixedArray::make(1 << 8, needle_len)
#| for i = needle_len - 1; i > 0; i = i - 1 {
#| skip_table[needle.unsafe_charcode_at(i) & 0xFF] = i
#| }
#| for i = haystack_len - needle_len
#| i >= 0
#| i = i - skip_table[haystack.unsafe_charcode_at(i) & 0xFF] {
#| // Check all charcodes for match at current position
#| for j in 0.. Int? { self[:].rev_find(str) }
),
),
"has_suffix": build(
(
#|pub fn View::has_suffix(self : View, str : View) -> Bool { self.rev_find(str) is Some(i) && i == self.length() - str.length() }
),
),
"has_suffix": build(
(
#|pub fn String::has_suffix(self : String, str : View) -> Bool { self[:].has_suffix(str) }
),
),
"has_prefix": build(
(
#|pub fn View::has_prefix(self : View, str : View) -> Bool { self.find(str) is Some(i) && i == 0 }
),
),
"has_prefix": build(
(
#|pub fn String::has_prefix(self : String, str : View) -> Bool { self[:].has_prefix(str) }
),
),
"strip_suffix": build(
(
#|pub fn strip_suffix(self : String, suffix : View) -> View? { if self.has_suffix(suffix) {
#| Some(self.charcodes(end=self.length() - suffix.length()))
#| } else {
#| None
#| } }
),
),
"strip_prefix": build(
(
#|pub fn strip_prefix(self : String, prefix : View) -> View? { if self.has_prefix(prefix) {
#| Some(self.charcodes(start=prefix.length()))
#| } else {
#| None
#| } }
),
),
"strip_prefix": build(
(
#|pub fn View::strip_prefix(self : View, prefix : View) -> View? { if self.has_prefix(prefix) {
#| Some(self.view(start_offset=prefix.length()))
#| } else {
#| None
#| } }
),
),
"strip_suffix": build(
(
#|pub fn View::strip_suffix(self : View, suffix : View) -> View? { if self.has_suffix(suffix) {
#| Some(self.view(end_offset=self.length() - suffix.length()))
#| } else {
#| None
#| } }
),
),
"to_array": build(
(
#|pub fn View::to_array(self : View) -> Array[Char] { self
#| .iter()
#| .fold(init=Array::new(capacity=self.length()), (rv, c) => {
#| rv.push(c)
#| rv
#| }) }
),
),
"to_bytes": build(
(
#|pub fn View::to_bytes(self : View) -> Bytes { let array = FixedArray::make(self.length() * 2, Byte::default())
#| array.blit_from_string(0, self.data(), self.start_offset(), self.length())
#| array |> unsafe_to_bytes }
),
),
"contains": build(
(
#|pub fn View::contains(self : View, str : View) -> Bool { self.find(str) is Some(_) }
),
),
"contains": build(
(
#|pub fn contains(self : String, str : View) -> Bool { self[:].contains(str) }
),
),
"contains_char": build(
(
#|pub fn View::contains_char(self : View, c : Char) -> Bool { let len = self.length()
#| // Check empty
#| guard len > 0 else { return false }
#| let c = c.to_int()
#| if c <= 0xFFFF {
#| // Search BMP
#| for i in 0..= 2 else { return false }
#| // Calc surrogate pair
#| let adj = c - 0x10000
#| let high = 0xD800 + (adj >> 10)
#| let low = 0xDC00 + (adj & 0x3FF)
#| // Search surrogate pair
#| let mut i = 0
#| while i < len - 1 {
#| if self.unsafe_charcode_at(i) == high {
#| i += 1
#| if self.unsafe_charcode_at(i) == low {
#| return true
#| }
#| }
#| i += 1
#| }
#| }
#| false }
),
),
"contains_char": build(
(
#|pub fn contains_char(self : String, c : Char) -> Bool { self[:].contains_char(c) }
),
),
"trim_start": build(
(
#|pub fn View::trim_start(self : View, char_set : View) -> View { loop self {
#| [] as v => v
#| [c, .. rest] as v =>
#| if char_set.contains_char(c) {
#| continue rest
#| } else {
#| v
#| }
#| } }
),
),
"trim_start": build(
(
#|pub fn trim_start(self : String, char_set : View) -> View { self[:].trim_start(char_set) }
),
),
"trim_end": build(
(
#|pub fn View::trim_end(self : View, char_set : View) -> View { loop self {
#| [] as v => v
#| [.. rest, c] as v =>
#| if char_set.contains_char(c) {
#| continue rest
#| } else {
#| v
#| }
#| } }
),
),
"trim_end": build(
(
#|pub fn trim_end(self : String, char_set : View) -> View { self[:].trim_end(char_set) }
),
),
"trim": build(
(
#|pub fn View::trim(self : View, char_set : View) -> View { self.trim_start(char_set).trim_end(char_set) }
),
),
"trim": build(
(
#|pub fn trim(self : String, char_set : View) -> View { self[:].trim(char_set) }
),
),
"trim_space": build(
(
#|pub fn View::trim_space(self : View) -> View { self.trim(\" \\n\\r\\t\") }
),
),
"trim_space": build(
(
#|pub fn trim_space(self : String) -> View { self[:].trim_space() }
),
),
"is_empty": build(
(
#|pub fn View::is_empty(self : View) -> Bool { self.length() == 0 }
),
),
"is_empty": build(
(
#|pub fn is_empty(self : String) -> Bool { self == \"\" }
),
),
"is_blank": build(
(
#|pub fn View::is_blank(self : View) -> Bool { self.trim_space().is_empty() }
),
),
"is_blank": build(
(
#|pub fn is_blank(self : String) -> Bool { self[:].is_blank() }
),
),
"repeat": build(
(
#|pub fn View::repeat(self : View, n : Int) -> View { match n {
#| _..=0 => \"\"
#| 1 => self
#| _ => {
#| let len = self.length()
#| let buf = StringBuilder::new(size_hint=len * n)
#| let str = self.to_string()
#| for _ in 0.. String { match n {
#| _..=0 => \"\"
#| 1 => self
#| _ => {
#| let len = self.length()
#| let buf = StringBuilder::new(size_hint=len * n)
#| let str = self.to_string()
#| for _ in 0.. String { let buf = StringBuilder::new(size_hint=self.length())
#| for c in self.rev_iter() {
#| buf.write_char(c)
#| }
#| buf.to_string() }
),
),
"rev": build(
(
#|pub fn rev(self : String) -> String { self[:].rev() }
),
),
"split": build(
(
#|pub fn View::split(self : View, sep : View) -> Iter[View] { let sep_len = sep.length()
#| if sep_len == 0 {
#| return self.iter().map(c => c.to_string().view())
#| }
#| Iter::new(yield_ => {
#| let mut view = self
#| while view.find(sep) is Some(end) {
#| guard yield_(view.view(end_offset=end)) is IterContinue else {
#| break IterEnd
#| }
#| view = view.view(start_offset=end + sep_len)
#| } else {
#| yield_(view)
#| }
#| }) }
),
),
"split": build(
(
#|pub fn split(self : String, sep : View) -> Iter[View] { self[:].split(sep) }
),
),
"replace": build(
(
#|pub fn View::replace(self : View, old~ : View, new~ : View) -> View { match self.find(old) {
#| Some(end) =>
#| [
#| ..self.view(end_offset=end),
#| ..new,
#| ..self.view(start_offset=end + old.length()),
#| ]
#| None => self
#| } }
),
),
"replace": build(
(
#|pub fn replace(self : String, old~ : View, new~ : View) -> String { match self.find(old) {
#| Some(end) =>
#| [
#| ..self.view(end_offset=end),
#| ..new,
#| ..self.view(start_offset=end + old.length()),
#| ]
#| None => self
#| } }
),
),
"replace_all": build(
(
#|pub fn View::replace_all(self : View, old~ : View, new~ : View) -> View { let len = self.length()
#| let buf = StringBuilder::new(size_hint=len)
#| let old_len = old.length()
#| let new = new.to_string()
#| // use write_substring to avoid intermediate allocations
#| if old_len == 0 {
#| buf.write_string(new)
#| for c in self {
#| buf.write_char(c)
#| buf.write_string(new)
#| }
#| buf.to_string()
#| } else {
#| let first_end = self.find(old)
#| if first_end is Some(end) {
#| for view = self, end = end {
#| let seg = view.view(end_offset=end)
#| buf.write_substring(seg.data(), seg.start_offset(), seg.length())
#| buf.write_string(new)
#| // check if there is no more characters after the last occurrence of `old`
#| guard end + old_len <= len else { break }
#| let next_view = view.view(start_offset=end + old_len)
#| guard next_view.find(old) is Some(next_end) else {
#| buf.write_substring(
#| next_view.data(),
#| next_view.start_offset(),
#| next_view.length(),
#| )
#| break
#| }
#| continue next_view, next_end
#| }
#| buf.to_string()
#| } else {
#| self
#| }
#| } }
),
),
"replace_all": build(
(
#|pub fn replace_all(self : String, old~ : View, new~ : View) -> String { let len = self.length()
#| let buf = StringBuilder::new(size_hint=len)
#| let old_len = old.length()
#| let new = new.to_string()
#| // use write_substring to avoid intermediate allocations
#| if old_len == 0 {
#| buf.write_string(new)
#| for c in self {
#| buf.write_char(c)
#| buf.write_string(new)
#| }
#| buf.to_string()
#| } else {
#| let first_end = self.find(old)
#| if first_end is Some(end) {
#| for view = self[:], end = end {
#| let seg = view.view(end_offset=end)
#| buf.write_substring(seg.data(), seg.start_offset(), seg.length())
#| buf.write_string(new)
#| // check if there is no more characters after the last occurrence of `old`
#| guard end + old_len <= len else { break }
#| let next_view = view.view(start_offset=end + old_len)
#| guard next_view.find(old) is Some(next_end) else {
#| buf.write_substring(
#| next_view.data(),
#| next_view.start_offset(),
#| next_view.length(),
#| )
#| break
#| }
#| continue next_view, next_end
#| }
#| buf.to_string()
#| } else {
#| self
#| }
#| } }
),
),
"to_lower": build(
(
#|pub fn View::to_lower(self : View) -> View { // TODO: deal with non-ascii characters
#| guard self.find_by(x => x.is_ascii_uppercase()) is Some(idx) else {
#| return self
#| }
#| let buf = StringBuilder::new(size_hint=self.length())
#| let head = self.view(end_offset=idx)
#| buf.write_substring(head.data(), head.start_offset(), head.length())
#| for c in self.view(start_offset=idx) {
#| if c.is_ascii_uppercase() {
#| // 'A' is 65 in ASCII, 'a' is 97, the difference is 32
#| buf.write_char((c.to_int() + 32).unsafe_to_char())
#| } else {
#| buf.write_char(c)
#| }
#| }
#| buf.to_string() }
),
),
"to_lower": build(
(
#|pub fn to_lower(self : String) -> String { // TODO: deal with non-ascii characters
#| guard self.find_by(x => x.is_ascii_uppercase()) is Some(idx) else {
#| return self
#| }
#| let buf = StringBuilder::new(size_hint=self.length())
#| let head = self.view(end_offset=idx)
#| buf.write_substring(head.data(), head.start_offset(), head.length())
#| for c in self.view(start_offset=idx) {
#| if c.is_ascii_uppercase() {
#| // 'A' is 65 in ASCII, 'a' is 97, the difference is 32
#| buf.write_char((c.to_int() + 32).unsafe_to_char())
#| } else {
#| buf.write_char(c)
#| }
#| }
#| buf.to_string() }
),
),
"to_upper": build(
(
#|pub fn View::to_upper(self : View) -> View { // TODO: deal with non-ascii characters
#| guard self.find_by(_.is_ascii_lowercase()) is Some(idx) else { return self }
#| let buf = StringBuilder::new(size_hint=self.length())
#| let head = self.view(end_offset=idx)
#| buf.write_substring(head.data(), head.start_offset(), head.length())
#| for c in self.view(start_offset=idx) {
#| if c.is_ascii_lowercase() {
#| buf.write_char((c.to_int() - 32).unsafe_to_char())
#| } else {
#| buf.write_char(c)
#| }
#| }
#| buf.to_string() }
),
),
"to_upper": build(
(
#|pub fn to_upper(self : String) -> String { // TODO: deal with non-ascii characters
#| guard self.find_by(_.is_ascii_lowercase()) is Some(idx) else { return self }
#| let buf = StringBuilder::new(size_hint=self.length())
#| let head = self.view(end_offset=idx)
#| buf.write_substring(head.data(), head.start_offset(), head.length())
#| for c in self.view(start_offset=idx) {
#| if c.is_ascii_lowercase() {
#| buf.write_char((c.to_int() - 32).unsafe_to_char())
#| } else {
#| buf.write_char(c)
#| }
#| }
#| buf.to_string() }
),
),
"fold": build(
(
#|pub fn[A] View::fold(self : View, init~ : A, f : (A, Char) -> A) -> A { let mut rv = init
#| for c in self {
#| rv = f(rv, c)
#| }
#| rv }
),
),
"fold": build(
(
#|pub fn[A] fold(self : String, init~ : A, f : (A, Char) -> A) -> A { self[:].fold(init~, f) }
),
),
"rev_fold": build(
(
#|pub fn[A] View::rev_fold(self : View, init~ : A, f : (A, Char) -> A) -> A { let mut rv = init
#| for c in self.rev_iter() {
#| rv = f(rv, c)
#| }
#| rv }
),
),
"rev_fold": build(
(
#|pub fn[A] rev_fold(self : String, init~ : A, f : (A, Char) -> A) -> A { self[:].rev_fold(init~, f) }
),
),
"get": build(
(
#|pub fn String::get(self : String, idx : Int) -> Int? { guard idx >= 0 && idx < self.length() else { return None }
#| Some(self.unsafe_charcode_at(idx)) }
),
),
"get": build(
(
#|pub fn View::get(self : View, idx : Int) -> Int? { guard idx >= 0 && idx < self.length() else { return None }
#| Some(self.unsafe_charcode_at(idx)) }
),
),
"get_char": build(
(
#|pub fn String::get_char(self : String, idx : Int) -> Char? { guard idx >= 0 && idx < self.length() else { return None }
#| let c = self.unsafe_charcode_at(idx)
#| if c.is_leading_surrogate() {
#| guard idx + 1 < self.length() else { return None }
#| let next = self.unsafe_charcode_at(idx + 1)
#| if next.is_trailing_surrogate() {
#| Some(code_point_of_surrogate_pair(c, next))
#| } else {
#| None
#| }
#| } else if c.is_trailing_surrogate() {
#| None
#| } else {
#| Some(c.unsafe_to_char())
#| } }
),
),
"get_char": build(
(
#|pub fn View::get_char(self : View, idx : Int) -> Char? { guard idx >= 0 && idx < self.length() else { return None }
#| let c = self.unsafe_charcode_at(idx)
#| if c.is_leading_surrogate() {
#| guard idx + 1 < self.length() else { return None }
#| let next = self.unsafe_charcode_at(idx + 1)
#| if next.is_trailing_surrogate() {
#| Some(code_point_of_surrogate_pair(c, next))
#| } else {
#| None
#| }
#| } else if c.is_trailing_surrogate() {
#| None
#| } else {
#| Some(c.unsafe_to_char())
#| } }
),
),
"from_array": build(
(
#|pub fn String::from_array(chars : Array[Char]) -> String { let buf = StringBuilder::new(size_hint=chars.length() * 4)
#| for c in chars {
#| buf.write_char(c)
#| }
#| buf.to_string() }
),
),
"from_array": build(
(
#|pub fn from_array(chars : Array[Char]) -> String { String::from_array(chars) }
),
),
"from_iter": build(
(
#|pub fn String::from_iter(iter : Iter[Char]) -> String { let chars = iter.collect()
#| String::from_array(chars) }
),
),
"from_iter": build(
(
#|pub fn from_iter(iter : Iter[Char]) -> String { let chars = iter.collect()
#| String::from_array(chars) }
),
),
"default": build(
(
#|pub fn default() -> String { \"\" }
),
),
"to_bytes": build(
(
#|pub fn to_bytes(self : String) -> Bytes { let array = FixedArray::make(self.length() * 2, Byte::default())
#| array.blit_from_string(0, self, 0, self.length())
#| array |> unsafe_to_bytes }
),
),
"to_array": build(
(
#|pub fn to_array(self : String) -> Array[Char] { self
#| .iter()
#| .fold(init=Array::new(capacity=self.length()), (rv, c) => {
#| rv.push(c)
#| rv
#| }) }
),
),
"iter": build(
(
#|pub fn iter(self : String) -> Iter[Char] { Iter::new(yield_ => {
#| let len = self.length()
#| for index in 0.. Iter2[Int, Char] { Iter2::new(yield_ => {
#| let len = self.length()
#| for index = 0, n = 0; index < len; index = index + 1, n = n + 1 {
#| let c1 = self.unsafe_charcode_at(index)
#| if c1.is_leading_surrogate() && index + 1 < len {
#| let c2 = self.unsafe_charcode_at(index + 1)
#| if c2.is_trailing_surrogate() {
#| let c = code_point_of_surrogate_pair(c1, c2)
#| guard yield_(n, c) is IterContinue else { break IterEnd }
#| continue index + 2, n + 1
#| }
#| }
#| //TODO: handle garbage input
#| guard yield_(n, c1.unsafe_to_char()) is IterContinue else {
#| break IterEnd
#| }
#| } else {
#| IterContinue
#| }
#| }) }
),
),
"rev_iter": build(
(
#|pub fn rev_iter(self : String) -> Iter[Char] { Iter::new(yield_ => {
#| let len = self.length()
#| for index = len - 1; index >= 0; index = index - 1 {
#| let c1 = self.unsafe_charcode_at(index)
#| if c1.is_trailing_surrogate() && index - 1 >= 0 {
#| let c2 = self.unsafe_charcode_at(index - 1)
#| if c2.is_leading_surrogate() {
#| let c = code_point_of_surrogate_pair(c2, c1)
#| guard yield_(c) is IterContinue else { break IterEnd }
#| continue index - 2
#| }
#| }
#| // TODO: handle garbage input
#| guard yield_(c1.unsafe_to_char()) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }
#| }) }
),
),
"op_get": build(
(
#|pub fn View::op_get(self : View, index : Int) -> Int { guard index >= 0 && index < self.length() else {
#| abort(\"Index out of bounds\")
#| }
#| self.str().unsafe_charcode_at(self.start() + index) }
),
),
"data": build(
(
#|pub fn data(self : View) -> String { self.str() }
),
),
"start_offset": build(
(
#|pub fn start_offset(self : View) -> Int { self.start() }
),
),
"length": build(
(
#|pub fn length(self : View) -> Int { self.end() - self.start() }
),
),
"charcodes": build(
(
#|pub fn String::charcodes(self : String, start~ : Int = 0, end? : Int) -> View { self.view(start_offset=start, end_offset?=end) }
),
),
"charcodes": build(
(
#|pub fn View::charcodes(self : View, start~ : Int = 0, end? : Int) -> View { self.view(start_offset=start, end_offset?=end) }
),
),
"offset_of_nth_char": build(
(
#|pub fn View::offset_of_nth_char(self : View, i : Int) -> Int? { if self
#| .str()
#| .offset_of_nth_char(i, start_offset=self.start(), end_offset=self.end())
#| is Some(index) {
#| Some(index - self.start())
#| } else {
#| None
#| } }
),
),
"unsafe_charcode_at": build(
(
#|pub fn View::unsafe_charcode_at(self : View, index : Int) -> Int { self.str().unsafe_charcode_at(self.start() + index) }
),
),
"char_length": build(
(
#|pub fn View::char_length(self : View) -> Int { self.str().char_length(start_offset=self.start(), end_offset=self.end()) }
),
),
"char_length_eq": build(
(
#|pub fn View::char_length_eq(self : View, len : Int) -> Bool { self
#| .str()
#| .char_length_eq(len, start_offset=self.start(), end_offset=self.end()) }
),
),
"char_length_ge": build(
(
#|pub fn View::char_length_ge(self : View, len : Int) -> Bool { self
#| .str()
#| .char_length_ge(len, start_offset=self.start(), end_offset=self.end()) }
),
),
"iter": build(
(
#|pub fn View::iter(self : View) -> Iter[Char] { Iter::new(yield_ => for index in self.start().. Iter2[Int, Char] { Iter2::new(yield_ => {
#| let len = self.length()
#| for index = 0, n = 0; index < len; index = index + 1, n = n + 1 {
#| let c1 = self.str().unsafe_charcode_at(self.start() + index)
#| if c1.is_leading_surrogate() && index + 1 < len {
#| let c2 = self.str().unsafe_charcode_at(self.start() + index + 1)
#| if c2.is_trailing_surrogate() {
#| let c = code_point_of_surrogate_pair(c1, c2)
#| guard yield_(n, c) is IterContinue else { break IterEnd }
#| continue index + 2, n + 1
#| }
#| }
#| guard yield_(n, c1.unsafe_to_char()) is IterContinue else {
#| break IterEnd
#| }
#| } else {
#| IterContinue
#| }
#| }) }
),
),
"rev_iter": build(
(
#|pub fn View::rev_iter(self : View) -> Iter[Char] { Iter::new(yield_ => for index = self.end() - 1
#| index >= self.start()
#| index = index - 1 {
#| let c1 = self.str().unsafe_charcode_at(index)
#| if c1.is_trailing_surrogate() && index - 1 >= 0 {
#| let c2 = self.str().unsafe_charcode_at(index - 1)
#| if c2.is_leading_surrogate() {
#| let c = code_point_of_surrogate_pair(c2, c1)
#| guard yield_(c) is IterContinue else { break IterEnd }
#| continue index - 2
#| }
#| }
#| guard yield_(c1.unsafe_to_char()) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }) }
),
),
"from_array": build(
(
#|pub fn View::from_array(chars : Array[Char]) -> View { // todo: remove .view() in new version
#| String::from_array(chars).view() }
),
),
"from_iter": build(
(
#|pub fn View::from_iter(iter : Iter[Char]) -> View { // todo: remove .view() in new version
#| String::from_iter(iter).view() }
),
),
"make": build(
(
#|pub fn View::make(length : Int, value : Char) -> View { // todo: remove .view() in new version
#| String::make(length, value).view() }
),
),
}
},
)
///|
let moonbitlang_core_test_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/test",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/bench": moonbitlang_core_bench_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
},
fn(_env, build) {
{
"eq": build(
(
#|pub fn[T : Show + Eq] eq(a : T, b : T, loc~ : SourceLoc) -> Unit raise { if a != b {
#| let a = debug_string(a)
#| let b = debug_string(b)
#| fail(\"`\\{a} == \\{b}`\", loc~)
#| } }
),
),
"ne": build(
(
#|pub fn[T : Show + Eq] ne(a : T, b : T, loc~ : SourceLoc) -> Unit raise { if !(a != b) {
#| let a = debug_string(a)
#| let b = debug_string(b)
#| fail(\"`\\{a} != \\{b}`\", loc~)
#| } }
),
),
"is_true": build(
(
#|pub fn is_true(x : Bool, loc~ : SourceLoc) -> Unit raise { if !x {
#| let x = debug_string(x)
#| fail(\"`\\{x}` is not true\", loc~)
#| } }
),
),
"is_false": build(
(
#|pub fn is_false(x : Bool, loc~ : SourceLoc) -> Unit raise { if x {
#| let x = debug_string(x)
#| fail(\"`\\{x}` is not false\", loc~)
#| } }
),
),
"new": build(
(
#|pub fn new(name : String) -> T { { name, buffer: StringBuilder::new() } }
),
),
"debug_string": build(
(
#|fn[T : Show] debug_string(t : T) -> String { let buf = StringBuilder::new(size_hint=50)
#| t.output(buf)
#| buf.to_string() }
),
),
"same_object": build(
(
#|pub fn[T : Show] same_object(a : T, b : T, loc~ : SourceLoc) -> Unit raise { if !physical_equal(a, b) {
#| let a = debug_string(a)
#| let b = debug_string(b)
#| fail(\"`\\{a} is \\{b}`\", loc~)
#| } }
),
),
"is_not": build(
(
#|pub fn[T : Show] is_not(a : T, b : T, loc~ : SourceLoc) -> Unit raise { if physical_equal(a, b) {
#| let a = debug_string(a)
#| let b = debug_string(b)
#| fail(\"`!(\\{a} is \\{b})`\", loc~)
#| } }
),
),
"fail": build(
(
#|pub fn[T] fail(msg : String, loc~ : SourceLoc) -> T raise { @builtin.fail(msg, loc~) }
),
),
"write": build(
(
#|pub fn write(self : T, obj : &Show) -> Unit { self.buffer.write_string(obj.to_string()) }
),
),
"writeln": build(
(
#|pub fn writeln(self : T, obj : &Show) -> Unit { self.write(obj)
#| self.buffer.write_char('\\n') }
),
),
}
},
)
///|
let moonbitlang_core_tuple_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/tuple",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
"moonbitlang/core/quickcheck/splitmix": moonbitlang_core_quickcheck_splitmix_module,
},
fn(_env, build) {
{
"pair": build(
(
#|pub fn[T, U] pair(x : T, y : U) -> (T, U) { (x, y) }
),
),
"fst": build(
(
#|pub fn[T, U] fst(tuple : (T, U)) -> T { tuple.0 }
),
),
"snd": build(
(
#|pub fn[T, U] snd(tuple : (T, U)) -> U { tuple.1 }
),
),
"map_fst": build(
(
#|pub fn[T, U, V] map_fst(f : (T) -> U, tuple : (T, V)) -> (U, V) { (f(tuple.0), tuple.1) }
),
),
"map_snd": build(
(
#|pub fn[T, U, V] map_snd(f : (T) -> U, tuple : (V, T)) -> (V, U) { (tuple.0, f(tuple.1)) }
),
),
"swap": build(
(
#|pub fn[T, U] swap(tuple : (T, U)) -> (U, T) { (tuple.1, tuple.0) }
),
),
"curry": build(
(
#|pub fn[T, U, V] curry(f : (T, U) -> V) -> (T) -> (U) -> V { (x : T) => (y : U) => f(x, y) }
),
),
"uncurry": build(
(
#|pub fn[T, U, V] uncurry(f : (T) -> (U) -> V) -> (T, U) -> V { (x : T, y : U) => f(x)(y) }
),
),
}
},
)
///|
let moonbitlang_core_uint_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/uint",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
fn(_env, build) {
{
"to_int64": build(
(
#|pub fn to_int64(self : UInt) -> Int64 { self.to_uint64().reinterpret_as_int64() }
),
),
"default": build(
(
#|pub fn default() -> UInt { 0 }
),
),
"to_be_bytes": build(
(
#|pub fn to_be_bytes(self : UInt) -> Bytes { [
#| (self >> 24).to_byte(),
#| (self >> 16).to_byte(),
#| (self >> 8).to_byte(),
#| self.to_byte(),
#| ] }
),
),
"to_le_bytes": build(
(
#|pub fn to_le_bytes(self : UInt) -> Bytes { [
#| self.to_byte(),
#| (self >> 8).to_byte(),
#| (self >> 16).to_byte(),
#| (self >> 24).to_byte(),
#| ] }
),
),
}
},
)
///|
let moonbitlang_core_uint16_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/uint16",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
},
fn(_env, build) {
{
"to_uint": build(
(
#|pub fn UInt16::to_uint(self : UInt16) -> UInt { self.to_int().reinterpret_as_uint() }
),
),
"to_uint64": build(
(
#|pub fn UInt16::to_uint64(self : UInt16) -> UInt64 { self.to_int().to_uint64() }
),
),
}
},
)
///|
let moonbitlang_core_uint64_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/uint64",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
fn(_env, build) {
{
"to_be_bytes": build(
(
#|pub fn to_be_bytes(self : UInt64) -> Bytes { [
#| (self >> 56).to_byte(),
#| (self >> 48).to_byte(),
#| (self >> 40).to_byte(),
#| (self >> 32).to_byte(),
#| (self >> 24).to_byte(),
#| (self >> 16).to_byte(),
#| (self >> 8).to_byte(),
#| self.to_byte(),
#| ] }
),
),
"to_le_bytes": build(
(
#|pub fn to_le_bytes(self : UInt64) -> Bytes { [
#| self.to_byte(),
#| (self >> 8).to_byte(),
#| (self >> 16).to_byte(),
#| (self >> 24).to_byte(),
#| (self >> 32).to_byte(),
#| (self >> 40).to_byte(),
#| (self >> 48).to_byte(),
#| (self >> 56).to_byte(),
#| ] }
),
),
}
},
)
///|
let moonbitlang_core_unit_module : RuntimeModule = RuntimeModule::new(
"moonbitlang/core/unit",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
fn(_env, build) {
{
"to_string": build(
(
#|pub fn to_string(self : Unit) -> String { let _ = self
#| \"()\" }
),
),
"default": build(
(
#|pub fn default() -> Unit { () }
),
),
}
},
)
|