///|
/// Auto-generated core modules for moonbit-eval interpreter
/// This file contains embedded RuntimePackage definitions for all moonbitlang/core modules
///|
let core_modules : Map[String, RuntimePackage] = {
"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,
"error": moonbitlang_core_error_module,
"moonbitlang/core/error": moonbitlang_core_error_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 : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/abort",
deps={},
files={
"moon.pkg.json": (
#|{
#| "virtual": {
#| "has-default": true
#| }
#|}
),
"abort.mbt": (
#|pub fn[T] abort(msg : String) -> T {
#| let _ = msg
#| panic_impl()
#|}
#|fn[T] panic_impl() -> T = "%panic"
),
},
)
///|
let moonbitlang_core_array_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/bytes",
#| "moonbitlang/core/string",
#| "moonbitlang/core/quickcheck",
#| "moonbitlang/core/quickcheck/splitmix"
#| ],
#| "test-import": [
#| "moonbitlang/core/char",
#| "moonbitlang/core/test",
#| "moonbitlang/core/random",
#| "moonbitlang/core/json"
#| ],
#| "targets": {
#| "array_js.mbt": ["js"],
#| "array_nonjs.mbt": ["not", "js"],
#| "blit_js.mbt": ["js"],
#| "blit_nonjs.mbt": ["not", "js"],
#| "panic_test.mbt": ["not", "native", "llvm"]
#| }
#|}
),
"array.mbt": (
#|pub fn[T] Array::from_iter(iter : Iter[T]) -> Array[T] {
#| iter.collect()
#|}
#|pub fn[T] Array::push_iter(self : Self[T], iter : Iter[T]) -> Unit {
#| for x in iter {
#| self.push(x)
#| }
#|}
#|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)
#| self.swap(i, j)
#| }
#|}
#|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
#|}
#|pub fn[A, B] filter_map(
#| self : Array[A],
#| f : (A) -> B? raise?,
#|) -> Array[B] raise? {
#| let result = []
#| for x in self {
#| if f(x) is Some(x) {
#| result.push(x)
#| }
#| }
#| result
#|}
#|pub fn[A] last(self : Array[A]) -> A? {
#| match self {
#| [] => None
#| [.., last] => Some(last)
#| }
#|}
#|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)
#|}
#|pub fn[A, B, C] zip_with(
#| l : Array[A],
#| r : Array[B],
#| merge : (A, B) -> C raise?,
#|) -> Array[C] raise? {
#| let length = if l.length() < r.length() { l.length() } else { r.length() }
#| let arr = Array::new(capacity=length)
#| for i in 0.. Iter2[A, B] {
#| Iter2::new(yield_ => {
#| let length = if self.length() < other.length() {
#| self.length()
#| } else {
#| other.length()
#| }
#| for i in 0.. X::arbitrary(x, rs))
#|}
#|pub fn[A : @string.ToStringView] Array::join(
#| self : Array[A],
#| separator : @string.View,
#|) -> String {
#| self[:].join(separator)
#|}
),
"array_js.mbt": (
#|priv type JSArray
#|fn[T] JSArray::ofAnyArray(array : Array[T]) -> JSArray = "%identity"
#|fn[T] JSArray::toAnyArray(self : JSArray) -> Array[T] = "%identity"
#|fn[T] JSArray::ofAnyFixedArray(array : FixedArray[T]) -> JSArray = "%identity"
#|fn[T] JSArray::toAnyFixedArray(self : JSArray) -> FixedArray[T] = "%identity"
#|extern "js" fn JSArray::copy(self : JSArray) -> JSArray =
#| #|(arr) => arr.slice(0)
#|pub fn[T] copy(self : Array[T]) -> Array[T] {
#| JSArray::ofAnyArray(self).copy().toAnyArray()
#|}
),
"array_nonjs.mbt": (
#|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
#| }
#|}
),
"blit.mbt": (
#|test "copy" {
#| let a : FixedArray[_] = [1, 2, 3, 4]
#| let b = a.copy()
#| inspect(b, content="[1, 2, 3, 4]")
#| inspect(physical_equal(b, a), content="false")
#| let c = FixedArray::make(8, 0)
#| a.blit_to(c, len=4, dst_offset=3)
#| inspect(c, content="[0, 0, 0, 1, 2, 3, 4, 0]")
#| inspect(([] : FixedArray[Int]).copy(), content="[]")
#| a.blit_to(a, len=2, src_offset=1)
#| inspect(a, content="[2, 3, 3, 4]")
#|}
#|pub fn FixedArray::blit_from_bytesview(
#| self : FixedArray[Byte],
#| bytes_offset : Int,
#| src : @bytes.View,
#|) -> Unit {
#| FixedArray::blit_from_bytes(
#| self,
#| bytes_offset,
#| src.data(),
#| src.start_offset(),
#| src.length(),
#| )
#|}
),
"blit_js.mbt": (
#|pub fn[T] FixedArray::copy(self : FixedArray[T]) -> FixedArray[T] {
#| JSArray::ofAnyFixedArray(self).copy().toAnyFixedArray()
#|}
),
"blit_nonjs.mbt": (
#|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
#| }
#|}
),
"deprecated.mbt": "",
"fixedarray.mbt": (
#|pub fn[T] FixedArray::each(
#| self : FixedArray[T],
#| f : (T) -> Unit raise?,
#|) -> Unit raise? {
#| for v in self {
#| f(v)
#| }
#|}
#|test "each" {
#| let mut i = 0
#| let mut failed = false
#| let f = elem => {
#| if elem != i + 1 {
#| failed = true
#| }
#| i = i + 1
#| }
#| {
#| i = 0
#| ([] : FixedArray[_]).each(f)
#| assert_false(failed)
#| inspect(i, content="0")
#| }
#| {
#| i = 0
#| ([1] : FixedArray[_]).each(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| }
#| i = 0
#| ([1, 2, 3, 4, 5] : FixedArray[_]).each(f)
#| assert_false(failed)
#| inspect(i, content="5")
#|}
#|pub fn[T] FixedArray::eachi(
#| self : FixedArray[T],
#| f : (Int, T) -> Unit raise?,
#|) -> Unit raise? {
#| for i, v in self {
#| f(i, v)
#| }
#|}
#|test "eachi" {
#| let mut i = 0
#| let mut failed = false
#| let f = (index, elem) => {
#| if index != i || elem != i + 1 {
#| failed = true
#| }
#| i = i + 1
#| }
#| {
#| i = 0
#| ([] : FixedArray[_]).eachi(f)
#| assert_false(failed)
#| inspect(i, content="0")
#| }
#| {
#| i = 0
#| ([1] : FixedArray[_]).eachi(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| }
#| i = 0
#| ([1, 2, 3, 4, 5] : FixedArray[_]).eachi(f)
#| assert_false(failed)
#| inspect(i, content="5")
#|}
#|pub fn[T] FixedArray::rev_each(
#| self : FixedArray[T],
#| f : (T) -> Unit raise?,
#|) -> Unit raise? {
#| for i = self.length() - 1; i >= 0; i = i - 1 {
#| f(self[i])
#| }
#|}
#|test "rev_each" {
#| let mut i = 6
#| let mut failed = false
#| let f = elem => {
#| if elem != i - 1 {
#| failed = true
#| }
#| i = i - 1
#| }
#| {
#| i = 1
#| ([] : FixedArray[_]).rev_each(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| }
#| {
#| i = 2
#| ([1] : FixedArray[_]).rev_each(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| }
#| i = 6
#| ([1, 2, 3, 4, 5] : FixedArray[_]).rev_each(f)
#| assert_false(failed)
#| inspect(i, content="1")
#|}
#|pub fn[T] FixedArray::rev_eachi(
#| self : FixedArray[T],
#| f : (Int, T) -> Unit raise?,
#|) -> Unit raise? {
#| let len = self.length()
#| for i in 0.. {
#| if index != j || elem != i - 1 {
#| failed = true
#| }
#| i = i - 1
#| j = j + 1
#| }
#| {
#| i = 1
#| j = 0
#| ([] : FixedArray[_]).rev_eachi(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| inspect(j, content="0")
#| }
#| {
#| i = 2
#| j = 0
#| ([1] : FixedArray[_]).rev_eachi(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| inspect(j, content="1")
#| }
#| i = 6
#| j = 0
#| ([1, 2, 3, 4, 5] : FixedArray[_]).rev_eachi(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| inspect(j, content="5")
#|}
#|pub fn[T, U] FixedArray::map(
#| self : FixedArray[T],
#| f : (T) -> U raise?,
#|) -> FixedArray[U] raise? {
#| if self.length() == 0 {
#| return []
#| }
#| let res = FixedArray::make(self.length(), f(self[0]))
#| for i in 1.. x)
#| assert_eq(empty, [])
#| let simple_arr : FixedArray[_] = [6]
#| let simple_doubled = simple_arr.map(x => x * 2)
#| assert_eq(simple_doubled, [12])
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| let doubled = arr.map(x => x * 2)
#| assert_eq(doubled, [2, 4, 6, 8, 10])
#|}
#|pub fn[T, U] FixedArray::mapi(
#| self : FixedArray[T],
#| f : (Int, T) -> U raise?,
#|) -> FixedArray[U] raise? {
#| if self.length() == 0 {
#| return []
#| }
#| let res = FixedArray::make(self.length(), f(0, self[0]))
#| for i in 1.. x + i)
#| assert_eq(empty, [])
#| let simple_arr : FixedArray[_] = [6]
#| let simple_doubled = simple_arr.mapi((i, x) => x * 2 + i)
#| assert_eq(simple_doubled, [12])
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| let doubled = arr.mapi((i, x) => x * 2 + i)
#| assert_eq(doubled, [2, 5, 8, 11, 14])
#|}
#|pub fn[T] FixedArray::makei(
#| length : Int,
#| value : (Int) -> T raise?,
#|) -> FixedArray[T] raise? {
#| if length <= 0 {
#| []
#| } else {
#| let array = FixedArray::make(length, value(0))
#| for i in 1.. i)
#| inspect(empty.length(), content="0")
#| let simple_arr = FixedArray::makei(1, i => i)
#| inspect(simple_arr.length(), content="1")
#| inspect(simple_arr[0], content="0")
#| let arr = FixedArray::makei(2, i => i)
#| inspect(arr.length(), content="2")
#| inspect(arr[0], content="0")
#| inspect(arr[1], content="1")
#|}
#|pub fn[T] FixedArray::from_array(array : Array[T]) -> FixedArray[T] {
#| FixedArray::makei(array.length(), i => array[i])
#|}
#|test "from_array" {
#| let array = FixedArray::from_array([1, 2, 3, 4, 5])
#| assert_eq(array, [1, 2, 3, 4, 5])
#|}
#|pub fn[A, B] FixedArray::fold(
#| self : FixedArray[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for i = 0, acc = init; i < self.length(); {
#| continue i + 1, f(acc, self[i])
#| } else {
#| acc
#| }
#|}
#|test "fold" {
#| let sum = ([] : FixedArray[_]).fold(init=1, (sum, elem) => sum + elem)
#| inspect(sum, content="1")
#| let sum = ([1] : FixedArray[_]).fold(init=2, (sum, elem) => sum + elem)
#| inspect(sum, content="3")
#| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).fold(init=0, (sum, elem) => sum +
#| elem)
#| inspect(sum, content="15")
#|}
#|pub fn[A, B] FixedArray::rev_fold(
#| self : FixedArray[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for i = self.length() - 1, acc = init; i >= 0; {
#| continue i - 1, f(acc, self[i])
#| } else {
#| acc
#| }
#|}
#|test "rev_fold" {
#| let sum = ([] : FixedArray[_]).rev_fold(init=1, (sum, elem) => sum + elem)
#| inspect(sum, content="1")
#| let sum = ([1] : FixedArray[_]).rev_fold(init=2, (sum, elem) => sum + elem)
#| inspect(sum, content="3")
#| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).rev_fold(init=0, (sum, elem) => sum +
#| elem)
#| inspect(sum, content="15")
#|}
#|pub fn[A, B] FixedArray::foldi(
#| self : FixedArray[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| for i = 0, acc = init; i < self.length(); {
#| continue i + 1, f(i, acc, self[i])
#| } else {
#| acc
#| }
#|}
#|test "fold_lefti" {
#| let f = (index, sum, elem) => index + sum + elem
#| {
#| let sum = ([] : FixedArray[_]).foldi(init=1, f)
#| inspect(sum, content="1")
#| }
#| {
#| let sum = ([1] : FixedArray[_]).foldi(init=2, f)
#| inspect(sum, content="3")
#| }
#| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).foldi(init=0, f)
#| inspect(sum, content="25")
#|}
#|pub fn[A, B] FixedArray::rev_foldi(
#| self : FixedArray[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| let len = self.length()
#| for i = len - 1, acc = init; i >= 0; {
#| continue i - 1, f(len - i - 1, acc, self[i])
#| } else {
#| acc
#| }
#|}
#|test "rev_foldi" {
#| let f = (index, sum, elem) => index + sum + elem
#| {
#| let sum = ([] : FixedArray[_]).rev_foldi(init=1, f)
#| inspect(sum, content="1")
#| }
#| {
#| let sum = ([1] : FixedArray[_]).rev_foldi(init=2, f)
#| inspect(sum, content="3")
#| }
#| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).rev_foldi(init=0, f)
#| inspect(sum, content="25")
#|}
#|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
#|}
#|test "swap" {
#| {
#| let arr : FixedArray[Int] = [1]
#| arr.swap(0, 0)
#| assert_eq(arr, [1])
#| }
#| {
#| let arr : FixedArray[_] = [1, 2]
#| arr.swap(0, 0)
#| assert_eq(arr, [1, 2])
#| arr.swap(0, 1)
#| assert_eq(arr, [2, 1])
#| }
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| arr.swap(3, 3)
#| assert_eq(arr, [1, 2, 3, 4, 5])
#| arr.swap(1, 3)
#| assert_eq(arr, [1, 4, 3, 2, 5])
#|}
#|pub fn[T] FixedArray::all(
#| self : FixedArray[T],
#| f : (T) -> Bool raise?,
#|) -> Bool raise? {
#| for i in 0.. ele < 6))
#| assert_true(arr.all(ele => ele < 5))
#| }
#| {
#| let arr : FixedArray[_] = [5]
#| assert_true(arr.all(ele => ele < 6))
#| assert_false(arr.all(ele => ele < 5))
#| }
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| assert_true(arr.all(ele => ele < 6))
#| assert_false(arr.all(ele => ele < 5))
#|}
#|pub fn[T] FixedArray::any(
#| self : FixedArray[T],
#| f : (T) -> Bool raise?,
#|) -> Bool raise? {
#| for i in 0.. ele < 6))
#| assert_false(arr.any(ele => ele < 5))
#| }
#| {
#| let arr : FixedArray[_] = [5]
#| assert_true(arr.any(ele => ele < 6))
#| assert_false(arr.any(ele => ele < 5))
#| }
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| assert_true(arr.any(ele => ele < 6))
#| assert_true(arr.any(ele => ele < 5))
#|}
#|test "fill" {
#| {
#| let arr : FixedArray[Int] = []
#| arr.fill(3)
#| assert_eq(arr, [])
#| }
#| {
#| let arr : FixedArray[_] = [6]
#| arr.fill(5)
#| assert_eq(arr, [5])
#| }
#| let arr : FixedArray[_] = [0, 0, 0, 0, 0]
#| arr.fill(3)
#| assert_eq(arr, [3, 3, 3, 3, 3])
#|}
#|pub fn[T : Eq] FixedArray::search(self : FixedArray[T], value : T) -> Int? {
#| for i in 0.. Bool {
#| for i in 0.. Bool {
#| if prefix.length() > self.length() {
#| return false
#| }
#| for i in 0.. Bool {
#| let self_len = self.length()
#| let suf_len = suffix.length()
#| if suf_len > self_len {
#| return false
#| }
#| for i in 0.. Bool {
#| if self.length() != that.length() {
#| return false
#| }
#| for i in 0.. if i < slen {
#| self[i]
#| } else {
#| other[i - slen]
#| })
#|}
#|test "op_add" {
#| {
#| inspect(([] : FixedArray[Int]) + [], content="[]")
#| inspect(([] : FixedArray[_]) + [1, 2, 3, 4, 5], content="[1, 2, 3, 4, 5]")
#| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) + [], content="[1, 2, 3, 4, 5]")
#| }
#| {
#| inspect(([1] : FixedArray[_]) + [2], content="[1, 2]")
#| inspect(
#| ([1] : FixedArray[_]) + [1, 2, 3, 4, 5],
#| content="[1, 1, 2, 3, 4, 5]",
#| )
#| inspect(
#| ([1, 2, 3, 4, 5] : FixedArray[_]) + [1],
#| content="[1, 2, 3, 4, 5, 1]",
#| )
#| }
#| inspect(
#| ([1, 2, 3, 4, 5] : FixedArray[_]) + [6, 7, 8, 9, 10],
#| content="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]",
#| )
#|}
#|test "iter" {
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| let iter = arr.iter()
#| let exb = StringBuilder::new()
#| let mut i = 0
#| iter.each(x => {
#| exb.write_string(x.to_string())
#| exb.write_char('\n')
#| i = i + 1
#| })
#| assert_eq(i, arr.length())
#| inspect(
#| exb,
#| content=(
#| #|1
#| #|2
#| #|3
#| #|4
#| #|5
#| #|
#| ),
#| )
#|}
#|pub fn[T] FixedArray::from_iter(iter : Iter[T]) -> FixedArray[T] {
#| FixedArray::from_array(iter.collect())
#|}
#|pub fn[A] FixedArray::last(self : FixedArray[A]) -> A? {
#| match self {
#| [] => None
#| [.., last] => Some(last)
#| }
#|}
#|pub fn FixedArray::join(
#| self : FixedArray[String],
#| separator : @string.View,
#|) -> String {
#| let len = self.length()
#| if len == 0 {
#| return ""
#| }
#| let first = self[0]
#| let mut size_hint = first.length()
#| for i in 1.. X::arbitrary(i, rs))
#|}
),
"fixedarray_sort.mbt": (
#|pub fn[T : Compare] FixedArray::stable_sort(self : FixedArray[T]) -> Unit {
#| timsort({ array: self, start: 0, end: self.length() })
#|}
#|priv struct TimSortRun {
#| len : Int
#| start : Int
#|}
#|fn[T : Compare] timsort(arr : FixedArraySlice[T]) -> Unit {
#| let max_insertion = 20
#| 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()
#| }
#| 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
#| }
#| }
#|}
#|fn[T : Compare] FixedArraySlice::insertion_sort(
#| arr : FixedArraySlice[T],
#|) -> Unit {
#| for i in 1.. 0 && arr[j] < arr[j - 1]; j = j - 1 {
#| arr.swap(j, j - 1)
#| }
#| }
#|}
#|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]
#| }
#|}
#|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)
#| }
#| }
#| }
#|}
#|fn[T : Compare] provide_sorted_batch(
#| arr : FixedArraySlice[T],
#| start : Int,
#| end : Int,
#|) -> Int {
#| let len = arr.length()
#| let min_insertion_run = 10
#| let start_end_diff = end - start
#| if start_end_diff < min_insertion_run && end < len {
#| let sort_end = minimum(len, start + min_insertion_run)
#| FixedArraySlice::insertion_sort(arr.slice(start, sort_end))
#| sort_end
#| } else {
#| end
#| }
#|}
#|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
#| }
#|}
#|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()),
#| )
#|}
#|fn[T : Compare] fixed_quick_sort(
#| arr : FixedArraySlice[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 bubble_sort_len = 16
#| while true {
#| let len = arr.length()
#| if len <= bubble_sort_len {
#| if len >= 2 {
#| fixed_bubble_sort(arr)
#| }
#| return
#| }
#| if limit == 0 {
#| fixed_heap_sort(arr)
#| return
#| }
#| let (pivot_index, likely_sorted) = fixed_choose_pivot(arr)
#| if was_partitioned && balanced && likely_sorted {
#| if fixed_try_bubble_sort(arr) {
#| return
#| }
#| }
#| let (pivot, partitioned) = fixed_partition(arr, pivot_index)
#| was_partitioned = partitioned
#| balanced = minimum(pivot, len - pivot) >= len / 8
#| if !balanced {
#| limit -= 1
#| }
#| if pred is Some(pred) {
#| if pred == arr[pivot] {
#| let mut i = pivot
#| while i < len && pred == arr[i] {
#| i = i + 1
#| }
#| arr = arr.slice(i, len)
#| continue
#| }
#| }
#| let left = arr.slice(0, pivot)
#| let right = arr.slice(pivot + 1, len)
#| if left.length() < right.length() {
#| fixed_quick_sort(left, pred, limit)
#| pred = Some(arr[pivot])
#| arr = right
#| } else {
#| fixed_quick_sort(right, Some(arr[pivot]), limit)
#| arr = left
#| }
#| }
#|}
#|fn fixed_get_limit(len : Int) -> Int {
#| let mut len = len
#| let mut limit = 0
#| while len > 0 {
#| len = len / 2
#| limit += 1
#| }
#| limit
#|}
#|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
#|}
#|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)
#| }
#| }
#|}
#|test "fixed_try_bubble_sort" {
#| let arr : FixedArray[_] = [8, 7, 6, 5, 4, 3, 2, 1]
#| let sorted = fixed_try_bubble_sort({ array: arr, start: 0, end: 8 })
#| inspect(sorted, content="true")
#| assert_eq(arr, [1, 2, 3, 4, 5, 6, 7, 8])
#|}
#|fn[T : Compare] fixed_partition(
#| arr : FixedArraySlice[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)
#|}
#|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)
#| }
#|}
#|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)
#| }
#|}
#|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
#| }
#|}
#|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)
#|}
#|test "fixed_heap_sort" {
#| fixed_test_sort(arr => fixed_heap_sort({
#| array: arr,
#| start: 0,
#| end: arr.length(),
#| }))
#|}
#|test "fixed_bubble_sort" {
#| fixed_test_sort(arr => fixed_bubble_sort({
#| array: arr,
#| start: 0,
#| end: arr.length(),
#| }))
#|}
#|test "sort" {
#| fixed_test_sort(arr => arr.sort())
#|}
#|test "stable_sort" {
#| let arr : FixedArray[_] = [5, 1, 3, 4, 2]
#| arr.stable_sort()
#| 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)
#| }
#| arr.stable_sort()
#| let expected = FixedArray::make(1000, 0)
#| for i in 0..<1000 {
#| expected[i] = i
#| }
#| assert_eq(arr, expected)
#|}
#|pub fn[T : Compare] FixedArray::is_sorted(arr : FixedArray[T]) -> Bool {
#| for i in 1.. acc + x)
#| let arr = FixedArray::make(total_len, 0)
#| let mut index = 0
#| for i in 0.. K,
#|) -> Unit {
#| fixed_quick_sort_by(
#| { array: self, start: 0, end: self.length() },
#| (a, b) => map(a).compare(map(b)),
#| None,
#| get_limit(self.length()),
#| )
#|}
#|test "@array.sort_by_key/basic" {
#| let arr : FixedArray[_] = [3, 1, 4, 1, 5]
#| arr.sort_by_key(x => x)
#| inspect(arr, content="[1, 1, 3, 4, 5]")
#| let arr2 : FixedArray[_] = [3, 1, 4, 1, 5]
#| arr2.sort_by_key(x => -x)
#| inspect(arr2, content="[5, 4, 3, 1, 1]")
#|}
#|pub fn[T] FixedArray::sort_by(
#| self : FixedArray[T],
#| cmp : (T, T) -> Int,
#|) -> Unit {
#| fixed_quick_sort_by(
#| { array: self, start: 0, end: self.length() },
#| cmp,
#| None,
#| get_limit(self.length()),
#| )
#|}
#|test "sort_by: basic functionality" {
#| let arr : FixedArray[_] = [5, 3, 2, 4, 1]
#| arr.sort_by((a, b) => a - b)
#| inspect(arr, content="[1, 2, 3, 4, 5]")
#|}
#|test "sort_by: edge cases" {
#| let empty_arr : FixedArray[Int] = []
#| empty_arr.sort_by((a, b) => a - b)
#| inspect(empty_arr, content="[]")
#| let single_element_arr : FixedArray[_] = [1]
#| single_element_arr.sort_by((a, b) => a - b)
#| inspect(single_element_arr, content="[1]")
#|}
#|test "sort_by: random cases" {
#| let random_arr1 : FixedArray[_] = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
#| random_arr1.sort_by((a, b) => a - b)
#| inspect(random_arr1, content="[1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]")
#| let random_arr2 : FixedArray[_] = [7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9]
#| random_arr2.sort_by((a, b) => a - b)
#| inspect(random_arr2, content="[1, 1, 2, 2, 4, 5, 7, 8, 8, 8, 8, 9]")
#| let random_arr3 : FixedArray[_] = [10, -1, 0, 10, -1, 0, 10, -1, 0]
#| random_arr3.sort_by((a, b) => a - b)
#| inspect(random_arr3, content="[-1, -1, -1, 0, 0, 0, 10, 10, 10]")
#|}
#|test "sort_by: large array" {
#| let large_arr = FixedArray::makei(1000, i => 1000 - i)
#| large_arr.sort_by((a, b) => a - b)
#| let expected = FixedArray::makei(1000, i => i + 1)
#| inspect(large_arr, content=expected.to_string())
#|}
#|test "sort_by: negative numbers" {
#| let negative_arr : FixedArray[_] = [-5, -3, -2, -4, -1]
#| negative_arr.sort_by((a, b) => a - b)
#| inspect(negative_arr, content="[-5, -4, -3, -2, -1]")
#|}
#|test "sort_by: mixed positive and negative numbers" {
#| let mixed_arr : FixedArray[_] = [-5, 3, -2, 4, -1]
#| mixed_arr.sort_by((a, b) => a - b)
#| inspect(mixed_arr, content="[-5, -2, -1, 3, 4]")
#|}
#|fn[T] fixed_quick_sort_by(
#| arr : FixedArraySlice[T],
#| cmp : (T, T) -> Int,
#| 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 bubble_sort_len = 16
#| while true {
#| let len = arr.length()
#| if len <= bubble_sort_len {
#| if len >= 2 {
#| fixed_bubble_sort_by(arr, cmp)
#| }
#| return
#| }
#| if limit == 0 {
#| fixed_heap_sort_by(arr, cmp)
#| return
#| }
#| let (pivot_index, likely_sorted) = fixed_choose_pivot_by(arr, cmp)
#| if was_partitioned && balanced && likely_sorted {
#| if fixed_try_bubble_sort_by(arr, cmp) {
#| return
#| }
#| }
#| let (pivot, partitioned) = fixed_partition_by(arr, cmp, pivot_index)
#| was_partitioned = partitioned
#| balanced = minimum(pivot, len - pivot) >= len / 8
#| if !balanced {
#| limit -= 1
#| }
#| if pred is Some(pred) {
#| if cmp(pred, arr[pivot]) == 0 {
#| let mut i = pivot
#| while i < len && cmp(pred, arr[i]) == 0 {
#| i = i + 1
#| }
#| arr = arr.slice(i, len)
#| continue
#| }
#| }
#| let left = arr.slice(0, pivot)
#| let right = arr.slice(pivot + 1, len)
#| if left.length() < right.length() {
#| fixed_quick_sort_by(left, cmp, pred, limit)
#| pred = Some(arr[pivot])
#| arr = right
#| } else {
#| fixed_quick_sort_by(right, cmp, Some(arr[pivot]), limit)
#| arr = left
#| }
#| }
#|}
#|fn[T] fixed_try_bubble_sort_by(
#| arr : FixedArraySlice[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
#|}
#|fn[T] fixed_bubble_sort_by(
#| arr : FixedArraySlice[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)
#| }
#| }
#|}
#|test "try_bubble_sort" {
#| let arr : FixedArray[_] = [8, 7, 6, 5, 4, 3, 2, 1]
#| let sorted = fixed_try_bubble_sort_by({ array: arr, start: 0, end: 8 }, (a, b) => a -
#| b)
#| inspect(sorted, content="true")
#| assert_eq(arr, [1, 2, 3, 4, 5, 6, 7, 8])
#|}
#|fn[T] fixed_partition_by(
#| arr : FixedArraySlice[T],
#| cmp : (T, T) -> Int,
#| 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 cmp(arr[j], pivot) < 0 {
#| if i != j {
#| arr.swap(i, j)
#| partitioned = false
#| }
#| i = i + 1
#| }
#| }
#| arr.swap(i, arr.length() - 1)
#| (i, partitioned)
#|}
#|fn[T] fixed_choose_pivot_by(
#| arr : FixedArraySlice[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)
#| }
#|}
#|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)
#| }
#|}
#|fn[T] fixed_sift_down_by(
#| arr : FixedArraySlice[T],
#| index : Int,
#| cmp : (T, T) -> Int,
#|) -> Unit {
#| let mut index = index
#| let len = arr.length()
#| let mut child = index * 2 + 1
#| while child < len {
#| if child + 1 < len && cmp(arr[child], arr[child + 1]) < 0 {
#| child = child + 1
#| }
#| if cmp(arr[index], arr[child]) >= 0 {
#| return
#| }
#| arr.swap(index, child)
#| index = child
#| child = index * 2 + 1
#| }
#|}
#|test "heap_sort" {
#| fixed_test_sort(arr => fixed_heap_sort_by(
#| { array: arr, start: 0, end: arr.length() },
#| (a, b) => a - b,
#| ))
#|}
#|test "bubble_sort" {
#| fixed_test_sort(arr => fixed_bubble_sort_by(
#| { array: arr, start: 0, end: arr.length() },
#| (a, b) => a - b,
#| ))
#|}
#|test "sort" {
#| fixed_test_sort(arr => arr.sort())
#|}
#|test "sort_by" {
#| let arr = [5, 1, 3, 4, 2]
#| arr.sort_by_key(x => -x)
#| assert_eq(arr, [5, 4, 3, 2, 1])
#|}
#|test "sort_by_fallback" {
#| let arr = FixedArray::makei(100, i => if i % 2 == 0 { 1 } else { 0 })
#| arr.sort_by(
#| (a, b) => if a < b { -1 } else { 1 },
#| )
#| assert_true(arr.is_sorted())
#|}
),
"slice.mbt": (
#|priv struct FixedArraySlice[T] {
#| array : FixedArray[T]
#| start : Int
#| end : Int
#|}
#|fn[T] FixedArraySlice::length(self : FixedArraySlice[T]) -> Int {
#| self.end - self.start
#|}
#|fn[T] FixedArraySlice::op_get(self : FixedArraySlice[T], index : Int) -> T {
#| self.array[self.start + index]
#|}
#|fn[T] FixedArraySlice::op_set(
#| self : FixedArraySlice[T],
#| index : Int,
#| value : T,
#|) -> Unit {
#| self.array[self.start + index] = value
#|}
#|fn[T] FixedArraySlice::swap(
#| self : FixedArraySlice[T],
#| a : Int,
#| b : Int,
#|) -> Unit {
#| self.array.swap(self.start + a, self.start + b)
#|}
#|fn[T] FixedArraySlice::rev_inplace(self : FixedArraySlice[T]) -> Unit {
#| let len = self.length()
#| let mid_len = len / 2
#| for i in 0.. FixedArraySlice[T] {
#| { array: self.array, start: self.start + start, end: self.start + end }
#|}
),
"sort.mbt": (
#|pub fn[T : Compare] sort(self : Array[T]) -> Unit {
#| let len = self.length()
#| quick_sort(self[:len], None, get_limit(len))
#|}
#|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
#| }
#| if limit == 0 {
#| heap_sort(arr)
#| return
#| }
#| let (pivot_index, likely_sorted) = choose_pivot(arr)
#| 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) {
#| 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]
#| 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
#| }
#| }
#|}
#|fn get_limit(len : Int) -> Int {
#| let mut len = len
#| let mut limit = 0
#| while len > 0 {
#| len = len / 2
#| limit += 1
#| }
#| limit
#|}
#|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
#|}
#|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)
#| }
#| }
#|}
#|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)
#|}
#|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)
#| }
#|}
#|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)
#| }
#|}
#|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
#| }
#|}
#|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)
#|}
#|test "try_bubble_sort" {
#| let arr = [8, 7, 6, 5, 4, 3, 2, 1]
#| let sorted = try_bubble_sort(arr[0:8])
#| inspect(sorted, content="true")
#| assert_eq(arr, [1, 2, 3, 4, 5, 6, 7, 8])
#|}
#|test "heap_sort" {
#| test_sort(arr => heap_sort(arr[:]))
#|}
#|test "insertion_sort" {
#| test_sort(arr => ArrayView::insertion_sort(arr[:]))
#|}
#|test "sort" {
#| test_sort(arr => arr.sort())
#|}
#|test "sort with same pivot optimization" {
#| let arr = [
#| 35, 43, 72, 83, 39, 4, 83, 18, 43, 25, 88, 51, 43, 60, 83, 6, 36, 68, 79, 86,
#| ]
#| arr.sort()
#| assert_eq(arr, [
#| 4, 6, 18, 25, 35, 36, 39, 43, 43, 43, 51, 60, 68, 72, 79, 83, 83, 83, 86, 88,
#| ])
#|}
#|test "heap_sort coverage" {
#| let arr = [5, 4, 3, 2, 1]
#| heap_sort(arr[:])
#| assert_eq(arr, [1, 2, 3, 4, 5])
#| let arr2 = [1, 2, 3, 4, 5]
#| heap_sort(arr2[:])
#| assert_eq(arr2, [1, 2, 3, 4, 5])
#| let arr2 = [1, 2, 3, 4, 5]
#| heap_sort(arr2[:])
#| assert_eq(arr2, [1, 2, 3, 4, 5])
#| let arr3 = [5, 5, 5, 5, 1]
#| heap_sort(arr3[:])
#| assert_eq(arr3, [1, 5, 5, 5, 5])
#|}
#|test "quick_sort limit check" {
#| let arr = [5, 4, 3, 2, 1]
#| quick_sort(arr[:], None, 0)
#| assert_eq(arr, [1, 2, 3, 4, 5])
#| let arr2 = [1, 2, 3, 4, 5]
#| quick_sort(arr2[:], None, 0)
#| assert_eq(arr2, [1, 2, 3, 4, 5])
#| let arr3 = [5, 5, 5, 5, 1]
#| quick_sort(arr3[:], None, 0)
#| assert_eq(arr3, [1, 5, 5, 5, 5])
#|}
#|test "quick_sort with pred check" {
#| let arr = []
#| for i = 16; i >= 0; i = i - 1 {
#| arr.push(i)
#| }
#| quick_sort(arr[:], Some(8), 0)
#| assert_eq(arr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
#| let arr = [5, 4, 3, 2, 1]
#| quick_sort(arr[:], Some(3), 0)
#| assert_eq(arr, [1, 2, 3, 4, 5])
#| let arr2 = [1, 2, 3, 4, 5]
#| quick_sort(arr2[:], Some(3), 0)
#| assert_eq(arr2, [1, 2, 3, 4, 5])
#| let arr3 = [5, 5, 5, 5, 1]
#| quick_sort(arr3[:], Some(3), 0)
#| assert_eq(arr3, [1, 5, 5, 5, 5])
#|}
#|test "quick_sort with unbalanced partitions" {
#| let arr = []
#| for i = 16; i >= 0; i = i - 1 {
#| arr.push(if i >= 8 { i } else { 8 })
#| }
#| quick_sort(arr[:], Some(8), 42)
#| assert_eq(arr, [8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16])
#| let arr = [5, 4, 3, 2, 1]
#| quick_sort(arr[:], None, 1)
#| assert_eq(arr, [1, 2, 3, 4, 5])
#| let arr2 = [1, 2, 3, 4, 5]
#| quick_sort(arr2[:], None, 1)
#| assert_eq(arr2, [1, 2, 3, 4, 5])
#| let arr3 = [5, 5, 5, 5, 1]
#| quick_sort(arr3[:], None, 1)
#| assert_eq(arr3, [1, 5, 5, 5, 5])
#|}
#|test "quick_sort with pivot equal to pred" {
#| let arr = [5, 4, 3, 2, 1]
#| quick_sort(arr[:], Some(3), 0)
#| assert_eq(arr, [1, 2, 3, 4, 5])
#|}
#|test "quick_sort with pred less than all elements" {
#| let arr = [5, 4, 3, 2, 1]
#| quick_sort(arr[:], Some(0), 0)
#| assert_eq(arr, [1, 2, 3, 4, 5])
#|}
#|test "quick_sort with pred greater than all elements" {
#| let arr = [5, 4, 3, 2, 1]
#| quick_sort(arr[:], Some(6), 0)
#| assert_eq(arr, [1, 2, 3, 4, 5])
#|}
),
"sort_by.mbt": (
#|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()),
#| )
#|}
#|pub fn[T] sort_by(self : Array[T], cmp : (T, T) -> Int) -> Unit {
#| quick_sort_by(self[:], cmp, None, get_limit(self.length()))
#|}
#|fn[T] quick_sort_by(
#| arr : ArrayView[T],
#| cmp : (T, T) -> Int,
#| 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 bubble_sort_len = 16
#| while true {
#| let len = arr.length()
#| if len <= bubble_sort_len {
#| if len >= 2 {
#| bubble_sort_by(arr, cmp)
#| }
#| return
#| }
#| if limit == 0 {
#| heap_sort_by(arr, cmp)
#| return
#| }
#| let (pivot_index, likely_sorted) = choose_pivot_by(arr, cmp)
#| if was_partitioned && balanced && likely_sorted {
#| if try_bubble_sort_by(arr, cmp) {
#| return
#| }
#| }
#| let (pivot, partitioned) = partition_by(arr, cmp, pivot_index)
#| was_partitioned = partitioned
#| balanced = minimum(pivot, len - pivot) >= len / 8
#| if !balanced {
#| limit -= 1
#| }
#| if pred is Some(pred) {
#| if cmp(pred, arr[pivot]) == 0 {
#| let mut i = pivot
#| while i < len && cmp(pred, arr[i]) == 0 {
#| i = i + 1
#| }
#| arr = arr[i:len]
#| continue
#| }
#| }
#| let left = arr[0:pivot]
#| let right = arr[pivot + 1:len]
#| if left.length() < right.length() {
#| quick_sort_by(left, cmp, pred, limit)
#| pred = Some(arr[pivot])
#| arr = right
#| } else {
#| quick_sort_by(right, cmp, Some(arr[pivot]), limit)
#| arr = left
#| }
#| }
#|}
#|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
#|}
#|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)
#| }
#| }
#|}
#|fn[T] partition_by(
#| arr : ArrayView[T],
#| cmp : (T, T) -> Int,
#| 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 cmp(arr[j], pivot) < 0 {
#| if i != j {
#| arr.swap(i, j)
#| partitioned = false
#| }
#| i = i + 1
#| }
#| }
#| arr.swap(i, arr.length() - 1)
#| (i, partitioned)
#|}
#|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)
#| }
#|}
#|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)
#| }
#|}
#|fn[T] sift_down_by(
#| arr : ArrayView[T],
#| index : Int,
#| cmp : (T, T) -> Int,
#|) -> Unit {
#| let mut index = index
#| let len = arr.length()
#| let mut child = index * 2 + 1
#| while child < len {
#| if child + 1 < len && cmp(arr[child], arr[child + 1]) < 0 {
#| child = child + 1
#| }
#| if cmp(arr[index], arr[child]) >= 0 {
#| return
#| }
#| arr.swap(index, child)
#| index = child
#| child = index * 2 + 1
#| }
#|}
#|test "try_bubble_sort" {
#| let arr = [8, 7, 6, 5, 4, 3, 2, 1]
#| let sorted = try_bubble_sort_by(arr[0:8], (a, b) => a - b)
#| inspect(sorted, content="true")
#| assert_eq(arr, [1, 2, 3, 4, 5, 6, 7, 8])
#|}
#|test "heap_sort" {
#| test_sort(arr => heap_sort_by(arr[:], (a, b) => a - b))
#|}
#|test "bubble_sort" {
#| test_sort(arr => bubble_sort_by(arr[:], (a, b) => a - b))
#|}
#|test "sort_by_key" {
#| let arr = [5, 1, 3, 4, 2]
#| arr.sort_by_key(x => -x)
#| assert_eq(arr, [5, 4, 3, 2, 1])
#|}
#|test "sort_by" {
#| test_sort(arr => arr.sort_by((a, b) => a - b))
#|}
),
"utils.mbt": (
#|fn minimum(x : Int, y : Int) -> Int {
#| if x > y {
#| y
#| } else {
#| x
#| }
#|}
),
"view.mbt": (
#|pub typealias ArrayView as View
#|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)
#| }
#|}
#|pub fn[T] View::eachi(
#| self : View[T],
#| f : (Int, T) -> Unit raise?,
#|) -> Unit raise? {
#| for i, v in self {
#| f(i, v)
#| }
#|}
#|pub fn[T] View::all(self : View[T], f : (T) -> Bool raise?) -> Bool raise? {
#| for v in self {
#| if !f(v) {
#| return false
#| }
#| }
#| true
#|}
#|pub fn[T] View::any(self : View[T], f : (T) -> Bool raise?) -> Bool raise? {
#| for v in self {
#| if f(v) {
#| return true
#| }
#| }
#| false
#|}
#|pub fn[T : Eq] View::contains(self : View[T], value : T) -> Bool {
#| for v in self {
#| if v == value {
#| break true
#| }
#| } else {
#| false
#| }
#|}
#|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
#| })
#|}
#|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
#| })
#|}
#|pub fn[A, B] View::fold(
#| self : View[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for i = 0, acc = init; i < self.length(); {
#| continue i + 1, f(acc, self[i])
#| } else {
#| acc
#| }
#|}
#|pub fn[A, B] View::rev_fold(
#| self : View[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for i = self.length() - 1, acc = init; i >= 0; {
#| continue i - 1, f(acc, self[i])
#| } else {
#| acc
#| }
#|}
#|pub fn[A, B] View::foldi(
#| self : View[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| for i = 0, acc = init; i < self.length(); {
#| continue i + 1, f(i, acc, self[i])
#| } else {
#| acc
#| }
#|}
#|pub fn[A, B] View::rev_foldi(
#| self : View[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| let len = self.length()
#| for i = len - 1, acc = init; i >= 0; {
#| continue i - 1, f(len - i - 1, acc, self[i])
#| } else {
#| acc
#| }
#|}
#|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]))
#|}
#|pub fn[T] View::map_inplace(self : View[T], f : (T) -> T raise?) -> Unit raise? {
#| for i, v in self {
#| self[i] = f(v)
#| }
#|}
#|pub fn[T, U] View::mapi(
#| self : View[T],
#| f : (Int, T) -> U raise?,
#|) -> Array[U] raise? {
#| if self.length() == 0 {
#| return []
#| }
#| Array::makei(self.length(), i => f(i, self[i]))
#|}
#|pub fn[T] View::mapi_inplace(
#| self : View[T],
#| f : (Int, T) -> T raise?,
#|) -> Unit raise? {
#| for i, v in self {
#| self[i] = f(i, v)
#| }
#|}
#|pub fn[T] View::filter(
#| self : View[T],
#| f : (T) -> Bool raise?,
#|) -> Array[T] raise? {
#| let arr = []
#| for v in self {
#| if f(v) {
#| arr.push(v)
#| }
#| }
#| arr
#|}
#|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
#| }
#|}
#|pub fn[A : @string.ToStringView] View::join(
#| self : ArrayView[A],
#| separator : @string.View,
#|) -> String {
#| match self {
#| [] => ""
#| [hd, .. tl] => {
#| let hd = hd.to_string_view()
#| let mut size_hint = hd.length()
#| for s in tl {
#| size_hint += s.to_string_view().length() + separator.length()
#| }
#| size_hint = size_hint << 1
#| let buf = StringBuilder::new(size_hint~)
#| buf.write_substring(hd.data(), hd.start_offset(), hd.length())
#| if separator is "" {
#| for s in tl {
#| let s = s.to_string_view()
#| buf.write_substring(s.data(), s.start_offset(), s.length())
#| }
#| } else {
#| for s in tl {
#| let s = s.to_string_view()
#| buf.write_substring(
#| separator.data(),
#| separator.start_offset(),
#| separator.length(),
#| )
#| buf.write_substring(s.data(), s.start_offset(), s.length())
#| }
#| }
#| buf.to_string()
#| }
#| }
#|}
#|pub impl[X : Show] Show for View[X] with output(self, logger) {
#| logger.write_iter(self.iter())
#|}
#|pub impl[T : Eq] Eq for View[T] with equal(self, other) -> Bool {
#| if self.length() != other.length() {
#| return false
#| }
#| for i in 0.. Int {
#| let len_self = self.length()
#| let len_other = other.length()
#| let cmp = len_self.compare(len_other)
#| guard cmp == 0 else { return cmp }
#| for i 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)
#|}
#|pub fn bench(
#| self : T,
#| name? : String,
#| f : () -> Unit,
#| count? : UInt = 10,
#|) -> Unit {
#| let summary = iter_count(name?, f, count)
#| if !self.buffer.is_empty() {
#| self.buffer.write_char(',')
#| }
#| self.buffer.write_string(summary.to_json().stringify(escape_slash=true))
#| self.summaries.push(summary)
#|}
#|pub fn single_bench(
#| name? : String,
#| f : () -> Unit,
#| count? : UInt = 10,
#|) -> Summary {
#| iter_count(name?, f, count)
#|}
#|pub fn[Any] keep(self : T, value : Any) -> Unit {
#| let trait_object : &OpaqueValue = value
#| self._storage = trait_object
#|}
#|#coverage.skip
#|pub fn dump_summaries(self : T) -> String {
#| "[\{self.buffer.to_string()}]"
#|}
#|test "bench - single_bench basic functionality" {
#| let bench_result = single_bench(
#| () => {
#| let x = 1 + 1
#| ignore(x)
#| },
#| count=2,
#| )
#| inspect(bench_result.runs, content="2")
#| inspect(bench_result.batch_size > 0, content="true")
#| inspect(bench_result.sum > 0.0, content="true")
#| inspect(bench_result.min <= bench_result.max, content="true")
#|}
#|test "bench - Summary struct properties" {
#| let bench_result = single_bench(
#| () => {
#| let x = 1
#| ignore(x)
#| },
#| count=5,
#| )
#| inspect(bench_result.mean >= 0, content="true")
#| inspect(bench_result.median >= 0, content="true")
#| inspect(bench_result.std_dev >= 0, content="true")
#| inspect(bench_result.std_dev_pct >= 0, content="true")
#| inspect(bench_result.median_abs_dev >= 0, content="true")
#| inspect(bench_result.median_abs_dev_pct >= 0, content="true")
#| let (q1, q2, q3) = bench_result.quartiles
#| inspect(q1 <= q2, content="true")
#| inspect(q2 <= q3, content="true")
#| inspect((q3 - q1 - bench_result.iqr).abs() < 0.001, content="true")
#|}
#|test "bench - T struct and bench method" {
#| let bench_obj = new()
#| inspect(bench_obj.buffer.is_empty(), content="true")
#| inspect(bench_obj.summaries.is_empty(), content="true")
#| bench_obj.bench(
#| () => {
#| let x = 20 * 20
#| ignore(x)
#| },
#| count=2,
#| )
#| inspect(bench_obj.buffer.is_empty(), content="false")
#| inspect(bench_obj.summaries.length(), content="1")
#| bench_obj.bench(
#| () => {
#| let y = 30 * 30
#| ignore(y)
#| },
#| count=2,
#| )
#| inspect(bench_obj.summaries.length(), content="2")
#|}
#|test "bench - monotonic clock functionality" {
#| let start = monotonic_clock_start()
#| let mut result = 0
#| for _ in 0..<1000 {
#| result += 1
#| }
#| ignore(result)
#| let elapsed = monotonic_clock_end(start)
#| inspect(elapsed >= 0.0, content="true")
#|}
#|test "bench - keep stores value" {
#| let b = new()
#| assert_eq(b.summaries.length(), 0)
#| b.keep(123)
#| assert_eq(b.summaries.length(), 0)
#| b.keep(456)
#| assert_eq(b.summaries.length(), 0)
#|}
),
"monotonic_clock_js.mbt": (
#|type Timestamp
#|pub extern "js" fn monotonic_clock_start() -> Timestamp =
#| #| () => performance.now()
#|pub extern "js" fn monotonic_clock_end(ts : Timestamp) -> Double =
#| #| (ts) => (performance.now() - ts) * 1000.0
),
"monotonic_clock_native.mbt": (
#|#external
#|type Timestamp
#|pub extern "C" fn monotonic_clock_start() -> Timestamp = "moonbit_monotonic_clock_start"
#|pub extern "C" fn monotonic_clock_end(ts : Timestamp) -> Double = "moonbit_monotonic_clock_stop"
),
"monotonic_clock_wasm.mbt": (
#|#external
#|type Timestamp
#|fn instant_elapsed_as_secs_f64(x : Timestamp) -> Double = "__moonbit_time_unstable" "instant_elapsed_as_secs_f64"
#|pub fn monotonic_clock_start() -> Timestamp = "__moonbit_time_unstable" "instant_now"
#|pub fn monotonic_clock_end(ts : Timestamp) -> Double {
#| let elapsed_secs : Double = instant_elapsed_as_secs_f64(ts)
#| elapsed_secs * 1000000.0
#|}
),
"stats.mbt": (
#|struct Summary {
#| name : String?
#| sum : Double
#| min : Double
#| max : Double
#| mean : Double
#| median : Double
#| variance : Double
#| std_dev : Double
#| std_dev_pct : Double
#| median_abs_dev : Double
#| median_abs_dev_pct : Double
#| quartiles : (Double, Double, Double)
#| iqr : Double
#| batch_size : Int
#| runs : Int
#|} derive(ToJson)
#|fn Summary::new(
#| name? : String,
#| sorted_data~ : Array[Double],
#| batch_size : Int,
#|) -> Summary {
#| let sum = sum(sorted_data)
#| let min = min(sorted_data~)
#| let max = max(sorted_data~)
#| let mean = mean(sorted_data, sum~)
#| let median = median(sorted_data~)
#| let variance = variance(sorted_data, mean~)
#| let std_dev = std_dev(variance~)
#| let std_dev_pct = std_dev_pct(mean~, std_dev~)
#| let median_abs_dev = median_abs_dev(sorted_data, median_=median)
#| let median_abs_dev_pct = median_abs_dev_pct(median~, median_abs_dev~)
#| let quartiles = quartiles(sorted_data~)
#| let iqr = iqr(quartiles~)
#| {
#| name,
#| sum,
#| min,
#| max,
#| mean,
#| median,
#| variance,
#| std_dev,
#| std_dev_pct,
#| median_abs_dev,
#| median_abs_dev_pct,
#| quartiles,
#| iqr,
#| batch_size,
#| runs: sorted_data.length(),
#| }
#|}
#|fn sum(data : Array[Double]) -> Double {
#| let mut sum = 0.0
#| for i in data {
#| sum += i
#| }
#| sum
#|}
#|fn min(sorted_data~ : Array[Double]) -> Double {
#| sorted_data[0]
#|}
#|fn max(sorted_data~ : Array[Double]) -> Double {
#| sorted_data[sorted_data.length() - 1]
#|}
#|fn mean(data : Array[Double], sum~ : Double) -> Double {
#| let count = data.length()
#| sum / count.to_double()
#|}
#|fn median(sorted_data~ : Array[Double]) -> Double {
#| percentile(sorted_data~, pct=50.0)
#|}
#|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()
#|}
#|fn std_dev(variance~ : Double) -> Double {
#| variance.sqrt()
#|}
#|fn std_dev_pct(mean~ : Double, std_dev~ : Double) -> Double {
#| if mean == 0.0 {
#| return 0.0
#| }
#| std_dev / mean * 100.0
#|}
#|fn median_abs_dev(data : Array[Double], median_~ : Double) -> Double {
#| let abs_devs = data.map(x => (median_ - x).abs())
#| abs_devs.sort()
#| median(sorted_data=abs_devs) * 1.4826
#|}
#|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
#|}
#|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)
#|}
#|fn iqr(quartiles~ : (Double, Double, Double)) -> Double {
#| let (q1, _, q3) = quartiles
#| q3 - q1
#|}
#|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
#|}
#|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
#| }
#| }
#|}
#|test {
#| let data = [1.1, 21.4, 2.2, 3.3, 4.5, 12.5, 33.3, 14.4]
#| data.sort()
#| let summary = Summary::new(sorted_data=data, 3)
#| assert_true(summary.sum.is_close(92.7))
#| assert_true(summary.min.is_close(1.1))
#| assert_true(summary.max.is_close(33.3))
#| assert_true(summary.mean.is_close(11.5875))
#| assert_true(summary.median.is_close(8.5))
#| assert_true(summary.variance.is_close(127.64125))
#| assert_true(summary.std_dev.is_close(11.297842714430043))
#| assert_true(summary.std_dev_pct.is_close(97.50026075020534))
#| assert_true(summary.median_abs_dev.is_close(9.04386))
#| assert_true(summary.median_abs_dev_pct.is_close(106.39835294117646))
#| let (q1, q2, q3) = summary.quartiles
#| assert_true(q1.is_close(3.025))
#| assert_true(q2.is_close(8.5))
#| assert_true(q3.is_close(16.15))
#| assert_true(summary.iqr.is_close(13.125))
#| assert_true(summary.batch_size == 3)
#| assert_true(summary.runs == 8)
#| @json.inspect(summary, content={
#| "sum": 92.69999999999999,
#| "min": 1.1,
#| "max": 33.3,
#| "mean": 11.587499999999999,
#| "median": 8.5,
#| "variance": 127.64124999999999,
#| "std_dev": 11.297842714430042,
#| "std_dev_pct": 97.50026075020534,
#| "median_abs_dev": 9.043859999999999,
#| "median_abs_dev_pct": 106.39835294117646,
#| "quartiles": [3.025, 8.5, 16.15],
#| "iqr": 13.124999999999998,
#| "batch_size": 3,
#| "runs": 8,
#| })
#|}
#|test "std_dev_pct zero mean" {
#| assert_eq(std_dev_pct(mean=0.0, std_dev=5.0), 0.0)
#|}
#|test "median_abs_dev_pct zero median" {
#| assert_eq(median_abs_dev_pct(median=0.0, median_abs_dev=3.0), 0.0)
#|}
#|test "percentile edge cases" {
#| assert_eq(percentile(sorted_data=[42.0], pct=50.0), 42.0)
#| assert_eq(percentile(sorted_data=[1.0, 2.0, 3.0], pct=100.0), 3.0)
#|}
),
"types.mbt": (
#|priv trait OpaqueValue {}
#|struct T {
#| buffer : StringBuilder
#| summaries : Array[Summary]
#| mut _storage : &OpaqueValue
#|}
#|pub fn new() -> T {
#| let buffer = StringBuilder::new()
#| let summaries = Array::new()
#| { buffer, summaries, _storage: () }
#|}
),
},
)
///|
let moonbitlang_core_bigint_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/char",
#| "moonbitlang/core/uint",
#| "moonbitlang/core/json",
#| "moonbitlang/core/quickcheck",
#| "moonbitlang/core/quickcheck/splitmix",
#| "moonbitlang/core/string"
#| ],
#| "targets": {
#| "bigint_js.mbt": ["js"],
#| "bigint_nonjs.mbt": ["not", "js"],
#| "bigint_js_wbtest.mbt": ["js"],
#| "bigint_nonjs_wbtest.mbt": ["not", "js"]
#| },
#| "warn-list": "-29"
#|}
),
"bigint.mbt": (
#|pub impl ToJson for BigInt with to_json(self : BigInt) -> Json {
#| Json::string(self.to_string())
#|}
#|pub impl @json.FromJson for BigInt with from_json(json, path) {
#| guard json is String(s) else {
#| raise @json.JsonDecodeError(
#| (path, "BigInt::from_json: expected number in string representation"),
#| )
#| }
#| BigInt::from_string(s)
#|}
#|pub impl @quickcheck.Arbitrary for BigInt with arbitrary(size, rs) {
#| if size == 0 {
#| 0
#| } else {
#| rs.next_int64() |> BigInt::from_int64
#| }
#|}
#|pub impl Default for BigInt with default() {
#| zero
#|}
#|pub fn BigInt::equal_int(self : BigInt, other : Int) -> Bool {
#| can_convert_to_int(self) && self.to_int() == other
#|}
#|pub fn BigInt::equal_int64(self : BigInt, other : Int64) -> Bool {
#| can_convert_to_int64(self) && self.to_int64() == other
#|}
#|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)
#|}
#|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)
#|}
#|test "can_convert_to_int" {
#| assert_true(can_convert_to_int(0N))
#| assert_true(can_convert_to_int(1N))
#| assert_true(can_convert_to_int(-1N))
#| assert_true(can_convert_to_int(2147483647N)) // Int.max_value
#| assert_true(can_convert_to_int(-2147483648N)) // Int.min_value
#| assert_false(can_convert_to_int(2147483648N)) // Int.max_value + 1
#| assert_false(can_convert_to_int(-2147483649N)) // Int.min_value - 1
#| assert_false(can_convert_to_int(4294967295N)) // 2^32 - 1
#| assert_false(can_convert_to_int(-4294967295N)) // -(2^32 - 1)
#| assert_false(can_convert_to_int(4294967296N)) // 2^32
#| assert_false(can_convert_to_int(-4294967296N)) // -2^32
#|}
#|test "can_convert_to_int64" {
#| assert_true(can_convert_to_int64(0N))
#| assert_true(can_convert_to_int64(1N))
#| assert_true(can_convert_to_int64(-1N))
#| assert_true(can_convert_to_int64(2147483647N)) // Int.max_value
#| assert_true(can_convert_to_int64(-2147483648N)) // Int.min_value
#| assert_true(can_convert_to_int64(2147483648N)) // Int.max_value + 1
#| assert_true(can_convert_to_int64(-2147483649N)) // Int.min_value - 1
#| assert_true(can_convert_to_int64(4294967295N)) // 2^32 - 1
#| assert_true(can_convert_to_int64(-4294967295N)) // -(2^32 - 1)
#| assert_true(can_convert_to_int64(4294967296N)) // 2^32
#| assert_true(can_convert_to_int64(-4294967296N)) // -2^32
#| assert_true(can_convert_to_int64(9223372036854775807N)) // Int64.max_value
#| assert_true(can_convert_to_int64(-9223372036854775808N)) // Int64.min_value
#| assert_false(can_convert_to_int64(9223372036854775808N)) // Int64.max_value + 1
#| assert_false(can_convert_to_int64(-9223372036854775809N)) // Int64.min_value - 1
#| assert_false(can_convert_to_int64(18446744073709551615N)) // 2^64 - 1
#| assert_false(can_convert_to_int64(-18446744073709551615N)) // -(2^64 - 1)
#| assert_false(can_convert_to_int64(18446744073709551616N)) // 2^64
#| assert_false(can_convert_to_int64(-18446744073709551616N)) // -2^64
#|}
#|pub impl Hash for BigInt with hash_combine(self, hasher) {
#| hasher.combine(self.signum())
#| for limb in self.limbs() {
#| hasher.combine(limb)
#| }
#|}
#|fn BigInt::signum(self : Self) -> Int {
#| if self.is_zero() {
#| 0
#| } else if is_neg(self) {
#| -1
#| } else {
#| 1
#| }
#|}
#|pub fn BigInt::to_uint16(self : BigInt) -> UInt16 {
#| self.to_int().to_uint16()
#|}
#|pub fn BigInt::to_int16(self : BigInt) -> Int16 {
#| self.to_int().to_int16()
#|}
),
"bigint_js.mbt": (
#|type BigInt
#|let zero = 0N
#|pub fn BigInt::from_string(str : String) -> BigInt {
#| if str.length() == 0 {
#| abort("empty string")
#| }
#| BigInt::js_from_string(str)
#|}
#|extern "js" fn BigInt::js_from_string(str : String) -> BigInt =
#| #|(x) => BigInt(x)
#|pub impl Show for BigInt with output(self, logger) {
#| logger.write_string(self.to_string())
#|}
#|pub extern "js" fn BigInt::to_string(self : BigInt) -> String =
#| #|(x) => String(x)
#|pub extern "js" fn BigInt::from_hex(str : String) -> BigInt =
#| #|(x) => x.startsWith('-') ? -BigInt(`0x${x.slice(1)}`) : BigInt(`0x${x}`)
#|pub extern "js" fn BigInt::to_hex(
#| self : BigInt,
#| uppercase? : Bool = true,
#|) -> String =
#| #|(x, uppercase) => {
#| #| const r = x.toString(16);
#| #| return uppercase ? r.toUpperCase() : r;
#| #|}
#|extern "js" fn hex2(b : Byte) -> String =
#| #|(x) => x.toString(16).padStart(2, '0')
#|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())
#|}
#|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])
#| }
#|}
#|extern "js" fn BigInt::compare(self : BigInt, other : BigInt) -> Int =
#| #|(x, y) => x < y ? -1 : x > y ? 1 : 0
#|pub impl Compare for BigInt with compare(self, other) {
#| self.compare(other)
#|}
#|extern "js" fn BigInt::equal(self : BigInt, other : BigInt) -> Bool =
#| #|(x, y) => x === y
#|pub impl Eq for BigInt with equal(self, other) {
#| self.equal(other)
#|}
#|pub extern "js" fn BigInt::from_int(x : Int) -> BigInt =
#| #|(x) => BigInt(x)
#|pub extern "js" fn BigInt::from_uint(x : UInt) -> BigInt =
#| #|(x) => BigInt(x >>> 0)
#|pub extern "js" fn BigInt::from_int64(x : Int64) -> BigInt =
#| #|(x) => BigInt(x.hi) * 0x100000000n + BigInt(x.lo >>> 0)
#|pub extern "js" fn BigInt::from_uint64(x : UInt64) -> BigInt =
#| #|(x) => BigInt(x.hi >>> 0) * 0x100000000n + BigInt(x.lo >>> 0)
#|pub extern "js" fn BigInt::is_zero(self : BigInt) -> Bool =
#| #|(x) => x === 0n
#|extern "js" fn BigInt::op_neg_ffi(self : BigInt) -> BigInt =
#| #|(x) => -x
#|pub impl Neg for BigInt with neg(self) {
#| self.op_neg_ffi()
#|}
#|extern "js" fn BigInt::op_add_ffi(self : BigInt, other : BigInt) -> BigInt =
#| #|(x, y) => x + y
#|pub impl Add for BigInt with add(self, other) {
#| self.op_add_ffi(other)
#|}
#|extern "js" fn BigInt::op_sub_ffi(self : BigInt, other : BigInt) -> BigInt =
#| #|(x, y) => x - y
#|pub impl Sub for BigInt with sub(self, other) {
#| self.op_sub_ffi(other)
#|}
#|extern "js" fn BigInt::op_mul_ffi(self : BigInt, other : BigInt) -> BigInt =
#| #|(x, y) => x * y
#|pub impl Mul for BigInt with mul(self, other) {
#| self.op_mul_ffi(other)
#|}
#|extern "js" fn BigInt::op_div_ffi(self : BigInt, other : BigInt) -> BigInt =
#| #|(x, y) => x / y
#|pub impl Div for BigInt with div(self, other) {
#| self.op_div_ffi(other)
#|}
#|extern "js" fn BigInt::op_mod_ffi(self : BigInt, other : BigInt) -> BigInt =
#| #|(x, y) => x % y
#|pub impl Mod for BigInt with mod(self, other) {
#| self.op_mod_ffi(other)
#|}
#|extern "js" fn BigInt::modpow_ffi(
#| self : BigInt,
#| exponent : BigInt,
#| modulus : BigInt,
#|) -> BigInt =
#| #|(x, y, z) => {
#| #| if (z === 1n) return 0n;
#| #| let result = 1n;
#| #| x = x % z;
#| #| while (y > 0n) {
#| #| if (y & 1n) {
#| #| result = (result * x) % z;
#| #| }
#| #| y >>= 1n;
#| #| x = (x * x) % z;
#| #| }
#| #| return result;
#| #|}
#|extern "js" fn BigInt::pow_ffi(self : BigInt, exponent : BigInt) -> BigInt =
#| #|(x, y) => x ** y
#|pub fn BigInt::pow(
#| self : BigInt,
#| exponent : BigInt,
#| modulus? : BigInt,
#|) -> BigInt {
#| if exponent < 0 {
#| abort("negative exponent")
#| }
#| match modulus {
#| Some(modulus) =>
#| if modulus <= 0 {
#| abort("non-positive modulus")
#| } else {
#| self.modpow_ffi(exponent, modulus)
#| }
#| None => self.pow_ffi(exponent)
#| }
#|}
#|extern "js" fn BigInt::to_byte(self : BigInt) -> Byte =
#| #|(x) => Number(BigInt.asUintN(8, x)) | 0
#|pub impl Shl for BigInt with shl(self : BigInt, n : Int) -> BigInt {
#| if n < 0 {
#| abort("negative shift count")
#| }
#| self.js_shl(n)
#|}
#|pub impl Shr for BigInt with shr(self : BigInt, n : Int) -> BigInt {
#| if n < 0 {
#| abort("negative shift count")
#| }
#| self.js_shr(n)
#|}
#|extern "js" fn BigInt::js_shl(self : BigInt, other : Int) -> BigInt =
#| #|(x, y) => x << BigInt(y)
#|extern "js" fn BigInt::js_shr(self : BigInt, other : Int) -> BigInt =
#| #|(x, y) => x >> BigInt(y)
#|extern "js" fn BigInt::js_land(self : BigInt, other : BigInt) -> BigInt =
#| #|(x, y) => x & y
#|pub impl BitAnd for BigInt with land(self, other) {
#| self.js_land(other)
#|}
#|extern "js" fn BigInt::js_lor(self : BigInt, other : BigInt) -> BigInt =
#| #|(x, y) => x | y
#|pub impl BitOr for BigInt with lor(self, other) {
#| self.js_lor(other)
#|}
#|extern "js" fn BigInt::js_lxor(self : BigInt, other : BigInt) -> BigInt =
#| #|(x, y) => x ^ y
#|pub impl BitXOr for BigInt with lxor(self, other) {
#| self.js_lxor(other)
#|}
#|pub extern "js" fn BigInt::to_uint(self : BigInt) -> UInt =
#| #|(x) => Number(BigInt.asUintN(32, x)) | 0
#|pub extern "js" fn BigInt::to_int(self : BigInt) -> Int =
#| #|(x) => Number(BigInt.asIntN(32, x))
#|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()
#|}
#|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()
#|}
#|pub extern "js" fn BigInt::bit_length(self : BigInt) -> Int =
#| #|(n) => {
#| #| if (n >= 0) {
#| #| return n === 0n ? 0 : n.toString(2).length;
#| #| } else {
#| #| const absN = -n;
#| #| const absMinus1 = absN - 1n;
#| #| return absMinus1 === 0n ? 0 : absMinus1.toString(2).length;
#| #| }
#| #|}
#|pub extern "js" fn BigInt::ctz(self : BigInt) -> Int =
#| #|(n) => {
#| #| if (n === 0n) return 0;
#| #| let absN = n < 0n ? -n : n;
#| #| let count = 0;
#| #| while ((absN & 1n) === 0n) {
#| #| absN >>= 1n;
#| #| count++;
#| #| }
#| #| return count;
#| #|}
#|extern "js" fn can_convert_to_int(x : BigInt) -> Bool =
#| #|(x) => x >= -(2n ** 31n) && x < 2n ** 31n
#|extern "js" fn can_convert_to_int64(x : BigInt) -> Bool =
#| #|(x) => x >= -(2n ** 63n) && x < 2n ** 63n
#|extern "js" fn is_neg(x : BigInt) -> Bool =
#| #|(x) => x < 0n
#|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
#| })
#|}
),
"bigint_nonjs.mbt": (
#|struct BigInt {
#| limbs : FixedArray[UInt] // Note: do not use limbs.length(), use len instead because of leading zeros
#| sign : Sign
#| len : Int
#|}
#|priv enum Sign {
#| Positive
#| Negative
#|} derive(Eq)
#|let radix_bit_len = 32
#|let radix : UInt64 = 1UL << radix_bit_len // TODO: This can be generalized once we have const generics
#|let radix_mask : UInt64 = radix - 1
#|let decimal_ratio = 0.302 // log10(2)
#|let karatsuba_threshold = 50
#|let zero : BigInt = 0N
#|let one : BigInt = 1N
#|pub fn BigInt::from_int(n : Int) -> BigInt {
#| BigInt::from_int64(n.to_int64())
#|}
#|pub fn BigInt::from_uint(n : UInt) -> BigInt {
#| BigInt::from_uint64(n.to_uint64())
#|}
#|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())
#| }
#|}
#|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 }
#|}
#|pub impl Neg for BigInt with neg(self : BigInt) -> BigInt {
#| if self.is_zero() {
#| return zero
#| }
#| { ..self, sign: if self.sign == Positive { Negative } else { Positive } }
#|}
#|pub impl Add for BigInt with add(self : BigInt, other : BigInt) -> BigInt {
#| if self.sign == Negative {
#| if other.sign == Negative {
#| return -(-other + -self)
#| } else {
#| return other - -self
#| }
#| } else if other.sign == Negative {
#| return self - -other
#| }
#| let self_len = self.len
#| let other_len = other.len
#| let limbs = FixedArray::make(1 + max(self_len, other_len), 0U)
#| let mut carry = 0UL
#| let mut i = 0
#| while i < self_len || i < other_len || carry != 0 {
#| let a = if i < self_len { self.limbs[i].to_uint64() } else { 0 }
#| let b = if i < other_len { other.limbs[i].to_uint64() } else { 0 }
#| let sum = a + b + carry
#| limbs[i] = (sum % radix).to_uint()
#| carry = sum / radix
#| i += 1
#| }
#| { limbs, sign: Positive, len: i }
#|}
#|pub impl Sub for BigInt with sub(self : BigInt, other : BigInt) -> BigInt {
#| if self.sign == Negative {
#| if other.sign == Negative {
#| return -other - -self
#| } else {
#| return -(other + -self)
#| }
#| } else if other.sign == Negative {
#| return self + -other
#| }
#| if self < other {
#| return -(other - self)
#| }
#| let self_len = self.len
#| let other_len = other.len
#| let limbs = FixedArray::make(max(self_len, other_len), 0U)
#| let mut borrow = 0L
#| let mut i = 0
#| while i < self_len || i < other_len || borrow != 0L {
#| let a = if i < self_len { self.limbs[i].to_int64() } else { 0 }
#| let b = if i < other_len { other.limbs[i].to_int64() } else { 0 }
#| let diff = a - b - borrow // 0 <= a < radix, 0 <= b < radix, 0 <= borrow <= 1 => -radix <= diff < radix
#| if diff < 0L {
#| limbs[i] = (diff + radix.reinterpret_as_int64())
#| .reinterpret_as_uint64()
#| .to_uint() // -radix <= diff < 0, so we don't need to mod by radix
#| borrow = 1L
#| } else {
#| limbs[i] = diff.reinterpret_as_uint64().to_uint() // 0 <= diff < radix, so we don't need to mod by radix
#| borrow = 0L
#| }
#| i += 1
#| }
#| while i > 1 && limbs[i - 1] == 0 {
#| i -= 1
#| }
#| { limbs, sign: Positive, len: i }
#|}
#|pub impl Mul for BigInt with mul(self : BigInt, other : BigInt) -> BigInt {
#| if self.is_zero() || other.is_zero() {
#| return zero
#| }
#| let ret = if self.len < karatsuba_threshold || other.len < karatsuba_threshold {
#| self.grade_school_mul(other)
#| } else {
#| self.karatsuba_mul(other)
#| }
#| { ..ret, sign: if self.sign == other.sign { Positive } else { Negative } }
#|}
#|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
#|}
#|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 },
#| )
#|}
#|pub impl Div for BigInt with div(self : BigInt, other : BigInt) -> BigInt {
#| if other is 0 {
#| abort("division by zero")
#| }
#| if self.sign == Negative {
#| if other.sign == Negative {
#| BigInt::grade_school_div(-self, -other).0
#| } else {
#| -BigInt::grade_school_div(-self, other).0
#| }
#| } else if other.sign == Negative {
#| -BigInt::grade_school_div(self, -other).0
#| } else {
#| return BigInt::grade_school_div(self, other).0
#| }
#|}
#|pub impl Mod for BigInt with mod(self : BigInt, other : BigInt) -> BigInt {
#| if other == zero {
#| abort("division by zero")
#| }
#| if self.sign == Negative {
#| if other.sign == Negative {
#| -BigInt::grade_school_div(-self, -other).1
#| } else {
#| -BigInt::grade_school_div(-self, other).1
#| }
#| } else if other.sign == Negative {
#| BigInt::grade_school_div(self, -other).1
#| } else {
#| BigInt::grade_school_div(self, other).1
#| }
#|}
#|fn BigInt::grade_school_div(self : BigInt, other : BigInt) -> (BigInt, BigInt) {
#| 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 },
#| )
#| }
#| let dividend = self
#| let divisor = other
#| 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()
#| }
#| }
#| let a_len = a_len + 1
#| let v1 = b[b_len - 1]
#| let v2 = b[b_len - 2]
#| let q = FixedArray::make(a_len - b_len, 0U)
#| 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]
#| let mut qh = (u0 * radix + u1) / v1
#| if qh * v2 > radix * (u0 * radix + u1 - qh * v1) + u2 {
#| qh -= 1
#| }
#| 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() }
#| 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)
#|}
#|pub impl Shl for BigInt with shl(self : BigInt, n : Int) -> BigInt {
#| if n < 0 {
#| abort("negative shift count")
#| }
#| if !self.is_zero() {
#| let new_limbs = FixedArray::make(
#| self.len + (n + radix_bit_len - 1) / radix_bit_len, // ceiling(n / radix_bit_len)
#| 0U,
#| )
#| let a = self.limbs
#| let r = n % radix_bit_len
#| let lz = n / radix_bit_len // number of leading zeros
#| let mut len = self.len + lz
#| if r != 0 {
#| let mut carry = 0UL
#| for i in 0..> radix_bit_len
#| }
#| if carry != 0 {
#| new_limbs[self.len + lz] = carry.to_uint()
#| len += 1
#| }
#| } else {
#| new_limbs.unsafe_blit(lz, self.limbs, 0, self.len)
#| }
#| { limbs: new_limbs, sign: self.sign, len }
#| } else {
#| zero
#| }
#|}
#|pub impl Shr for BigInt with shr(self : BigInt, n : Int) -> BigInt {
#| if n < 0 {
#| abort("negative shift count")
#| }
#| let r = n % radix_bit_len
#| let lz = n / radix_bit_len
#| if lz >= self.len {
#| match self.sign {
#| Positive => return zero
#| Negative =>
#| return { limbs: FixedArray::make(1, 1), sign: Negative, len: 1 }
#| }
#| }
#| let mut new_len = self.len - lz
#| if r == 0 {
#| let new_limbs = FixedArray::make(new_len, 0U)
#| new_limbs.unsafe_blit(0, self.limbs, lz, new_len)
#| { limbs: new_limbs, sign: self.sign, len: new_len }
#| } else {
#| let new_limbs = FixedArray::make(new_len, 0U)
#| let a = self.limbs
#| let mut carry = 0UL
#| for i = self.len - 1; i >= lz; i = i - 1 {
#| let x = a[i].to_uint64()
#| new_limbs[i - lz] = ((x >> r) | carry).to_uint()
#| carry = (x << (radix_bit_len - r)) % radix
#| }
#| if new_len > 1 && new_limbs[new_len - 1] == 0 {
#| new_len -= 1
#| }
#| if self.sign == Negative && (carry & (1UL << r)) != carry {
#| { limbs: new_limbs, sign: self.sign, len: new_len } - 1
#| } else {
#| { limbs: new_limbs, sign: self.sign, len: new_len }
#| }
#| }
#|}
#|pub fn BigInt::is_zero(self : BigInt) -> Bool {
#| self.len == 1 && self.limbs[0] == 0
#|}
#|pub impl Compare for BigInt with compare(self, other) {
#| if self.sign != other.sign {
#| return if self.sign == Positive { 1 } else { -1 }
#| }
#| let self_len = self.len
#| let other_len = other.len
#| if self_len != other_len {
#| return if self.sign == Positive {
#| self_len - other_len
#| } else {
#| other_len - self_len
#| }
#| }
#| for i = self_len - 1; i >= 0; i = i - 1 {
#| if self.limbs[i] != other.limbs[i] {
#| return if self.sign == Positive {
#| self.limbs[i].compare(other.limbs[i])
#| } else {
#| other.limbs[i].compare(self.limbs[i])
#| }
#| }
#| }
#| 0
#|}
#|pub impl Eq for BigInt with equal(self, other) {
#| if self.sign != other.sign || self.len != other.len {
#| return false
#| }
#| for i in 0.. String {
#| 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.
#| 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
#|}
#|pub impl Show for BigInt with output(self, logger) {
#| logger.write_string(self.to_string())
#|}
#|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 }
#|}
#|pub fn BigInt::from_hex(input : String) -> BigInt {
#| 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 }
#|}
#|pub fn BigInt::to_hex(self : BigInt, uppercase? : Bool = true) -> String {
#| if self.is_zero() {
#| return "0"
#| }
#| 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.
#| 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 }
#|}
#|fn[T : Compare] max(a : T, b : T) -> T {
#| if a > b {
#| a
#| } else {
#| b
#| }
#|}
#|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
#| }
#| }
#|}
#|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)
#| 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
#| 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)
#|}
#|pub impl BitAnd for BigInt with land(self : BigInt, other : BigInt) -> BigInt {
#| let max_length = if self.limbs.length() < other.limbs.length() {
#| other.limbs.length() + 1
#| } else {
#| self.limbs.length() + 1
#| }
#| let x_limbs = FixedArray::make(max_length, 0U)
#| x_limbs..unsafe_blit(0, self.limbs, 0, self.limbs.length())
#| let y_limbs = FixedArray::make(max_length, 0U)
#| y_limbs..unsafe_blit(0, other.limbs, 0, other.limbs.length())
#| if self.sign == Negative {
#| for i in 0..
other.len {
#| self.len
#| } else {
#| other.len
#| },
#| }
#|}
#|pub impl BitOr for BigInt with lor(self : BigInt, other : BigInt) -> BigInt {
#| let max_length = if self.limbs.length() < other.limbs.length() {
#| other.limbs.length() + 1
#| } else {
#| self.limbs.length() + 1
#| }
#| let x_limbs = FixedArray::make(max_length, 0U)
#| x_limbs.unsafe_blit(0, self.limbs, 0, self.limbs.length())
#| let y_limbs = FixedArray::make(max_length, 0U)
#| y_limbs.unsafe_blit(0, other.limbs, 0, other.limbs.length())
#| if self.sign == Negative {
#| for i in 0.. other.len {
#| self.len
#| } else {
#| other.len
#| },
#| }
#|}
#|pub impl BitXOr for BigInt with lxor(self : BigInt, other : BigInt) -> BigInt {
#| let max_length = if self.limbs.length() < other.limbs.length() {
#| other.limbs.length() + 1
#| } else {
#| self.limbs.length() + 1
#| }
#| let x_limbs = FixedArray::make(max_length, 0U)
#| x_limbs..unsafe_blit(0, self.limbs, 0, self.limbs.length())
#| let y_limbs = FixedArray::make(max_length, 0U)
#| y_limbs..unsafe_blit(0, other.limbs, 0, other.limbs.length())
#| if self.sign == Negative {
#| for i in 0.. other.len {
#| self.len
#| } else {
#| other.len
#| },
#| }
#|}
#|pub fn BigInt::to_int(self : BigInt) -> Int {
#| self.to_uint().reinterpret_as_int()
#|}
#|pub fn BigInt::to_uint(self : BigInt) -> UInt {
#| let value = if self.sign == Negative { (1N << 32) + self } else { self }
#| value.limbs[0]
#|}
#|pub fn BigInt::to_int64(self : BigInt) -> Int64 {
#| self.to_uint64().reinterpret_as_int64()
#|}
#|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
#|}
#|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 {
#| 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
#|}
#|pub fn BigInt::ctz(self : BigInt) -> Int {
#| if self.is_zero() {
#| return 0
#| }
#| let mut i = 0
#| while i < self.len && self.limbs[i] == 0 {
#| i = i + 1
#| }
#| radix_bit_len * i + self.limbs[i].ctz()
#|}
#|fn unchecked_double_to_int(d : Double) -> Int = "%f64_to_i32"
#|fn unsafe_fixedarray_to_bytes(arr : FixedArray[Byte]) -> Bytes = "%identity"
#|fn can_convert_to_int(x : BigInt) -> Bool {
#| x.len == 1 &&
#| (if x.sign == Negative {
#| x.limbs[0] <= 0x80000000
#| } else {
#| x.limbs[0] < 0x80000000
#| })
#|}
#|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
#| })
#|}
#|fn is_neg(x : BigInt) -> Bool {
#| x.sign == Negative
#|}
#|test "limb length" {
#| inspect(0N.len, content="1")
#| inspect(1N.len, content="1")
#| inspect((-1N).len, content="1")
#| inspect(2147483647N.len, content="1") // Int.max_value
#| inspect((-2147483648N).len, content="1") // Int.min_value
#| inspect(2147483648N.len, content="1") // Int.max_value + 1
#| inspect((-2147483649N).len, content="1") // Int.min_value - 1
#| inspect(4294967295N.len, content="1") // 2^32 - 1
#| inspect((-4294967295N).len, content="1") // -(2^32 - 1)
#| inspect(4294967296N.len, content="2") // 2^32
#| inspect((-4294967296N).len, content="2") // -2^32
#|}
#|fn BigInt::limbs(self : Self) -> Iter[UInt] {
#| self.limbs.iter().take(self.len)
#|}
),
"deprecated.mbt": (
#|#deprecated("Use infix bitwise operator `>>` instead")
#|#coverage.skip
#|pub fn BigInt::asr(self : BigInt, n : Int) -> BigInt {
#| self >> n
#|}
#|#deprecated("Use infix bitwise operator `<<` instead")
#|#coverage.skip
#|pub fn BigInt::shl(self : BigInt, n : Int) -> BigInt {
#| self << n
#|}
#|#deprecated("Use infix bitwise operator `<<` instead")
#|#coverage.skip
#|pub fn BigInt::lsl(self : BigInt, n : Int) -> BigInt {
#| self << n
#|}
#|#deprecated("Use infix bitwise operator `>>` instead")
#|#coverage.skip
#|pub fn BigInt::shr(self : BigInt, n : Int) -> BigInt {
#| self >> n
#|}
),
},
)
///|
let moonbitlang_core_bool_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/bool",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin"],
#| "test-import": [ "moonbitlang/core/char" ]
#|}
),
"bool.mbt": (
#|pub fn to_int(self : Bool) -> Int {
#| if self {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub fn to_int64(self : Bool) -> Int64 {
#| if self {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub fn to_uint(self : Bool) -> UInt {
#| if self {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub fn to_uint64(self : Bool) -> UInt64 {
#| if self {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub impl Hash for Bool with hash(self) {
#| self.to_int()
#|}
#|pub impl Hash for Bool with hash_combine(self, hasher) {
#| hasher.combine_bool(self)
#|}
#|pub fn to_uint16(self : Bool) -> UInt16 {
#| if self {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub fn to_int16(self : Bool) -> Int16 {
#| if self {
#| 1
#| } else {
#| 0
#| }
#|}
),
},
)
///|
let moonbitlang_core_buffer_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/bytes",
#| "moonbitlang/core/array",
#| "moonbitlang/core/string"
#| ],
#| "test-import": ["moonbitlang/core/int"]
#|}
),
"buffer.mbt": (
#|struct Buffer {
#| mut data : FixedArray[Byte]
#| mut len : Int
#| initial_data : FixedArray[Byte]
#|}
#|fn grow_if_necessary(self : Buffer, 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
#| }
#|}
#|pub fn length(self : Buffer) -> Int {
#| self.len
#|}
#|pub fn is_empty(self : Buffer) -> Bool {
#| self.len == 0
#|}
#|pub fn contents(self : Buffer) -> Bytes {
#| @bytes.from_fixedarray(self.data, len=self.len)
#|}
#|pub fn new(size_hint? : Int = 0) -> Buffer {
#| let initial = if size_hint < 1 { 1 } else { size_hint }
#| let data = FixedArray::make(initial, Byte::default())
#| { data, len: 0, initial_data: data }
#|}
#|pub fn from_bytes(bytes : Bytes) -> Buffer {
#| let val_len = bytes.length()
#| let buf = new(size_hint=val_len)
#| buf.data.blit_from_bytes(0, bytes, 0, val_len)
#| buf.len = val_len
#| buf
#|}
#|pub fn from_array(arr : Array[Byte]) -> Buffer {
#| let buf = new(size_hint=arr.length())
#| for byte in arr {
#| buf.data[buf.len] = byte
#| buf.len += 1
#| }
#| buf
#|}
#|pub fn from_iter(iter : Iter[Byte]) -> Buffer {
#| let buf = new()
#| let mut capacity = buf.data.length()
#| for byte in iter {
#| if buf.len == capacity {
#| buf.grow_if_necessary(capacity + 1)
#| capacity = buf.data.length()
#| }
#| buf.data[buf.len] = byte
#| buf.len += 1
#| }
#| buf
#|}
#|pub impl Logger for Buffer with write_string(self, value) {
#| self.grow_if_necessary(self.len + value.length() * 2)
#| self.data.blit_from_string(self.len, value, 0, value.length())
#| self.len += value.length() * 2
#|}
#|pub fn write_uint64_be(self : Buffer, 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())
#|}
#|pub fn write_uint64_le(self : Buffer, 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())
#|}
#|pub fn write_int64_be(self : Buffer, value : Int64) -> Unit {
#| self.write_uint64_be(value.reinterpret_as_uint64())
#|}
#|pub fn write_int64_le(self : Buffer, value : Int64) -> Unit {
#| self.write_uint64_le(value.reinterpret_as_uint64())
#|}
#|pub fn write_uint_be(self : Buffer, 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())
#|}
#|pub fn write_uint_le(self : Buffer, 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())
#|}
#|pub fn write_int_be(self : Buffer, value : Int) -> Unit {
#| self.write_uint_be(value.reinterpret_as_uint())
#|}
#|pub fn write_int_le(self : Buffer, value : Int) -> Unit {
#| self.write_uint_le(value.reinterpret_as_uint())
#|}
#|pub fn write_double_be(self : Buffer, value : Double) -> Unit {
#| self.write_uint64_be(value.reinterpret_as_uint64())
#|}
#|pub fn write_double_le(self : Buffer, value : Double) -> Unit {
#| self.write_uint64_le(value.reinterpret_as_uint64())
#|}
#|pub fn write_float_be(self : Buffer, value : Float) -> Unit {
#| self.write_uint_be(value.reinterpret_as_uint())
#|}
#|pub fn write_float_le(self : Buffer, value : Float) -> Unit {
#| self.write_uint_le(value.reinterpret_as_uint())
#|}
#|pub fn write_object(self : Buffer, value : &Show) -> Unit {
#| self.write_string(value.to_string())
#|}
#|pub fn write_bytes(self : Buffer, 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
#|}
#|pub fn write_bytesview(self : Buffer, 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
#|}
#|pub impl Logger for Buffer with write_substring(
#| self : Buffer,
#| value : String,
#| start : Int,
#| len : Int,
#|) -> Unit {
#| guard start >= 0 && len >= 0 && start + len <= value.length()
#| self.grow_if_necessary(self.len + len * 2)
#| self.data.blit_from_string(self.len, value, start, len)
#| self.len += len * 2
#|}
#|pub fn write_stringview(self : Buffer, 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
#|}
#|pub impl Logger for Buffer with write_char(self : Buffer, value : Char) -> Unit {
#| self.grow_if_necessary(self.len + 4)
#| let inc = self.data.set_utf16le_char(self.len, value)
#| self.len += inc
#|}
#|pub fn write_byte(self : Buffer, value : Byte) -> Unit {
#| self.grow_if_necessary(self.len + 1)
#| self.data[self.len] = value
#| self.len += 1
#|}
#|pub fn write_iter(self : Buffer, iter : Iter[Byte]) -> Unit {
#| for byte in iter {
#| self.write_byte(byte)
#| }
#|}
#|pub fn reset(self : Buffer) -> Unit {
#| self.data = self.initial_data
#| self.len = 0
#|}
#|pub fn to_bytes(self : Buffer) -> Bytes {
#| @bytes.from_fixedarray(self.data, len=self.len)
#|}
#|pub impl Show for Buffer with output(self, logger) {
#| logger.write_string(self.contents().to_unchecked_string())
#|}
),
"deprecated.mbt": (
#|#deprecated("Use type `Buffer` instead")
#|pub typealias Buffer as T
),
"sleb128.mbt": (
#|trait Leb128 {
#| output(Self, Buffer) -> Unit
#|}
#|pub impl Leb128 for Int with output(self, buffer) {
#| for value = self {
#| let byte = value & 0x7f // Get the low 7 bits
#| let next_value = value >> 7 // Arithmetic right shift
#| let sign_bit_set = (byte & 0x40) != 0
#| let need_more = if value >= 0 {
#| next_value != 0
#| } else {
#| next_value != -1 || !sign_bit_set
#| }
#| if need_more {
#| buffer.write_byte((byte | 0x80).to_byte())
#| continue next_value
#| } else {
#| buffer.write_byte(byte.to_byte())
#| break
#| }
#| }
#|}
#|pub impl Leb128 for Int64 with output(self, buffer) {
#| for value = self {
#| let byte = value & 0x7f // Get the low 7 bits
#| let next_value = value >> 7 // Arithmetic right shift
#| let sign_bit_set = (byte & 0x40) != 0
#| let need_more = if value >= 0 {
#| next_value != 0
#| } else {
#| next_value != -1 || !sign_bit_set
#| }
#| if need_more {
#| buffer.write_byte((byte | 0x80).to_byte())
#| continue next_value
#| } else {
#| buffer.write_byte(byte.to_byte())
#| break
#| }
#| }
#|}
#|pub fn[A : Leb128] Buffer::write_leb128(buffer : Buffer, value : A) -> Unit {
#| value.output(buffer)
#|}
),
"uleb128.mbt": (
#|pub impl Leb128 for UInt with output(self, buffer) {
#| for value = self {
#| if value < 128 {
#| buffer.write_byte(value.to_byte())
#| break
#| } else {
#| buffer.write_byte(((value % 128) | 128).to_byte())
#| continue value / 128
#| }
#| }
#|}
#|pub impl Leb128 for UInt64 with output(self, buffer) {
#| for value = self {
#| if value < 128 {
#| buffer.write_byte(value.to_byte())
#| break
#| } else {
#| buffer.write_byte(((value % 128) | 128).to_byte())
#| continue value / 128
#| }
#| }
#|}
),
},
)
///|
let moonbitlang_core_builtin_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/builtin",
deps={ "moonbitlang/core/abort": moonbitlang_core_abort_module },
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/abort"
#| ],
#| "test-import": [
#| "moonbitlang/core/char",
#| "moonbitlang/core/string",
#| "moonbitlang/core/bytes",
#| "moonbitlang/core/int",
#| "moonbitlang/core/double",
#| "moonbitlang/core/uint64",
#| "moonbitlang/core/array",
#| "moonbitlang/core/int64",
#| "moonbitlang/core/uint",
#| "moonbitlang/core/json",
#| "moonbitlang/core/bigint"
#| ],
#| "alert-list": "-test_import_all",
#| "targets": {
#| "int64_js.mbt": ["js"],
#| "int64_nonjs.mbt": ["not", "js"],
#| "arraycore_js.mbt": ["js"],
#| "arraycore_nonjs.mbt": ["not", "js"],
#| "panic_test.mbt": ["not", "native", "llvm"],
#| "panic_wbtest.mbt": ["not", "native", "llvm"],
#| "panic_nonjs_test.mbt": ["wasm", "wasm-gc"],
#| "array_nonjs_test.mbt": ["not", "js"],
#| "stringbuilder_buffer.mbt": ["not", "js"],
#| "stringbuilder_concat.mbt": ["js"],
#| "double_to_int64_js.mbt": ["js"],
#| "double_to_int64_native.mbt": ["native", "llvm"],
#| "double_to_int64_wasm.mbt": ["wasm", "wasm-gc"],
#| "double_to_int.mbt": ["not", "wasm", "wasm-gc"],
#| "double_to_int_wasm.mbt": ["wasm", "wasm-gc"]
#| }
#|}
),
"array.mbt": (
#|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
#|}
#|pub fn[T] Array::make(len : Int, elem : T) -> Array[T] {
#| let arr = Array::make_uninit(len)
#| for i in 0.. T raise?,
#|) -> Array[T] raise? {
#| if length <= 0 {
#| []
#| } else {
#| let array = Array::make_uninit(length)
#| for i in 0.. Int {
#| self.buffer().0.length()
#|}
#|#intrinsic("%array.unsafe_get")
#|pub fn[T] Array::unsafe_get(self : Array[T], idx : Int) -> T {
#| self.buffer()[idx]
#|}
#|#intrinsic("%array.get")
#|pub fn[T] Array::op_get(self : Array[T], index : Int) -> T {
#| let len = self.length()
#| guard index >= 0 && index < len
#| self.buffer()[index]
#|}
#|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))
#|}
#|#intrinsic("%array.unsafe_set")
#|fn[T] Array::unsafe_set(self : Array[T], idx : Int, val : T) -> Unit {
#| self.buffer()[idx] = val
#|}
#|#intrinsic("%array.set")
#|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
#|}
#|pub impl[T : Eq] Eq for Array[T] with equal(self, other) {
#| let self_len = self.length()
#| let other_len = other.length()
#| guard self_len == other_len else { return false }
#| for i in 0.. Unit {
#| other.blit_to(
#| self,
#| len=other.length(),
#| src_offset=0,
#| dst_offset=self.length(),
#| )
#|}
#|#locals(f)
#|pub fn[T] Array::each(self : Array[T], f : (T) -> Unit raise?) -> Unit raise? {
#| for v in self {
#| f(v)
#| }
#|}
#|#locals(f)
#|pub fn[T] Array::rev_each(self : Array[T], f : (T) -> Unit) -> Unit {
#| let len = self.length()
#| for i in 0.. Unit raise?,
#|) -> Unit raise? {
#| let len = self.length()
#| for i in 0.. Unit raise?,
#|) -> Unit raise? {
#| for i, v in self {
#| f(i, v)
#| }
#|}
#|pub fn[T] Array::clear(self : Array[T]) -> Unit {
#| self.unsafe_truncate_to_length(0)
#|}
#|#locals(f)
#|pub fn[T, U] Array::map(
#| self : Array[T],
#| f : (T) -> U raise?,
#|) -> Array[U] raise? {
#| let arr = Array::make_uninit(self.length())
#| for i, v in self {
#| arr.unsafe_set(i, f(v))
#| }
#| arr
#|}
#|#locals(f)
#|pub fn[T] Array::map_inplace(
#| self : Array[T],
#| f : (T) -> T raise?,
#|) -> Unit raise? {
#| for i, v in self {
#| self[i] = f(v)
#| }
#|}
#|#locals(f)
#|pub fn[T, U] Array::mapi(
#| self : Array[T],
#| f : (Int, T) -> U raise?,
#|) -> Array[U] raise? {
#| if self.length() == 0 {
#| return []
#| }
#| let arr = Array::make_uninit(self.length())
#| for i, v in self {
#| arr.unsafe_set(i, f(i, v))
#| }
#| arr
#|}
#|#locals(f)
#|pub fn[T] Array::mapi_inplace(
#| self : Array[T],
#| f : (Int, T) -> T raise?,
#|) -> Unit raise? {
#| for i, v in self {
#| self[i] = f(i, v)
#| }
#|}
#|#locals(f)
#|pub fn[T] Array::filter(
#| self : Array[T],
#| f : (T) -> Bool raise?,
#|) -> Array[T] raise? {
#| let arr = []
#| for v in self {
#| if f(v) {
#| arr.push(v)
#| }
#| }
#| arr
#|}
#|pub fn[T] Array::is_empty(self : Array[T]) -> Bool {
#| self.length() == 0
#|}
#|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
#| }
#|}
#|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)
#| }
#|}
#|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)
#|}
#|pub fn[T : Eq] Array::contains(self : Array[T], value : T) -> Bool {
#| for v in self {
#| if v == value {
#| break true
#| }
#| } else {
#| false
#| }
#|}
#|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.. Array[T]? {
#| if self.starts_with(prefix) {
#| let v = Array::make_uninit(self.length() - prefix.length())
#| UninitializedArray::unsafe_blit(
#| v.buffer(),
#| 0,
#| self.buffer(),
#| prefix.length(),
#| self.length() - prefix.length(),
#| )
#| Some(v)
#| } else {
#| None
#| }
#|}
#|pub fn[T : Eq] Array::strip_suffix(
#| self : Array[T],
#| suffix : Array[T],
#|) -> Array[T]? {
#| if self.ends_with(suffix) {
#| let v = Array::make_uninit(self.length() - suffix.length())
#| let len = self.length() - suffix.length()
#| UninitializedArray::unsafe_blit(v.buffer(), 0, self.buffer(), 0, len)
#| Some(v)
#| } else {
#| None
#| }
#|}
#|pub fn[T : Eq] Array::search(self : Array[T], value : T) -> Int? {
#| for i, v in self {
#| if v == value {
#| break Some(i)
#| }
#| } else {
#| None
#| }
#|}
#|#locals(f)
#|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
#| }
#|}
#|pub fn[T : Compare] Array::binary_search(
#| self : Array[T],
#| value : T,
#|) -> Result[Int, Int] {
#| let len = self.length()
#| for i = 0, j = len; i < j; {
#| let h = i + (j - i) / 2
#| if self.unsafe_get(h) < value {
#| continue h + 1, j
#| } else {
#| continue i, h
#| }
#| } else {
#| if i < len && self.unsafe_get(i) == value {
#| Ok(i)
#| } else {
#| Err(i)
#| }
#| }
#|}
#|#locals(cmp)
#|pub fn[T] Array::binary_search_by(
#| self : Array[T],
#| cmp : (T) -> Int,
#|) -> Result[Int, Int] {
#| let len = self.length()
#| for i = 0, j = len; i < j; {
#| let h = i + (j - i) / 2
#| if cmp(self.unsafe_get(h)) < 0 {
#| continue h + 1, j
#| } else {
#| continue i, h
#| }
#| } else {
#| if i < len && cmp(self.unsafe_get(i)) == 0 {
#| Ok(i)
#| } else {
#| Err(i)
#| }
#| }
#|}
#|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)
#|}
#|#locals(f)
#|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 {
#| self.unsafe_truncate_to_length(j)
#| }
#|}
#|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
#|}
#|pub fn[T] Array::repeat(self : Array[T], times : Int) -> Array[T] {
#| let v = Array::new(capacity=self.length() * times)
#| for i in 0.. B raise?,
#|) -> B raise? {
#| for i = 0, acc = init; i < self.length(); {
#| continue i + 1, f(acc, self[i])
#| } else {
#| acc
#| }
#|}
#|#locals(f)
#|pub fn[A, B] Array::rev_fold(
#| self : Array[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for i = self.length() - 1, acc = init; i >= 0; {
#| continue i - 1, f(acc, self[i])
#| } else {
#| acc
#| }
#|}
#|#locals(f)
#|pub fn[A, B] Array::foldi(
#| self : Array[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| for i = 0, acc = init; i < self.length(); {
#| continue i + 1, f(i, acc, self[i])
#| } else {
#| acc
#| }
#|}
#|#locals(f)
#|pub fn[A, B] Array::rev_foldi(
#| self : Array[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| let len = self.length()
#| for i = len - 1, acc = init; i >= 0; {
#| continue i - 1, f(len - i - 1, acc, self[i])
#| } else {
#| acc
#| }
#|}
#|pub fn[T : Eq] Array::dedup(self : Array[T]) -> 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
#|}
#|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
#|}
#|#locals(pred)
#|pub fn[T] Array::chunk_by(
#| self : Array[T],
#| pred : (T, T) -> Bool raise?,
#|) -> Array[Array[T]] raise? {
#| let chunks = []
#| let mut i = 0
#| while i < self.length() {
#| let chunk = []
#| chunk.push(self[i])
#| i = i + 1
#| while i < self.length() && pred(self[i - 1], self[i]) {
#| chunk.push(self[i])
#| i = i + 1
#| }
#| chunks.push(chunk)
#| }
#| chunks
#|}
#|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.. Bool raise?,
#|) -> Array[Array[T]] raise? {
#| let chunks = []
#| let mut i = 0
#| while i < self.length() {
#| let chunk = []
#| while i < self.length() && !pred(self[i]) {
#| chunk.push(self[i])
#| i = i + 1
#| }
#| chunks.push(chunk)
#| i = i + 1
#| }
#| chunks
#|}
#|pub fn[T] Array::iter(self : Array[T]) -> Iter[T] {
#| Iter::new(yield_ => for v in self {
#| guard yield_(v) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| })
#|}
#|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
#| })
#|}
#|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
#| })
#|}
#|pub impl[T] Default for Array[T] with default() {
#| []
#|}
#|#internal(unsafe, "Panic if the array is empty on non-JS backend.")
#|pub fn[A] Array::unsafe_pop_back(self : Array[A]) -> Unit {
#| self.unsafe_pop() |> ignore
#|}
#|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)
#|}
#|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)
#|}
),
"array_block.mbt": (
#|#internal(unsafe, "Panic if the indices or length are out of bounds")
#|pub fn[A] Array::unsafe_blit(
#| dst : Array[A],
#| dst_offset : Int,
#| src : Array[A],
#| src_offset : Int,
#| len : Int,
#|) -> Unit {
#| FixedArray::unsafe_blit(
#| dst.buffer().0,
#| dst_offset,
#| src.buffer().0,
#| src_offset,
#| len,
#| )
#|}
#|pub fn[A] Array::unsafe_blit_fixed(
#| dst : Array[A],
#| dst_offset : Int,
#| src : FixedArray[A],
#| src_offset : Int,
#| len : Int,
#|) -> Unit {
#| UninitializedArray::unsafe_blit_fixed(
#| dst.buffer(),
#| dst_offset,
#| src,
#| src_offset,
#| len,
#| )
#|}
#|pub fn[A] Array::blit_to(
#| self : Array[A],
#| dst : Array[A],
#| len~ : Int,
#| src_offset? : Int = 0,
#| dst_offset? : Int = 0,
#|) -> Unit {
#| guard len >= 0 &&
#| dst_offset >= 0 &&
#| src_offset >= 0 &&
#| dst_offset <= dst.length() &&
#| src_offset + len <= self.length()
#| if dst_offset + len > dst.length() {
#| dst.unsafe_grow_to_length(dst_offset + len)
#| }
#| Array::unsafe_blit(dst, dst_offset, self, src_offset, len)
#|}
#|test "Array::blit_to/basic" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| Array::blit_to(src, dst, len=3, src_offset=1, dst_offset=2)
#| inspect(dst, content="[0, 0, 2, 3, 4]")
#|}
#|test "Array::blit_to/basic" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| Array::blit_to(src, dst, len=3)
#| inspect(dst, content="[1, 2, 3, 0, 0]")
#|}
#|test "Array::blit_to/zero_length" {
#| let src = [1, 2, 3]
#| let dst = [4, 5, 6]
#| Array::blit_to(src, dst, len=0)
#| inspect(dst, content="[4, 5, 6]")
#|}
#|test "Array::blit_to/grow_destination" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0]
#| Array::blit_to(src, dst, len=3, dst_offset=1)
#| inspect(dst, content="[0, 1, 2, 3]")
#|}
#|test "Array::blit_to/edge_cases" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| Array::blit_to(src, dst, len=2, src_offset=1, dst_offset=2)
#| inspect(dst, content="[0, 0, 2, 3, 0]")
#| Array::blit_to(src, src, len=2, src_offset=0, dst_offset=3)
#| inspect(src, content="[1, 2, 3, 1, 2]")
#| Array::blit_to(src, dst, len=0, src_offset=0, dst_offset=0)
#| inspect(dst, content="[0, 0, 2, 3, 0]")
#| Array::blit_to(src, dst, len=5)
#| inspect(dst, content="[1, 2, 3, 1, 2]")
#|}
#|test "Array::blit_to/edge_cases" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| Array::blit_to(src, dst, len=0, src_offset=0, dst_offset=0)
#| inspect(dst, content="[0, 0, 0, 0, 0]")
#| Array::blit_to(src, dst, len=5, src_offset=0, dst_offset=0)
#| inspect(dst, content="[1, 2, 3, 4, 5]")
#|}
#|test "panic Array::blit_to/boundary_cases" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| ignore(Array::blit_to(src, dst, len=-1))
#|}
#|test "panic Array::blit_to/boundary_cases" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| ignore(Array::blit_to(src, dst, len=2, src_offset=-1))
#|}
#|test "panic Array::blit_to/boundary_cases" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| ignore(Array::blit_to(src, dst, len=6))
#|}
#|test "panic Array::blit_to/boundary_cases" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| ignore(Array::blit_to(src, dst, len=5, dst_offset=6))
#|}
#|test "Array::blit_to - random cases" {
#| let src = [10, 20, 30, 40, 50]
#| let dst = [0, 0, 0, 0, 0]
#| Array::blit_to(src, dst, len=2, src_offset=2, dst_offset=1)
#| inspect(dst, content="[0, 30, 40, 0, 0]")
#| Array::blit_to(src, dst, len=3, src_offset=1, dst_offset=2)
#| inspect(dst, content="[0, 30, 20, 30, 40]")
#| Array::blit_to(src, dst, len=1, src_offset=4, dst_offset=4)
#| inspect(dst, content="[0, 30, 20, 30, 50]")
#|}
#|test "Array::blit_to - boundary cases" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| Array::blit_to(src, dst, len=1, src_offset=4, dst_offset=0)
#| inspect(dst, content="[5, 0, 0, 0, 0]")
#| Array::blit_to(src, dst, len=1, src_offset=0, dst_offset=4)
#| inspect(dst, content="[5, 0, 0, 0, 1]")
#| Array::blit_to(src, dst, len=2, src_offset=3, dst_offset=3)
#| inspect(dst, content="[5, 0, 0, 4, 5]")
#|}
#|test "Array::unsafe_blit_fixed" {
#| let src = FixedArray::make(3, 1) // Create a FixedArray with 3 elements of value 1
#| let dst = Array::make(5, 0) // Create an Array with 5 elements of value 0
#| Array::unsafe_blit_fixed(dst, 1, src, 0, 2) // Copy 2 elements from src[0] to dst[1]
#| inspect(dst, content="[0, 1, 1, 0, 0]")
#|}
),
"arraycore_js.mbt": (
#|#external
#|priv type JSValue
#|fn[T] JSValue::ofAny(array : T) -> JSValue = "%identity"
#|fn[T] JSValue::toAny(self : JSValue) -> T = "%identity"
#|#external
#|priv type JSArray
#|fn[T] JSArray::ofAnyArray(array : Array[T]) -> JSArray = "%identity"
#|fn[T] JSArray::toAnyArray(self : JSArray) -> Array[T] = "%identity"
#|extern "js" fn JSArray::set_length(self : JSArray, new_len : Int) -> Unit =
#| #| (arr, len) => { arr.length = len; }
#|extern "js" fn JSArray::push(self : JSArray, value : JSValue) -> Unit =
#| #| (arr, val) => { arr.push(val); }
#|extern "js" fn JSArray::pop(self : JSArray) -> JSValue =
#| #| (arr) => arr.pop()
#|extern "js" fn JSArray::splice(
#| self : JSArray,
#| index : Int,
#| count : Int,
#|) -> JSArray =
#| #| (arr, idx, cnt) => arr.splice(idx, cnt)
#|extern "js" fn JSArray::splice1(
#| self : JSArray,
#| index : Int,
#| count : Int,
#| value : JSValue,
#|) -> JSArray =
#| #| (arr, idx, cnt, val) => arr.splice(idx, cnt, val)
#|extern "js" fn JSArray::fill(
#| self : JSArray,
#| value : JSValue,
#| start : Int,
#| end : Int,
#|) -> Unit =
#| #| (arr, val, start, end) => arr.fill(val, start, end)
#|#external
#|type Array[T]
#|fn[T] Array::make_uninit(len : Int) -> Array[T] = "%fixedarray.make_uninit"
#|pub fn[T] Array::new(capacity? : Int = 0) -> Array[T] {
#| ignore(capacity)
#| []
#|}
#|pub fn[T] Array::length(self : Array[T]) -> Int = "%fixedarray.length"
#|fn[T] Array::unsafe_truncate_to_length(self : Array[T], new_len : Int) -> Unit {
#| JSArray::ofAnyArray(self).set_length(new_len)
#|}
#|fn[T] Array::buffer(self : Array[T]) -> UninitializedArray[T] = "%identity"
#|test "array_unsafe_blit_fixed" {
#| let src = FixedArray::make(5, 0)
#| let dst = UninitializedArray::make(5)
#| for i in 0..<5 {
#| src[i] = i + 1
#| }
#| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5)
#| for i in 0..<5 {
#| assert_eq(dst[i], src[i])
#| }
#|}
#|test "UninitializedArray::unsafe_blit_fixed" {
#| let src = FixedArray::make(5, 0)
#| let dst = UninitializedArray::make(5)
#| for i in 0..<5 {
#| src[i] = i + 1
#| }
#| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5)
#| for i in 0..<5 {
#| assert_eq(dst[i], src[i])
#| }
#|}
#|test "UninitializedArray::unsafe_blit_fixed" {
#| let src = FixedArray::make(5, 0)
#| let dst = UninitializedArray::make(5)
#| for i in 0..<5 {
#| src[i] = i + 1
#| }
#| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5)
#| for i in 0..<5 {
#| assert_eq(dst[i], src[i])
#| }
#|}
#|pub fn[T] Array::reserve_capacity(self : Array[T], capacity : Int) -> Unit {
#| ignore(self)
#| ignore(capacity)
#|}
#|pub fn[T] Array::shrink_to_fit(self : Array[T]) -> Unit {
#| ignore(self)
#|}
#|pub fn[T] Array::push(self : Array[T], value : T) -> Unit {
#| JSArray::ofAnyArray(self).push(JSValue::ofAny(value))
#|}
#|pub fn[T] Array::pop(self : Array[T]) -> T? {
#| if self.length() == 0 {
#| None
#| } else {
#| let v = self.unsafe_pop()
#| Some(v)
#| }
#|}
#|#internal(unsafe, "Panic if the array is empty.")
#|pub fn[T] Array::unsafe_pop(self : Array[T]) -> T {
#| JSArray::ofAnyArray(self).pop().toAny()
#|}
#|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
#|}
#|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()
#|}
#|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))
#|}
#|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)
#|}
#|pub fn[A] Array::fill(
#| self : Array[A],
#| value : A,
#| start? : Int = 0,
#| end? : Int,
#|) -> Unit {
#| let array_length = self.length()
#| guard array_length > 0 else { return }
#| guard start >= 0 && start < array_length
#| let end = match end {
#| None => array_length
#| Some(e) => {
#| guard e >= 0 && e <= array_length
#| e
#| }
#| }
#| JSArray::ofAnyArray(self).fill(JSValue::ofAny(value), start, end)
#|}
),
"arraycore_nonjs.mbt": (
#|fn[T] set_null(self : UninitializedArray[T], index : Int) = "%fixedarray.set_null"
#|struct Array[T] {
#| mut buf : UninitializedArray[T]
#| mut len : Int
#|}
#|fn[T] Array::make_uninit(len : Int) -> Array[T] {
#| { buf: UninitializedArray::make(len), len }
#|}
#|pub fn[T] Array::new(capacity? : Int = 0) -> Array[T] {
#| if capacity == 0 {
#| []
#| } else {
#| { buf: UninitializedArray::make(capacity), len: 0 }
#| }
#|}
#|#intrinsic("%array.length")
#|pub fn[T] Array::length(self : Array[T]) -> Int {
#| self.len
#|}
#|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
#|}
#|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
#|}
#|test "array_unsafe_blit_fixed" {
#| let src = FixedArray::make(5, 0)
#| let dst = UninitializedArray::make(5)
#| for i in 0..<5 {
#| src[i] = i + 1
#| }
#| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5)
#| for i in 0..<5 {
#| assert_eq(dst[i], src[i])
#| }
#|}
#|test "UninitializedArray::unsafe_blit_fixed" {
#| let src = FixedArray::make(5, 0)
#| let dst = UninitializedArray::make(5)
#| for i in 0..<5 {
#| src[i] = i + 1
#| }
#| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5)
#| for i in 0..<5 {
#| assert_eq(dst[i], src[i])
#| }
#|}
#|test "UninitializedArray::unsafe_blit_fixed" {
#| let src = FixedArray::make(5, 0)
#| let dst = UninitializedArray::make(5)
#| for i in 0..<5 {
#| src[i] = i + 1
#| }
#| UninitializedArray::unsafe_blit_fixed(dst, 0, src, 0, 5)
#| for i in 0..<5 {
#| assert_eq(dst[i], src[i])
#| }
#|}
#|test "Array::resize_buffer" {
#| let arr = Array::new(capacity=2)
#| arr.push(1)
#| arr.push(2)
#| arr.resize_buffer(4)
#| assert_eq(arr.buffer().0.length() >= 4, true)
#| arr.push(3)
#| arr.push(4)
#| assert_eq(arr.length(), 4)
#| assert_eq(arr[0], 1)
#| assert_eq(arr[1], 2)
#| assert_eq(arr[2], 3)
#| assert_eq(arr[3], 4)
#|}
#|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)
#|}
#|pub fn[T] Array::reserve_capacity(self : Array[T], capacity : Int) -> Unit {
#| if self.capacity() >= capacity {
#| return
#| }
#| self.resize_buffer(capacity)
#|}
#|pub fn[T] Array::shrink_to_fit(self : Array[T]) -> Unit {
#| if self.capacity() <= self.length() {
#| return
#| }
#| self.resize_buffer(self.length())
#|}
#|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
#|}
#|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)
#| }
#|}
#|#internal(unsafe, "Panic if the array is empty.")
#|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
#|}
#|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
#|}
#|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
#|}
#|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
#|}
#|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
#|}
#|pub fn[A] Array::fill(
#| self : Array[A],
#| value : A,
#| start? : Int = 0,
#| end? : Int,
#|) -> Unit {
#| let array_length = self.length()
#| guard array_length > 0 else { return }
#| guard start >= 0 && start < array_length
#| let length = match end {
#| None => array_length
#| Some(e) => {
#| guard e >= start && e <= array_length
#| e
#| }
#| }
#| self.buf.unchecked_fill(start, value, length - start)
#|}
),
"arrayview.mbt": (
#|#deprecated("use @array.View instead")
#|#builtin.valtype
#|type ArrayView[T]
#|fn[T] ArrayView::buf(self : ArrayView[T]) -> UninitializedArray[T] = "%arrayview.buf"
#|fn[T] ArrayView::start(self : ArrayView[T]) -> Int = "%arrayview.start"
#|fn[T] ArrayView::len(self : ArrayView[T]) -> Int = "%arrayview.len"
#|fn[T] ArrayView::make(
#| buf : UninitializedArray[T],
#| start : Int,
#| len : Int,
#|) -> ArrayView[T] = "%arrayview.make"
#|pub fn[T] ArrayView::length(self : ArrayView[T]) -> Int {
#| self.len()
#|}
#|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]
#|}
#|#intrinsic("%arrayview.unsafe_get")
#|#internal(unsafe, "Panic if index is out of bounds")
#|pub fn[T] ArrayView::unsafe_get(self : ArrayView[T], index : Int) -> T {
#| self.buf()[self.start() + index]
#|}
#|pub fn[T] ArrayView::op_set(
#| self : ArrayView[T],
#| index : Int,
#| value : T,
#|) -> Unit {
#| 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] = value
#|}
#|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
#|}
#|pub fn[T] Array::op_as_view(
#| self : Array[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| 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("View index out of bounds")
#| }
#| ArrayView::make(self.buffer(), start, end - start)
#|}
#|pub fn[T] ArrayView::op_as_view(
#| self : ArrayView[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| 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("View index out of bounds")
#| }
#| ArrayView::make(self.buf(), self.start() + start, end - start)
#|}
#|pub fn[T] ArrayView::blit_to(self : ArrayView[T], dst : ArrayView[T]) -> Unit {
#| let src_len = self.length()
#| let dst_len = dst.length()
#| guard dst_len >= src_len
#| UninitializedArray::unsafe_blit(
#| dst.buf(),
#| dst.start(),
#| self.buf(),
#| self.start(),
#| src_len,
#| )
#|}
),
"assert.mbt": (
#|fn[T : Show] debug_string(t : T) -> String {
#| let buf = StringBuilder::new(size_hint=50)
#| t.output(buf)
#| buf.to_string()
#|}
#|#callsite(autofill(loc))
#|#coverage.skip
#|pub fn[T : Eq + Show] assert_eq(
#| a : T,
#| b : T,
#| msg? : String,
#| loc~ : SourceLoc,
#|) -> Unit raise {
#| if a != b {
#| let fail_msg = match msg {
#| Some(msg) => msg
#| None => "`\{debug_string(a)} != \{debug_string(b)}`"
#| }
#| fail(fail_msg, loc~)
#| }
#|}
#|#callsite(autofill(loc))
#|#coverage.skip
#|pub fn[T : Eq + Show] assert_not_eq(
#| a : T,
#| b : T,
#| msg? : String,
#| loc~ : SourceLoc,
#|) -> Unit raise {
#| if !(a != b) {
#| let fail_msg = match msg {
#| Some(msg) => msg
#| None => "`\{debug_string(a)} == \{debug_string(b)}`"
#| }
#| fail(fail_msg, loc~)
#| }
#|}
#|#callsite(autofill(loc))
#|#coverage.skip
#|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~)
#| }
#|}
#|#callsite(autofill(loc))
#|#coverage.skip
#|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~)
#| }
#|}
),
"autoloc.mbt": (
#|pub(all) type SourceLoc
#|pub fn SourceLoc::to_string(self : Self) -> String = "%loc_to_string"
#|pub impl Show for SourceLoc with output(self, logger) {
#| logger.write_string(self.to_string())
#|}
#|pub(all) struct ArgsLoc(Array[SourceLoc?]) derive(Show)
#|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()
#|}
),
"byte.mbt": (
#|pub impl Mul for Byte with mul(self : Byte, that : Byte) -> Byte {
#| (self.to_int() * that.to_int()).to_byte()
#|}
#|pub impl Mul for Byte with op_mul(self : Byte, that : Byte) -> Byte {
#| (self.to_int() * that.to_int()).to_byte()
#|}
#|pub impl Div for Byte with div(self : Byte, that : Byte) -> Byte {
#| (self.to_int() / that.to_int()).to_byte()
#|}
#|pub impl Div for Byte with op_div(self : Byte, that : Byte) -> Byte {
#| (self.to_int() / that.to_int()).to_byte()
#|}
#|pub impl Mod for Byte with mod(self : Byte, that : Byte) -> Byte {
#| (self.to_int() % that.to_int()).to_byte()
#|}
#|pub impl Mod for Byte with op_mod(self : Byte, that : Byte) -> Byte {
#| (self.to_int() % that.to_int()).to_byte()
#|}
#|pub impl Eq for Byte with equal(self : Byte, that : Byte) -> Bool {
#| self.to_int() == that.to_int()
#|}
#|pub impl Eq for Byte with op_equal(self : Byte, that : Byte) -> Bool {
#| self.to_int() == that.to_int()
#|}
#|pub impl Add for Byte with add(self : Byte, that : Byte) -> Byte {
#| (self.to_int() + that.to_int()).to_byte()
#|}
#|pub impl Add for Byte with op_add(self : Byte, that : Byte) -> Byte {
#| (self.to_int() + that.to_int()).to_byte()
#|}
#|pub impl Sub for Byte with sub(self : Byte, that : Byte) -> Byte {
#| (self.to_int() - that.to_int()).to_byte()
#|}
#|pub impl Sub for Byte with op_sub(self : Byte, that : Byte) -> Byte {
#| (self.to_int() - that.to_int()).to_byte()
#|}
#|pub impl Compare for Byte with compare(self : Byte, that : Byte) -> Int {
#| self.to_int().compare(that.to_int())
#|}
#|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")
#| }
#|}
#|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}'"
#|}
#|pub impl Hash for Byte with hash(self) {
#| self.to_int()
#|}
#|pub impl Hash for Byte with hash_combine(self, hasher) {
#| hasher.combine_byte(self)
#|}
#|pub impl Default for Byte with default() {
#| b'\x00'
#|}
#|pub fn Byte::lnot(self : Byte) -> Byte {
#| self.to_int().lnot().to_byte()
#|}
#|pub impl BitAnd for Byte with land(self : Byte, that : Byte) -> Byte {
#| (self.to_int() & that.to_int()).to_byte()
#|}
#|pub impl BitOr for Byte with lor(self : Byte, that : Byte) -> Byte {
#| (self.to_int() | that.to_int()).to_byte()
#|}
#|pub impl BitXOr for Byte with lxor(self : Byte, that : Byte) -> Byte {
#| (self.to_int() ^ that.to_int()).to_byte()
#|}
#|pub fn Byte::to_uint(self : Byte) -> UInt {
#| self.to_int().reinterpret_as_uint()
#|}
#|pub impl Shl for Byte with shl(self : Byte, count : Int) -> Byte {
#| (self.to_int() << count).to_byte()
#|}
#|pub impl Shr for Byte with shr(self : Byte, count : Int) -> Byte {
#| (self.to_uint() >> count).reinterpret_as_int().to_byte()
#|}
),
"bytes.mbt": (
#|#internal(unsafe, "Creating mutable Bytes")
#|pub fn FixedArray::unsafe_reinterpret_as_bytes(
#| self : FixedArray[Byte],
#|) -> Bytes = "%identity"
#|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.. String = "$moonbit.unsafe_bytes_sub_string"
#|pub fn Bytes::to_unchecked_string(
#| self : Bytes,
#| offset? : Int = 0,
#| length? : Int,
#|) -> String {
#| let len = self.length()
#| let length = if length is Some(l) { l } else { len - offset }
#| guard offset >= 0 && length >= 0 && offset + length <= len
#| unsafe_sub_string(self, offset, length)
#|}
#|pub fn FixedArray::blit_from_string(
#| self : FixedArray[Byte],
#| bytes_offset : Int,
#| str : String,
#| str_offset : Int,
#| length : Int,
#|) -> Unit {
#| let s1 = bytes_offset
#| let s2 = str_offset
#| let e1 = bytes_offset + length * 2 - 1
#| let e2 = str_offset + length - 1
#| let len1 = self.length()
#| let len2 = str.length()
#| guard length >= 0 && s1 >= 0 && e1 < len1 && s2 >= 0 && e2 < len2
#| let end_str_offset = str_offset + length
#| for i = str_offset, j = bytes_offset; i < end_str_offset; i = i + 1, j = j + 2 {
#| let c = str.unsafe_charcode_at(i).reinterpret_as_uint()
#| self[j] = (c & 0xff).to_byte()
#| self[j + 1] = (c >> 8).to_byte()
#| }
#|}
#|fn unsafe_from_bytes(bytes : Bytes) -> FixedArray[Byte] = "%identity"
#|pub fn FixedArray::blit_from_bytes(
#| self : FixedArray[Byte],
#| bytes_offset : Int,
#| src : Bytes,
#| src_offset : Int,
#| length : Int,
#|) -> Unit {
#| let s1 = bytes_offset
#| let s2 = src_offset
#| let e1 = bytes_offset + length - 1
#| let e2 = src_offset + length - 1
#| let len1 = self.length()
#| let len2 = src.length()
#| guard length >= 0 && s1 >= 0 && e1 < len1 && s2 >= 0 && e2 < len2
#| FixedArray::unsafe_blit(
#| self,
#| bytes_offset,
#| unsafe_from_bytes(src),
#| src_offset,
#| length,
#| )
#|}
#|pub fn FixedArray::set_utf8_char(
#| self : FixedArray[Byte],
#| offset : Int,
#| value : Char,
#|) -> Int {
#| let code = value.to_uint()
#| match code {
#| _..<0x80 => {
#| self[offset] = ((code & 0x7F) | 0x00).to_byte()
#| 1
#| }
#| _..<0x0800 => {
#| self[offset] = (((code >> 6) & 0x1F) | 0xC0).to_byte()
#| self[offset + 1] = ((code & 0x3F) | 0x80).to_byte()
#| 2
#| }
#| _..<0x010000 => {
#| self[offset] = (((code >> 12) & 0x0F) | 0xE0).to_byte()
#| self[offset + 1] = (((code >> 6) & 0x3F) | 0x80).to_byte()
#| self[offset + 2] = ((code & 0x3F) | 0x80).to_byte()
#| 3
#| }
#| _..<0x110000 => {
#| self[offset] = (((code >> 18) & 0x07) | 0xF0).to_byte()
#| self[offset + 1] = (((code >> 12) & 0x3F) | 0x80).to_byte()
#| self[offset + 2] = (((code >> 6) & 0x3F) | 0x80).to_byte()
#| self[offset + 3] = ((code & 0x3F) | 0x80).to_byte()
#| 4
#| }
#| _ => abort("Char out of range")
#| }
#|}
#|pub fn FixedArray::set_utf16le_char(
#| self : FixedArray[Byte],
#| offset : Int,
#| value : Char,
#|) -> Int {
#| let code = value.to_uint()
#| if code < 0x10000 {
#| self[offset] = (code & 0xFF).to_byte()
#| self[offset + 1] = (code >> 8).to_byte()
#| 2
#| } else if code < 0x110000 {
#| let hi = code - 0x10000
#| let lo = (hi >> 10) | 0xD800
#| let hi = (hi & 0x3FF) | 0xDC00
#| self[offset] = (lo & 0xFF).to_byte()
#| self[offset + 1] = (lo >> 8).to_byte()
#| self[offset + 2] = (hi & 0xFF).to_byte()
#| self[offset + 3] = (hi >> 8).to_byte()
#| 4
#| } else {
#| abort("Char out of range")
#| }
#|}
#|pub fn FixedArray::set_utf16be_char(
#| self : FixedArray[Byte],
#| offset : Int,
#| value : Char,
#|) -> Int {
#| let code = value.to_uint()
#| if code < 0x10000 {
#| self[offset] = (code >> 8).to_byte()
#| self[offset + 1] = (code & 0xFF).to_byte()
#| 2
#| } else if code < 0x110000 {
#| let hi = code - 0x10000
#| let lo = (hi >> 10) | 0xD800
#| let hi = (hi & 0x3FF) | 0xDC00
#| self[offset] = (lo >> 8).to_byte()
#| self[offset + 1] = (lo & 0xFF).to_byte()
#| self[offset + 2] = (hi >> 8).to_byte()
#| self[offset + 3] = (hi & 0xFF).to_byte()
#| 4
#| } else {
#| abort("Char out of range")
#| }
#|}
#|pub impl Eq for Bytes with equal(self : Bytes, other : Bytes) -> Bool {
#| if self.length() != other.length() {
#| false
#| } else {
#| let len = self.length()
#| for i in 0.. Unit = "%println"
#|fn[T] any_to_string(any : T) -> String = "%any.to_string"
#|pub fn[T : Show] println(input : T) -> Unit {
#| println_mono(input.to_string())
#|}
#|pub(all) suberror InspectError String
#|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()
#|}
#|fn base64_encode_string_codepoint(s : String) -> 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)
#|}
#|test {
#| inspect(base64_encode_string_codepoint(""))
#| inspect(base64_encode_string_codepoint("a"), content="YQAAAA==")
#| inspect(base64_encode_string_codepoint("ab"), content="YQAAAGIAAAA=")
#| inspect(base64_encode_string_codepoint("abc"), content="YQAAAGIAAABjAAAA")
#| inspect(
#| base64_encode_string_codepoint("abcd"),
#| content="YQAAAGIAAABjAAAAZAAAAA==",
#| )
#| inspect(
#| base64_encode_string_codepoint("abcde"),
#| content="YQAAAGIAAABjAAAAZAAAAGUAAAA=",
#| )
#| inspect(base64_encode_string_codepoint("a中"), content="YQAAAC1OAAA=")
#| inspect(
#| base64_encode_string_codepoint("a中🤣"),
#| content="YQAAAC1OAAAj+QEA",
#| )
#| inspect(
#| base64_encode_string_codepoint("a中🤣a"),
#| content="YQAAAC1OAAAj+QEAYQAAAA==",
#| )
#| inspect(
#| base64_encode_string_codepoint("a中🤣中"),
#| content="YQAAAC1OAAAj+QEALU4AAA==",
#| )
#|}
#|#callsite(autofill(args_loc, loc))
#|pub fn inspect(
#| obj : &Show,
#| content? : String = "",
#| loc~ : SourceLoc,
#| args_loc~ : ArgsLoc,
#|) -> Unit raise InspectError {
#| let actual = obj.to_string()
#| if actual != content {
#| let loc = loc.to_string().escape()
#| let args_loc = args_loc.to_json().escape()
#| let expect_escaped = content.escape()
#| let actual_escaped = actual.escape()
#| let expect_base64 = "\"\{base64_encode_string_codepoint(content)}\""
#| let actual_base64 = "\"\{base64_encode_string_codepoint(actual)}\""
#| raise InspectError(
#| "@EXPECT_FAILED {\"loc\": \{loc}, \"args_loc\": \{args_loc}, \"expect\": \{expect_escaped}, \"actual\": \{actual_escaped}, \"expect_base64\": \{expect_base64}, \"actual_base64\": \{actual_base64}}",
#| )
#| }
#|}
#|pub(all) suberror SnapshotError String
#|pub(all) suberror BenchError String
#|test "panic error case of inspect" {
#| let x : Int = 42
#| inspect(x, content="100")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `..<` in for loop or `until` method instead")
#|#coverage.skip
#|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
#| }
#| }
#|}
#|#deprecated("Use `..<` in for loop or `until` method instead")
#|#coverage.skip
#|pub fn UInt::upto(
#| self : UInt,
#| end : UInt,
#| inclusive? : Bool = false,
#|) -> Iter[UInt] {
#| 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
#| }
#| }
#|}
#|#deprecated("Use `..<` in for loop or `until` method instead")
#|#coverage.skip
#|pub fn UInt64::upto(
#| self : UInt64,
#| end : UInt64,
#| inclusive? : Bool = false,
#|) -> Iter[UInt64] {
#| 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
#| }
#| }
#|}
#|#deprecated("Use `..<` in for loop or `until` method instead")
#|#coverage.skip
#|pub fn Int64::upto(
#| self : Int64,
#| end : Int64,
#| inclusive? : Bool = false,
#|) -> Iter[Int64] {
#| 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
#| }
#| }
#|}
#|#deprecated("Use `..<` in for loop or `until` method instead")
#|#coverage.skip
#|pub fn Float::upto(
#| self : Float,
#| end : Float,
#| inclusive? : Bool = false,
#|) -> Iter[Float] {
#| 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
#| }
#| }
#|}
#|#deprecated("Use `..<` in for loop or `until` method instead")
#|#coverage.skip
#|pub fn Double::upto(
#| self : Double,
#| end : Double,
#| inclusive? : Bool = false,
#|) -> Iter[Double] {
#| 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
#| }
#| }
#|}
#|#deprecated("Use `search_by` instead.")
#|#coverage.skip
#|pub fn[T] Array::find_index(self : Array[T], f : (T) -> Bool) -> Int? {
#| self.search_by(f)
#|}
#|#deprecated("Use `fold` instead.")
#|#coverage.skip
#|pub fn[T, U] Array::fold_left(
#| self : Array[T],
#| f : (U, T) -> U raise?,
#| init~ : U,
#|) -> U raise? {
#| self.fold(init~, f)
#|}
#|#deprecated("Use `rev_fold` instead.")
#|#coverage.skip
#|pub fn[T, U] Array::fold_right(
#| self : Array[T],
#| f : (U, T) -> U raise?,
#| init~ : U,
#|) -> U raise? {
#| self.rev_fold(init~, f)
#|}
#|#deprecated("Use `foldi` instead.")
#|#coverage.skip
#|pub fn[T, U] Array::fold_lefti(
#| self : Array[T],
#| f : (Int, U, T) -> U raise?,
#| init~ : U,
#|) -> U raise? {
#| self.foldi(init~, f)
#|}
#|#deprecated("Use `rev_foldi` instead.")
#|#coverage.skip
#|pub fn[T, U] Array::fold_righti(
#| self : Array[T],
#| f : (Int, U, T) -> U raise?,
#| init~ : U,
#|) -> U raise? {
#| self.rev_foldi(init~, f)
#|}
#|#deprecated("Use `unsafe_pop` instead")
#|#coverage.skip
#|pub fn[T] Array::pop_exn(self : Array[T]) -> T {
#| self.unsafe_pop()
#|}
#|#deprecated("Use `str.to_bytes()` instead")
#|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()
#|}
#|#deprecated("Bytes are immutable. Use `FixedArray::blit_from_bytes` if it's really necessary.")
#|pub fn Bytes::copy(self : Bytes) -> Bytes {
#| Bytes::makei(self.length(), i => self[i])
#|}
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn Byte::lsl(self : Byte, count : Int) -> Byte {
#| (self.to_int() << count).to_byte()
#|}
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn Byte::lsr(self : Byte, count : Int) -> Byte {
#| (self.to_uint() >> count).reinterpret_as_int().to_byte()
#|}
#|#callsite(autofill(loc))
#|#deprecated("This function is for debugging only and should not be used in production")
#|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
#|}
#|#deprecated("The index will be changed to utf16 index. If you want to access n-th character, use `str.iter().nth(n).unwrap()` instead.")
#|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()
#| }
#| }
#|}
#|#deprecated("Use `char_length` instead.")
#|pub fn String::codepoint_length(
#| self : String,
#| start_offset? : Int = 0,
#| end_offset? : Int,
#|) -> Int {
#| self.char_length(start_offset~, end_offset?)
#|}
#|#deprecated("Use `s[i]` instead")
#|pub fn String::charcode_at(self : String, index : Int) -> Int {
#| self[index]
#|}
#|#deprecated("Use `s.get_char(i).unwrap()` instead")
#|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()
#| }
#|}
),
"double_to_int.mbt": (
#|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()
#| }
#|}
#|fn Double::to_unchecked_int(self : Double) -> Int = "%f64_to_i32"
),
"double_to_int64_js.mbt": (
#|extern "js" fn MyInt64::from_double(value : Double) -> MyInt64 =
#| #|(a) => {
#| #| if (isNaN(a)) {
#| #| return { hi: 0, lo: 0 };
#| #| }
#| #| if (a >= 9223372036854775807) {
#| #| return { hi: 0x7fffffff, lo: 0xffffffff };
#| #| }
#| #| if (a <= -9223372036854775808) {
#| #| return { hi: -2147483648, lo: 0 };
#| #| }
#| #| let neg = false;
#| #| if (a < 0) {
#| #| neg = true;
#| #| a = -a;
#| #| }
#| #| let hi = (a * (1 / 0x100000000)) | 0;
#| #| let lo = a >>> 0;
#| #| if (neg) {
#| #| if (lo === 0) {
#| #| hi = ~hi + 1;
#| #| } else {
#| #| hi = ~hi;
#| #| lo = ~lo + 1;
#| #| }
#| #| }
#| #| return { hi, lo };
#| #|}
#|pub fn Double::to_int64(self : Double) -> Int64 {
#| MyInt64::from_double(self).to_int64()
#|}
#|extern "js" fn MyInt64::from_double_unsigned(value : Double) -> MyInt64 =
#| #|(a) => {
#| #| if (isNaN(a)) {
#| #| return { hi: 0, lo: 0 };
#| #| }
#| #| if (a >= 18446744073709551615) {
#| #| return { hi: 0xffffffff, lo: 0xffffffff };
#| #| }
#| #| if (a <= 0) {
#| #| return { hi: 0, lo: 0 };
#| #| }
#| #| let hi = (a * (1 / 0x100000000)) | 0;
#| #| let lo = a >>> 0;
#| #| return { hi, lo };
#| #|}
#|pub fn Double::to_uint64(self : Double) -> UInt64 {
#| MyInt64::from_double_unsigned(self).to_uint64()
#|}
),
"double_to_int64_native.mbt": (
#|fn Double::to_unchecked_int64(self : Double) -> Int64 = "%f64_to_i64"
#|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()
#| }
#|}
#|fn Double::to_unchecked_uint64(self : Double) -> UInt64 = "%f64_to_i64"
#|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()
#| }
#|}
),
"double_to_int64_wasm.mbt": (
#|pub fn Double::to_int64(self : Double) -> Int64 = "%f64_to_i64_saturate"
#|pub fn Double::to_uint64(self : Double) -> UInt64 = "%f64.to_u64_saturate"
),
"double_to_int_wasm.mbt": (
#|pub fn Double::to_int(self : Double) -> Int = "%f64_to_i32_saturate"
),
"failure.mbt": (
#|pub(all) suberror Failure String derive(ToJson(style="flat"), Show)
#|#callsite(autofill(loc))
#|pub fn[T] fail(msg : String, loc~ : SourceLoc) -> T raise Failure {
#| raise Failure("\{loc} FAILED: \{msg}")
#|}
),
"fixedarray.mbt": (
#|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))
#|}
#|#intrinsic("%iter.from_array")
#|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
#| })
#|}
#|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
#| })
#|}
#|pub impl[X] Default for FixedArray[X] with default() {
#| []
#|}
#|pub fn[T] FixedArray::fill(
#| self : FixedArray[T],
#| value : T,
#| start? : Int = 0,
#| end? : Int,
#|) -> Unit {
#| let array_length = self.length()
#| guard array_length > 0 else { return }
#| guard start >= 0 && start < array_length
#| let length = match end {
#| None => array_length - start
#| Some(e) => {
#| guard e >= start && e <= array_length
#| e - start
#| }
#| }
#| self.unchecked_fill(start, value, length)
#|}
#|#intrinsic("%fixedarray.fill")
#|fn[T] FixedArray::unchecked_fill(
#| self : FixedArray[T],
#| start : Int,
#| value : T,
#| len : Int,
#|) -> Unit {
#| for i in start..<(start + len) {
#| self[i] = value
#| }
#|}
#|pub fn[T] FixedArray::is_empty(self : FixedArray[T]) -> Bool {
#| self.length() == 0
#|}
#|pub fn[T : Compare] FixedArray::binary_search(
#| self : FixedArray[T],
#| value : T,
#|) -> Result[Int, Int] {
#| let len = self.length()
#| for i = 0, j = len; i < j; {
#| let h = i + (j - i) / 2
#| if self.unsafe_get(h) < value {
#| continue h + 1, j
#| } else {
#| continue i, h
#| }
#| } else {
#| if i < len && self.unsafe_get(i) == value {
#| Ok(i)
#| } else {
#| Err(i)
#| }
#| }
#|}
#|#locals(cmp)
#|pub fn[T] FixedArray::binary_search_by(
#| self : FixedArray[T],
#| cmp : (T) -> Int raise?,
#|) -> Result[Int, Int] raise? {
#| let len = self.length()
#| for i = 0, j = len; i < j; {
#| let h = i + (j - i) / 2
#| if cmp(self.unsafe_get(h)) < 0 {
#| continue h + 1, j
#| } else {
#| continue i, h
#| }
#| } else {
#| if i < len && cmp(self.unsafe_get(i)) == 0 {
#| Ok(i)
#| } else {
#| Err(i)
#| }
#| }
#|}
),
"fixedarray_block.mbt": (
#|#intrinsic("%fixedarray.copy")
#|#coverage.skip
#|pub fn[A] FixedArray::unsafe_blit(
#| dst : FixedArray[A],
#| dst_offset : Int,
#| src : FixedArray[A],
#| src_offset : Int,
#| len : Int,
#|) -> Unit {
#| if physical_equal(dst, src) && dst_offset < src_offset {
#| for i in 0..= 0; i = i - 1 {
#| dst[dst_offset + i] = src[src_offset + i]
#| }
#| }
#|}
#|#intrinsic("%fixedarray.copy")
#|#coverage.skip
#|fn[T] UninitializedArray::unsafe_blit_fixed(
#| dst : UninitializedArray[T],
#| dst_offset : Int,
#| src : FixedArray[T],
#| src_offset : Int,
#| len : Int,
#|) -> Unit {
#| for i = len - 1; i >= 0; i = i - 1 {
#| dst[dst_offset + i] = src[src_offset + i]
#| }
#|}
#|pub fn[A] FixedArray::blit_to(
#| self : FixedArray[A],
#| dst : FixedArray[A],
#| len~ : Int,
#| src_offset? : Int = 0,
#| dst_offset? : Int = 0,
#|) -> Unit {
#| guard dst_offset >= 0 &&
#| src_offset >= 0 &&
#| dst_offset + len <= dst.length() &&
#| src_offset + len <= self.length() else {
#| abort(
#| "bounds check failed: dst_offset = \{dst_offset}, src_offset = \{src_offset}, len = \{len}, dst.length = \{dst.length()}, self.length = \{self.length()}",
#| )
#| }
#| FixedArray::unsafe_blit(dst, dst_offset, self, src_offset, len)
#|}
),
"hasher.mbt": (
#|const GPRIME1 : UInt = 0x9E3779B1
#|const GPRIMES2 : UInt = 0x85EBCA77
#|const GPRIME3 : UInt = 0xC2B2AE3D
#|const GPRIME4 : UInt = 0x27D4EB2F
#|const GPRIME5 : UInt = 0x165667B1
#|struct Hasher {
#| mut acc : UInt
#|}
#|pub fn Hasher::new(seed? : Int = 0) -> Hasher {
#| { acc: seed.reinterpret_as_uint() + GPRIME5 }
#|}
#|pub fn[T : Hash] Hasher::combine(self : Hasher, value : T) -> Unit {
#| value.hash_combine(self)
#|}
#|pub fn Hasher::combine_unit(self : Hasher) -> Unit {
#| self.combine_uint(0)
#|}
#|pub fn Hasher::combine_bool(self : Hasher, value : Bool) -> Unit {
#| self.combine_uint(if value { 1 } else { 0 })
#|}
#|pub fn Hasher::combine_int(self : Hasher, value : Int) -> Unit {
#| self.combine_uint(value.reinterpret_as_uint())
#|}
#|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())
#|}
#|pub fn Hasher::combine_uint(self : Hasher, value : UInt) -> Unit {
#| self.acc += 4
#| self.consume4(value)
#|}
#|pub fn Hasher::combine_uint64(self : Hasher, value : UInt64) -> Unit {
#| self.combine_int64(value.reinterpret_as_int64())
#|}
#|pub fn Hasher::combine_double(self : Hasher, value : Double) -> Unit {
#| self.combine_int64(value.reinterpret_as_int64())
#|}
#|pub fn Hasher::combine_float(self : Hasher, value : Float) -> Unit {
#| self.combine_uint(value.reinterpret_as_uint())
#|}
#|pub fn Hasher::combine_byte(self : Hasher, value : Byte) -> Unit {
#| self.consume1(value)
#|}
#|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
#| }
#|}
#|pub fn Hasher::combine_string(self : Hasher, value : String) -> Unit {
#| for i in 0.. Unit {
#| self.combine_uint(value.to_uint())
#|}
#|pub fn Hasher::finalize(self : Hasher) -> Int {
#| self.avalanche().reinterpret_as_int()
#|}
#|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
#|}
#|fn Hasher::consume4(self : Hasher, input : UInt) -> Unit {
#| self.acc = rotl(self.acc + input * GPRIME3, 17) * GPRIME4
#|}
#|fn Hasher::consume1(self : Hasher, input : Byte) -> Unit {
#| self.acc = rotl(self.acc + input.to_uint() * GPRIME5, 11) * GPRIME1
#|}
#|fn rotl(x : UInt, r : Int) -> UInt {
#| (x << r) | (x >> (32 - r))
#|}
#|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)
#| )
#|}
#|pub impl Hash for String with hash_combine(self, hasher) {
#| hasher.combine_string(self)
#|}
#|pub impl Hash for Int with hash(self) {
#| let self = self.reinterpret_as_uint()
#| let mut x = self ^ (self >> 17)
#| x = x * 0xed5ad4bb
#| x = x ^ (x >> 11)
#| x = x * 0xac4c1b51
#| x = x ^ (x >> 15)
#| x = x * 0x31848bab
#| x = x ^ (x >> 14)
#| x.reinterpret_as_int()
#|}
#|pub impl Hash for Int with hash_combine(self, hasher) {
#| hasher.combine_int(self)
#|}
#|pub impl Hash for UInt with hash_combine(self, hasher) {
#| hasher.combine_uint(self)
#|}
#|pub impl Hash for UInt64 with hash_combine(self, hasher) {
#| hasher.combine_uint64(self)
#|}
#|pub impl[X : Hash] Hash for X? with hash_combine(self, hasher) {
#| match self {
#| None => hasher.combine_int(0)
#| Some(x) => hasher..combine_int(1)..combine(x)
#| }
#|}
#|pub impl[T : Hash, E : Hash] Hash for Result[T, E] with hash_combine(
#| self,
#| hasher,
#|) {
#| match self {
#| Ok(x) => hasher..combine_int(0)..combine(x)
#| Err(x) => hasher..combine_int(1)..combine(x)
#| }
#|}
),
"int.mbt": (
#|pub fn Int::next_power_of_two(self : Int) -> Int {
#| guard self >= 0
#| if self <= 1 {
#| return 1
#| }
#| let max_power_of_two = 1073741824 // 2^30
#| if self > max_power_of_two {
#| return max_power_of_two
#| }
#| (2147483647 >> ((self - 1).clz() - 1)) + 1
#|}
#|pub fn Int::min(self : Int, other : Int) -> Int {
#| if self < other {
#| self
#| } else {
#| other
#| }
#|}
#|pub fn Int::max(self : Int, other : Int) -> Int {
#| if self > other {
#| self
#| } else {
#| other
#| }
#|}
#|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
#| }
#|}
#|pub fn Int::is_leading_surrogate(self : Int) -> Bool {
#| 0xD800 <= self && self <= 0xDBFF
#|}
#|pub fn Int::is_trailing_surrogate(self : Int) -> Bool {
#| 0xDC00 <= self && self <= 0xDFFF
#|}
#|pub fn Int::is_surrogate(self : Int) -> Bool {
#| 0xD800 <= self && self <= 0xDFFF
#|}
),
"int64_js.mbt": (
#|priv struct MyInt64 {
#| hi : Int
#| lo : Int
#|}
#|fn MyInt64::to_int64(self : MyInt64) -> Int64 = "%identity"
#|fn MyInt64::from_int64(value : Int64) -> MyInt64 = "%identity"
#|impl Neg for MyInt64 with neg(self : MyInt64) -> MyInt64 {
#| if self.lo == 0 {
#| { hi: self.hi.lnot() + 1, lo: 0 }
#| } else {
#| { hi: self.hi.lnot(), lo: self.lo.lnot() + 1 }
#| }
#|}
#|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 }
#|}
#|impl Add for MyInt64 with add(self : MyInt64, other : MyInt64) -> MyInt64 {
#| self.add_hi_lo(other.hi, other.lo)
#|}
#|impl Sub for MyInt64 with sub(self : MyInt64, other : MyInt64) -> MyInt64 {
#| if other.lo == 0 {
#| { hi: self.hi - other.hi, lo: self.lo }
#| } else {
#| self.add_hi_lo(other.hi.lnot(), other.lo.lnot() + 1)
#| }
#|}
#|impl Mul for MyInt64 with mul(self : MyInt64, other : MyInt64) -> MyInt64 {
#| let { hi: ahi, lo: alo } = self
#| let { hi: bhi, lo: blo } = other
#| let ahi = ahi.reinterpret_as_uint()
#| let alo = alo.reinterpret_as_uint()
#| let bhi = bhi.reinterpret_as_uint()
#| let blo = blo.reinterpret_as_uint()
#| let a48 = ahi >> 16
#| let a32 = ahi & 0xffff
#| let a16 = alo >> 16
#| let a00 = alo & 0xffff
#| let b48 = bhi >> 16
#| let b32 = bhi & 0xffff
#| let b16 = blo >> 16
#| let b00 = blo & 0xffff
#| let c00 = a00 * b00
#| let c16 = c00 >> 16
#| let c00 = c00 & 0xffff
#| let c16 = c16 + a16 * b00
#| let c32 = c16 >> 16
#| let c16 = c16 & 0xffff
#| let c16 = c16 + a00 * b16
#| let c32 = c32 + (c16 >> 16)
#| let c16 = c16 & 0xffff
#| let c32 = c32 + a32 * b00
#| let c48 = c32 >> 16
#| let c32 = c32 & 0xffff
#| let c32 = c32 + a16 * b16
#| let c48 = c48 + (c32 >> 16)
#| let c32 = c32 & 0xffff
#| let c32 = c32 + a00 * b32
#| let c48 = c48 + (c32 >> 16)
#| let c32 = c32 & 0xffff
#| let c48 = c48 + a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48
#| let c48 = c48 & 0xffff
#| {
#| hi: ((c48 << 16) | c32).reinterpret_as_int(),
#| lo: ((c16 << 16) | c00).reinterpret_as_int(),
#| }
#|}
#|priv struct Int64WasmHelper {
#| div_s : (Int, Int, Int, Int) -> Int
#| div_u : (Int, Int, Int, Int) -> Int
#| rem_s : (Int, Int, Int, Int) -> Int
#| rem_u : (Int, Int, Int, Int) -> Int
#| get_high : () -> Int
#|}
#|extern "js" fn get_int64_wasm_helper() -> Int64WasmHelper =
#| #|function f() {
#| #| if (f._exports) return f._exports;
#| #| return f._exports = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 13, 2, 96, 0, 1, 127, 96, 4, 127, 127, 127, 127, 1, 127, 3, 7, 6, 0, 1, 1, 1, 1, 1, 6, 6, 1, 127, 1, 65, 0, 11, 7, 50, 6, 3, 109, 117, 108, 0, 1, 5, 100, 105, 118, 95, 115, 0, 2, 5, 100, 105, 118, 95, 117, 0, 3, 5, 114, 101, 109, 95, 115, 0, 4, 5, 114, 101, 109, 95, 117, 0, 5, 8, 103, 101, 116, 95, 104, 105, 103, 104, 0, 0, 10, 191, 1, 6, 4, 0, 35, 0, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 126, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 127, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 128, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 129, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11, 36, 1, 1, 126, 32, 0, 173, 32, 1, 173, 66, 32, 134, 132, 32, 2, 173, 32, 3, 173, 66, 32, 134, 132, 130, 34, 4, 66, 32, 135, 167, 36, 0, 32, 4, 167, 11])), {}).exports;
#| #|}
#|impl Div for MyInt64 with div(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_s)(alo, ahi, blo, bhi)
#| let hi = (exports.get_high)()
#| { hi, lo }
#|}
#|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 }
#|}
#|impl Mod for MyInt64 with mod(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_s)(alo, ahi, blo, bhi)
#| let hi = (exports.get_high)()
#| { hi, lo }
#|}
#|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 }
#|}
#|fn MyInt64::lnot(self : MyInt64) -> MyInt64 {
#| { hi: self.hi.lnot(), lo: self.lo.lnot() }
#|}
#|fn MyInt64::land(self : MyInt64, other : MyInt64) -> MyInt64 {
#| { hi: self.hi & other.hi, lo: self.lo & other.lo }
#|}
#|fn MyInt64::lor(self : MyInt64, other : MyInt64) -> MyInt64 {
#| { hi: self.hi | other.hi, lo: self.lo | other.lo }
#|}
#|fn MyInt64::lxor(self : MyInt64, other : MyInt64) -> MyInt64 {
#| { hi: self.hi ^ other.hi, lo: self.lo ^ other.lo }
#|}
#|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 }
#| }
#|}
#|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(),
#| }
#| }
#|}
#|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) }
#| }
#|}
#|fn MyInt64::clz(self : MyInt64) -> Int {
#| if self.hi != 0 {
#| self.hi.clz()
#| } else {
#| 32 + self.lo.clz()
#| }
#|}
#|fn MyInt64::ctz(self : MyInt64) -> Int {
#| if self.lo != 0 {
#| self.lo.ctz()
#| } else {
#| 32 + self.hi.ctz()
#| }
#|}
#|fn MyInt64::popcnt(self : MyInt64) -> Int {
#| self.hi.popcnt() + self.lo.popcnt()
#|}
#|impl Eq for MyInt64 with equal(self : MyInt64, other : MyInt64) -> Bool {
#| self.hi == other.hi && self.lo == other.lo
#|}
#|extern "js" fn MyInt64::compare(self : MyInt64, other : MyInt64) -> Int =
#| #|(a, b) => {
#| #| const ahi = a.hi;
#| #| const bhi = b.hi;
#| #| if (ahi < bhi) {
#| #| return -1;
#| #| }
#| #| if (ahi > bhi) {
#| #| return 1;
#| #| }
#| #| const alo = a.lo >>> 0;
#| #| const blo = b.lo >>> 0;
#| #| if (alo < blo) {
#| #| return -1;
#| #| }
#| #| if (alo > blo) {
#| #| return 1;
#| #| }
#| #| return 0;
#| #|}
#|extern "js" fn MyInt64::compare_u(self : MyInt64, other : MyInt64) -> Int =
#| #|(a, b) => {
#| #| const ahi = a.hi >>> 0;
#| #| const bhi = b.hi >>> 0;
#| #| if (ahi < bhi) {
#| #| return -1;
#| #| }
#| #| if (ahi > bhi) {
#| #| return 1;
#| #| }
#| #| const alo = a.lo >>> 0;
#| #| const blo = b.lo >>> 0;
#| #| if (alo < blo) {
#| #| return -1;
#| #| }
#| #| if (alo > blo) {
#| #| return 1;
#| #| }
#| #| return 0;
#| #|}
#|fn MyInt64::from_int(value : Int) -> MyInt64 {
#| { hi: (value >> 31) & -1, lo: value | 0 }
#|}
#|fn MyInt64::to_int(self : MyInt64) -> Int {
#| self.lo
#|}
#|fn MyInt64::to_uint(self : MyInt64) -> UInt {
#| self.lo.reinterpret_as_uint()
#|}
#|fn MyInt64::extend_i32_u(value : Int) -> MyInt64 {
#| { hi: 0, lo: value }
#|}
#|extern "js" fn MyInt64::reinterpret_as_double(self : MyInt64) -> Double =
#| #|function f(a) {
#| #| let view = f._view;
#| #| if (view === undefined) {
#| #| view = f._view = new DataView(new ArrayBuffer(8));
#| #| }
#| #| view.setUint32(0, a.hi);
#| #| view.setUint32(4, a.lo);
#| #| return view.getFloat64(0);
#| #|}
#|extern "js" fn MyInt64::reinterpret_double(value : Double) -> MyInt64 =
#| #|function f(a) {
#| #| let view = f._view;
#| #| if (view === undefined) {
#| #| view = f._view = new DataView(new ArrayBuffer(8));
#| #| }
#| #| view.setFloat64(0, a);
#| #| const hi = view.getInt32(0);
#| #| const lo = view.getInt32(4);
#| #| return { hi, lo };
#| #|}
#|extern "js" fn MyInt64::trunc_double_u(value : Double) -> MyInt64 =
#| #|(a) => {
#| #| let hi = (a * (1 / 0x100000000)) | 0;
#| #| let lo = a >>> 0;
#| #| return { hi, lo };
#| #|}
#|extern "js" fn MyInt64::convert_to_double_u(self : MyInt64) -> Double =
#| #|(a) => (a.hi >>> 0) * 4294967296.0 + (a.lo >>> 0)
#|extern "js" fn MyInt64::convert_to_double(self : MyInt64) -> Double =
#| #|(a) => a.hi * 4294967296.0 + (a.lo >>> 0)
#|pub impl Neg for Int64 with neg(self : Int64) -> Int64 {
#| (-MyInt64::from_int64(self)).to_int64()
#|}
#|pub impl Add for Int64 with add(self : Int64, other : Int64) -> Int64 {
#| MyInt64::from_int64(self).add(MyInt64::from_int64(other)).to_int64()
#|}
#|pub impl Sub for Int64 with sub(self : Int64, other : Int64) -> Int64 {
#| MyInt64::from_int64(self).sub(MyInt64::from_int64(other)).to_int64()
#|}
#|pub impl Mul for Int64 with mul(self : Int64, other : Int64) -> Int64 {
#| MyInt64::from_int64(self).mul(MyInt64::from_int64(other)).to_int64()
#|}
#|pub impl Div for Int64 with div(self : Int64, other : Int64) -> Int64 {
#| MyInt64::from_int64(self).div(MyInt64::from_int64(other)).to_int64()
#|}
#|pub impl Mod for Int64 with mod(self : Int64, other : Int64) -> Int64 {
#| MyInt64::from_int64(self).mod(MyInt64::from_int64(other)).to_int64()
#|}
#|pub fn Int64::lnot(self : Int64) -> Int64 {
#| MyInt64::from_int64(self).lnot().to_int64()
#|}
#|pub impl BitAnd for Int64 with land(self : Int64, other : Int64) -> Int64 {
#| MyInt64::from_int64(self).land(MyInt64::from_int64(other)).to_int64()
#|}
#|pub impl BitOr for Int64 with lor(self : Int64, other : Int64) -> Int64 {
#| MyInt64::from_int64(self).lor(MyInt64::from_int64(other)).to_int64()
#|}
#|pub impl BitXOr for Int64 with lxor(self : Int64, other : Int64) -> Int64 {
#| MyInt64::from_int64(self).lxor(MyInt64::from_int64(other)).to_int64()
#|}
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn Int64::lsl(self : Int64, other : Int) -> Int64 {
#| MyInt64::from_int64(self).lsl(other).to_int64()
#|}
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn Int64::shl(self : Int64, other : Int) -> Int64 {
#| MyInt64::from_int64(self).lsl(other).to_int64()
#|}
#|#deprecated("Use UInt64 type and infix operator `>>` instead")
#|#coverage.skip
#|pub fn Int64::lsr(self : Int64, other : Int) -> Int64 {
#| MyInt64::from_int64(self).lsr(other).to_int64()
#|}
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn Int64::shr(self : Int64, other : Int) -> Int64 {
#| MyInt64::from_int64(self).asr(other).to_int64()
#|}
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn Int64::asr(self : Int64, other : Int) -> Int64 {
#| MyInt64::from_int64(self).asr(other).to_int64()
#|}
#|pub impl Shr for Int64 with shr(self : Int64, other : Int) -> Int64 {
#| MyInt64::from_int64(self).asr(other).to_int64()
#|}
#|pub impl Shl for Int64 with shl(self : Int64, other : Int) -> Int64 {
#| MyInt64::from_int64(self).lsl(other).to_int64()
#|}
#|pub fn Int64::ctz(self : Int64) -> Int {
#| MyInt64::from_int64(self).ctz()
#|}
#|pub fn Int64::clz(self : Int64) -> Int {
#| MyInt64::from_int64(self).clz()
#|}
#|pub fn Int64::popcnt(self : Int64) -> Int {
#| MyInt64::from_int64(self).popcnt()
#|}
#|pub impl Eq for Int64 with equal(self : Int64, other : Int64) -> Bool {
#| MyInt64::from_int64(self) == MyInt64::from_int64(other)
#|}
#|pub impl Compare for Int64 with compare(self : Int64, other : Int64) -> Int {
#| MyInt64::compare(MyInt64::from_int64(self), MyInt64::from_int64(other))
#|}
#|pub impl Default for Int64 with default() {
#| 0L
#|}
#|pub fn Int64::to_int(self : Int64) -> Int {
#| MyInt64::from_int64(self).to_int()
#|}
#|pub fn Int64::to_double(self : Int64) -> Double {
#| Double::convert_int64(self)
#|}
#|pub fn Int64::to_byte(self : Int64) -> Byte {
#| MyInt64::from_int64(self).to_int().to_byte()
#|}
#|pub fn Int64::to_int16(self : Int64) -> Int16 {
#| MyInt64::from_int64(self).to_int().to_int16()
#|}
#|pub fn Int64::to_uint16(self : Int64) -> UInt16 {
#| MyInt64::from_int64(self).to_int().to_uint16()
#|}
#|pub fn UInt64::extend_uint(value : UInt) -> UInt64 {
#| MyInt64::extend_i32_u(value.reinterpret_as_int()).to_uint64()
#|}
#|pub fn Int64::reinterpret_as_double(self : Int64) -> Double {
#| MyInt64::reinterpret_as_double(MyInt64::from_int64(self))
#|}
#|pub fn UInt64::reinterpret_as_double(self : UInt64) -> Double {
#| MyInt64::reinterpret_as_double(MyInt64::from_uint64(self))
#|}
#|pub fn Int::to_int64(self : Int) -> Int64 {
#| MyInt64::from_int(self).to_int64()
#|}
#|pub fn Int16::to_int64(self : Int16) -> Int64 {
#| MyInt64::from_int(self.to_int()).to_int64()
#|}
#|pub fn UInt16::to_int64(self : UInt16) -> Int64 {
#| MyInt64::from_int(self.to_int()).to_int64()
#|}
#|#deprecated("Use `reinterpret_as_int64` instead")
#|#coverage.skip
#|pub fn Double::reinterpret_as_i64(self : Double) -> Int64 {
#| MyInt64::reinterpret_double(self).to_int64()
#|}
#|pub fn Double::reinterpret_as_int64(self : Double) -> Int64 {
#| MyInt64::reinterpret_double(self).to_int64()
#|}
#|#deprecated("Use `reinterpret_as_uint64` instead")
#|#coverage.skip
#|pub fn Double::reinterpret_as_u64(self : Double) -> UInt64 {
#| MyInt64::reinterpret_double(self).to_uint64()
#|}
#|pub fn Double::reinterpret_as_uint64(self : Double) -> UInt64 {
#| MyInt64::reinterpret_double(self).to_uint64()
#|}
#|pub fn Double::convert_uint64(value : UInt64) -> Double {
#| MyInt64::convert_to_double_u(MyInt64::from_uint64(value))
#|}
#|fn Double::convert_int64(value : Int64) -> Double {
#| MyInt64::convert_to_double(MyInt64::from_int64(value))
#|}
#|fn MyInt64::to_uint64(self : MyInt64) -> UInt64 = "%identity"
#|fn MyInt64::from_uint64(value : UInt64) -> MyInt64 = "%identity"
#|#deprecated("Use `reinterpret_as_uint64` instead")
#|#coverage.skip
#|pub fn Int64::to_uint64(self : Int64) -> UInt64 = "%identity"
#|pub fn Int64::reinterpret_as_uint64(self : Int64) -> UInt64 = "%identity"
#|pub impl Add for UInt64 with add(self : UInt64, other : UInt64) -> UInt64 {
#| MyInt64::from_uint64(self).add(MyInt64::from_uint64(other)).to_uint64()
#|}
#|pub impl Sub for UInt64 with sub(self : UInt64, other : UInt64) -> UInt64 {
#| MyInt64::from_uint64(self).sub(MyInt64::from_uint64(other)).to_uint64()
#|}
#|pub impl Mul for UInt64 with mul(self : UInt64, other : UInt64) -> UInt64 {
#| MyInt64::from_uint64(self).mul(MyInt64::from_uint64(other)).to_uint64()
#|}
#|pub impl Div for UInt64 with div(self : UInt64, other : UInt64) -> UInt64 {
#| MyInt64::from_uint64(self).div_u(MyInt64::from_uint64(other)).to_uint64()
#|}
#|pub impl Mod for UInt64 with mod(self : UInt64, other : UInt64) -> UInt64 {
#| MyInt64::from_uint64(self).mod_u(MyInt64::from_uint64(other)).to_uint64()
#|}
#|#deprecated("Use reinterpret_as_int64 instead")
#|#coverage.skip
#|pub fn UInt64::to_int64(self : UInt64) -> Int64 = "%identity"
#|pub fn UInt64::reinterpret_as_int64(self : UInt64) -> Int64 = "%identity"
#|pub fn UInt64::to_uint(self : UInt64) -> UInt {
#| MyInt64::from_uint64(self).to_uint()
#|}
#|pub fn UInt64::to_int(self : UInt64) -> Int {
#| MyInt64::from_uint64(self).to_int()
#|}
#|pub fn UInt64::to_double(self : UInt64) -> Double {
#| Double::convert_uint64(self)
#|}
#|pub impl Compare for UInt64 with compare(self : UInt64, other : UInt64) -> Int {
#| MyInt64::from_uint64(self).compare_u(MyInt64::from_uint64(other))
#|}
#|pub impl Eq for UInt64 with equal(self : UInt64, other : UInt64) -> Bool {
#| MyInt64::from_uint64(self).equal(MyInt64::from_uint64(other))
#|}
#|pub fn UInt64::trunc_double(value : Double) -> UInt64 {
#| MyInt64::trunc_double_u(value).to_uint64()
#|}
#|pub impl BitAnd for UInt64 with land(self : UInt64, other : UInt64) -> UInt64 {
#| MyInt64::land(MyInt64::from_uint64(self), MyInt64::from_uint64(other)).to_uint64()
#|}
#|pub impl BitOr for UInt64 with lor(self : UInt64, other : UInt64) -> UInt64 {
#| MyInt64::lor(MyInt64::from_uint64(self), MyInt64::from_uint64(other)).to_uint64()
#|}
#|pub impl BitXOr for UInt64 with lxor(self : UInt64, other : UInt64) -> UInt64 {
#| MyInt64::lxor(MyInt64::from_uint64(self), MyInt64::from_uint64(other)).to_uint64()
#|}
#|pub fn UInt64::lnot(self : UInt64) -> UInt64 {
#| MyInt64::lnot(MyInt64::from_uint64(self)).to_uint64()
#|}
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn UInt64::lsl(self : UInt64, shift : Int) -> UInt64 {
#| MyInt64::lsl(MyInt64::from_uint64(self), shift).to_uint64()
#|}
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn UInt64::lsr(self : UInt64, shift : Int) -> UInt64 {
#| MyInt64::lsr(MyInt64::from_uint64(self), shift).to_uint64()
#|}
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn UInt64::shl(self : UInt64, shift : Int) -> UInt64 {
#| MyInt64::lsl(MyInt64::from_uint64(self), shift).to_uint64()
#|}
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn UInt64::shr(self : UInt64, shift : Int) -> UInt64 {
#| MyInt64::lsr(MyInt64::from_uint64(self), shift).to_uint64()
#|}
#|pub impl Shl for UInt64 with shl(self : UInt64, shift : Int) -> UInt64 {
#| MyInt64::lsl(MyInt64::from_uint64(self), shift).to_uint64()
#|}
#|pub impl Shr for UInt64 with shr(self : UInt64, shift : Int) -> UInt64 {
#| MyInt64::lsr(MyInt64::from_uint64(self), shift).to_uint64()
#|}
#|pub fn UInt64::clz(self : UInt64) -> Int {
#| MyInt64::from_uint64(self).clz()
#|}
#|pub fn UInt64::ctz(self : UInt64) -> Int {
#| MyInt64::from_uint64(self).ctz()
#|}
#|pub fn UInt64::popcnt(self : UInt64) -> Int {
#| MyInt64::from_uint64(self).popcnt()
#|}
#|pub fn Int64::to_float(self : Int64) -> Float {
#| self.to_double().to_float()
#|}
#|pub fn UInt64::to_float(self : UInt64) -> Float {
#| Double::convert_uint64(self).to_float()
#|}
),
"int64_nonjs.mbt": (
#|pub impl Neg for Int64 with neg(self : Int64) -> Int64 = "%i64_neg"
#|pub impl Add for Int64 with add(self, other) = "%i64_add"
#|pub impl Sub for Int64 with sub(self, other) = "%i64_sub"
#|pub impl Mul for Int64 with mul(self, other) = "%i64_mul"
#|pub impl Div for Int64 with div(self, other) = "%i64_div"
#|pub impl Mod for Int64 with mod(self, other) = "%i64_mod"
#|pub fn Int64::lnot(self : Int64) -> Int64 = "%i64_lnot"
#|pub impl BitAnd for Int64 with land(self, other) = "%i64_land"
#|pub impl BitOr for Int64 with lor(self, other) = "%i64_lor"
#|pub impl BitXOr for Int64 with lxor(self, other) = "%i64_lxor"
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn Int64::lsl(self : Int64, other : Int) -> Int64 = "%i64_shl"
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn Int64::shl(self : Int64, other : Int) -> Int64 = "%i64_shl"
#|#deprecated("Use UInt64 type and infix operator `>>` instead")
#|#coverage.skip
#|pub fn Int64::lsr(self : Int64, other : Int) -> Int64 = "%u64.shr"
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn Int64::asr(self : Int64, other : Int) -> Int64 = "%i64_shr"
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn Int64::shr(self : Int64, other : Int) -> Int64 = "%i64_shr"
#|pub impl Shl for Int64 with shl(self, other) = "%i64_shl"
#|pub impl Shr for Int64 with shr(self, other) = "%i64_shr"
#|pub fn Int64::ctz(self : Int64) -> Int = "%i64_ctz"
#|pub fn Int64::clz(self : Int64) -> Int = "%i64_clz"
#|pub fn Int64::popcnt(self : Int64) -> Int = "%i64_popcnt"
#|pub impl Eq for Int64 with equal(self : Int64, other : Int64) -> Bool = "%i64_eq"
#|pub impl Compare for Int64 with compare(self, other) = "%i64_compare"
#|pub impl Default for Int64 with default() = "%i64_default"
#|pub fn Int64::to_int(self : Int64) -> Int = "%i64_to_i32"
#|pub fn Int64::to_double(self : Int64) -> Double = "%i64_to_f64"
#|pub fn Int64::reinterpret_as_double(self : Int64) -> Double = "%i64_to_f64_reinterpret"
#|pub fn UInt64::reinterpret_as_double(self : UInt64) -> Double = "%i64_to_f64_reinterpret"
#|pub fn Int64::to_byte(self : Int64) -> Byte = "%i64_to_byte"
#|pub fn Int64::to_int16(self : Int64) -> Int16 = "%i64_to_i16"
#|pub fn Int64::to_uint16(self : Int64) -> UInt16 = "%i64_to_u16"
#|pub fn UInt64::trunc_double(val : Double) -> UInt64 = "%f64.to_u64"
#|pub fn Int64::to_float(self : Int64) -> Float = "%i64.to_f32"
#|pub fn UInt64::extend_uint(val : UInt) -> UInt64 = "%u32.to_u64"
#|pub fn Int::to_int64(self : Int) -> Int64 = "%i32_to_i64"
#|pub fn Int16::to_int64(self : Int16) -> Int64 = "%i16_to_i64"
#|pub fn UInt16::to_int64(self : UInt16) -> Int64 = "%u16_to_i64"
#|#deprecated("Use `reinterpret_as_int64` instead")
#|#coverage.skip
#|pub fn Double::reinterpret_as_i64(self : Double) -> Int64 = "%f64_to_i64_reinterpret"
#|pub fn Double::reinterpret_as_int64(self : Double) -> Int64 = "%f64_to_i64_reinterpret"
#|#deprecated("Use `reinterpret_as_uint64` instead")
#|#coverage.skip
#|pub fn Double::reinterpret_as_u64(self : Double) -> UInt64 = "%f64_to_i64_reinterpret"
#|pub fn Double::reinterpret_as_uint64(self : Double) -> UInt64 = "%f64_to_i64_reinterpret"
#|pub fn Double::convert_uint64(val : UInt64) -> Double = "%u64.to_f64"
#|#deprecated("Use `reinterpret_as_uint64` instead")
#|#coverage.skip
#|pub fn Int64::to_uint64(self : Int64) -> UInt64 = "%i64.to_u64_reinterpret"
#|pub fn Int64::reinterpret_as_uint64(self : Int64) -> UInt64 = "%i64.to_u64_reinterpret"
#|#deprecated("Use `reinterpret_as_int64` instead")
#|#coverage.skip
#|pub fn UInt64::to_int64(self : UInt64) -> Int64 = "%u64.to_i64_reinterpret"
#|pub fn UInt64::reinterpret_as_int64(self : UInt64) -> Int64 = "%u64.to_i64_reinterpret"
#|pub fn UInt64::to_uint(self : UInt64) -> UInt = "%u64.to_u32"
#|pub fn UInt64::to_int(self : UInt64) -> Int = "%u64.to_i32"
#|pub fn UInt64::to_double(self : UInt64) -> Double = "%u64.to_f64"
#|pub impl Add for UInt64 with add(self, other) = "%u64.add"
#|pub impl Sub for UInt64 with sub(self, other) = "%u64.sub"
#|pub impl Mul for UInt64 with mul(self, other) = "%u64.mul"
#|pub impl Div for UInt64 with div(self, other) = "%u64.div"
#|pub impl Mod for UInt64 with mod(self, other) = "%u64.mod"
#|pub impl Compare for UInt64 with compare(self, other) = "%u64.compare"
#|pub impl Eq for UInt64 with equal(self : UInt64, other : UInt64) -> Bool = "%u64.eq"
#|pub impl BitAnd for UInt64 with land(self, other) = "%u64.bitand"
#|pub impl BitOr for UInt64 with lor(self, other) = "%u64.bitor"
#|pub impl BitXOr for UInt64 with lxor(self, other) = "%u64.bitxor"
#|pub fn UInt64::lnot(self : UInt64) -> UInt64 = "%u64.bitnot"
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn UInt64::lsl(self : UInt64, shift : Int) -> UInt64 = "%u64.shl"
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn UInt64::shl(self : UInt64, shift : Int) -> UInt64 = "%u64.shl"
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn UInt64::shr(self : UInt64, shift : Int) -> UInt64 = "%u64.shr"
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn UInt64::lsr(self : UInt64, shift : Int) -> UInt64 = "%u64.shr"
#|pub impl Shl for UInt64 with shl(self, shift) = "%u64.shl"
#|pub impl Shr for UInt64 with shr(self, shift) = "%u64.shr"
#|pub fn UInt64::clz(self : UInt64) -> Int = "%u64.clz"
#|pub fn UInt64::ctz(self : UInt64) -> Int = "%u64.ctz"
#|pub fn UInt64::popcnt(self : UInt64) -> Int = "%u64.popcnt"
#|pub fn UInt64::to_float(self : UInt64) -> Float = "%u64.to_f32"
),
"intrinsics.mbt": (
#|pub fn[T] ignore(t : T) -> Unit = "%ignore"
#|pub fn[T] physical_equal(a : T, b : T) -> Bool = "%refeq"
#|pub fnalias @abort.abort
#|pub fn[T] panic() -> T = "%panic"
#|pub fn not(x : Bool) -> Bool = "%bool_not"
#|pub impl Eq for Bool with equal(self : Bool, other : Bool) -> Bool = "%bool_eq"
#|#deprecated("Use `compare` instead")
#|#coverage.skip
#|pub fn Bool::op_compare(self : Bool, other : Bool) -> Int = "%bool_compare"
#|pub impl Compare for Bool with compare(self, other) = "%bool_compare"
#|pub impl Default for Bool with default() = "%bool_default"
#|pub impl Neg for Int with neg(self) = "%i32_neg"
#|pub impl Add for Int with add(self, other) = "%i32_add"
#|pub impl Sub for Int with sub(self, other) = "%i32_sub"
#|pub impl Mul for Int with mul(self, other) = "%i32_mul"
#|pub impl Div for Int with div(self, other) = "%i32_div"
#|pub impl Mod for Int with mod(self, other) = "%i32_mod"
#|pub fn Int::lnot(self : Int) -> Int = "%i32_lnot"
#|pub fn Int::land(self : Int, other : Int) -> Int = "%i32_land"
#|pub fn Int::lor(self : Int, other : Int) -> Int = "%i32_lor"
#|pub fn Int::lxor(self : Int, other : Int) -> Int = "%i32_lxor"
#|pub impl Shl for Int with shl(self, other) = "%i32_shl"
#|pub impl Shr for Int with shr(self, other) = "%i32_shr"
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn Int::lsl(self : Int, other : Int) -> Int = "%i32_shl"
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn Int::shl(self : Int, other : Int) -> Int = "%i32_shl"
#|#deprecated("Use UInt type and infix operator `>>` instead")
#|#coverage.skip
#|pub fn Int::lsr(self : Int, other : Int) -> Int {
#| (self.reinterpret_as_uint() >> other).reinterpret_as_int()
#|}
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn Int::asr(self : Int, other : Int) -> Int = "%i32_shr"
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn Int::shr(self : Int, other : Int) -> Int = "%i32_shr"
#|pub fn Int::ctz(self : Int) -> Int = "%i32_ctz"
#|pub fn Int::clz(self : Int) -> Int = "%i32_clz"
#|pub fn Int::popcnt(self : Int) -> Int = "%i32_popcnt"
#|pub impl Eq for Int with equal(self : Int, other : Int) -> Bool = "%i32_eq"
#|pub impl Compare for Int with compare(self, other) = "%i32_compare"
#|pub fn Int::is_pos(self : Int) -> Bool = "%i32_is_pos"
#|pub fn Int::is_neg(self : Int) -> Bool = "%i32_is_neg"
#|pub fn Int::is_non_pos(self : Int) -> Bool = "%i32_is_non_pos"
#|pub fn Int::is_non_neg(self : Int) -> Bool = "%i32_is_non_neg"
#|pub impl Default for Int with default() = "%i32_default"
#|pub fn Int::to_double(self : Int) -> Double = "%i32_to_f64"
#|pub fn UInt::trunc_double(val : Double) -> UInt = "%f64.to_u32"
#|pub fn Int::reinterpret_as_uint(self : Int) -> UInt = "%i32.to_u32_reinterpret"
#|#deprecated("Use `reinterpret_as_uint` instead")
#|#coverage.skip
#|pub fn Int::to_uint(self : Int) -> UInt = "%i32.to_u32_reinterpret"
#|pub fn Int::to_uint64(self : Int) -> UInt64 {
#| self.to_int64().reinterpret_as_uint64()
#|}
#|pub impl Neg for Double with neg(self) = "%f64_neg"
#|pub impl Add for Double with add(self, other) = "%f64_add"
#|pub impl Sub for Double with sub(self, other) = "%f64_sub"
#|pub impl Mul for Double with mul(self, other) = "%f64_mul"
#|pub impl Div for Double with div(self, other) = "%f64_div"
#|pub fn Double::sqrt(self : Double) -> Double = "%f64_sqrt"
#|pub impl Eq for Double with equal(self : Double, other : Double) -> Bool = "%f64_eq"
#|pub fn Double::op_neq(self : Double, other : Double) -> Bool = "%f64_ne"
#|pub impl Compare for Double with compare(self, other) = "%f64_compare"
#|pub impl Default for Double with default() = "%f64_default"
#|pub fn Double::convert_uint(val : UInt) -> Double = "%u32.to_f64"
#|pub fn Char::to_int(self : Char) -> Int = "%char_to_int"
#|pub fn Char::to_uint(self : Char) -> UInt {
#| self.to_int().reinterpret_as_uint()
#|}
#|#deprecated("Use `Int::unsafe_to_char` instead, and use `Int::to_char` for safe conversion")
#|pub fn Char::from_int(val : Int) -> Char = "%char_from_int"
#|pub impl Eq for Char with equal(self : Char, other : Char) -> Bool = "%char_eq"
#|pub impl Compare for Char with compare(self, other) = "%char_compare"
#|pub impl Default for Char with default() = "%char_default"
#|pub fn Bytes::op_get(self : Bytes, idx : Int) -> Byte = "%bytes_get"
#|#internal(unsafe, "Panic if index is out of bounds")
#|pub fn Bytes::unsafe_get(self : Bytes, idx : Int) -> Byte = "%bytes.unsafe_get"
#|pub fn Bytes::length(self : Bytes) -> Int = "%bytes_length"
#|pub fn Bytes::make(len : Int, init : Byte) -> Bytes {
#| if len < 0 {
#| return []
#| }
#| Bytes::unsafe_make(len, init)
#|}
#|fn Bytes::unsafe_make(len : Int, init : Byte) -> Bytes = "%bytes_make"
#|pub fn Bytes::new(len : Int) -> Bytes {
#| Bytes::make(len, b'\x00')
#|}
#|pub fn Int::to_byte(self : Int) -> Byte = "%i32_to_byte"
#|pub fn Int::unsafe_to_char(self : Int) -> Char = "%char_from_int"
#|pub fn Int::to_char(self : Int) -> Char? {
#| if self is (0..=0xD7FF) || self is (0xE000..=0x10FFFF) {
#| Some(self.unsafe_to_char())
#| } else {
#| None
#| }
#|}
#|pub fn UInt64::to_byte(self : UInt64) -> Byte {
#| self.to_int().to_byte()
#|}
#|pub fn[T] FixedArray::op_get(self : FixedArray[T], idx : Int) -> T = "%fixedarray.get"
#|#internal(unsafe, "Panic if index is out of bounds")
#|pub fn[T] FixedArray::unsafe_get(self : FixedArray[T], idx : Int) -> T = "%fixedarray.unsafe_get"
#|#internal(unsafe, "Panic if index is out of bounds")
#|pub fn[T] FixedArray::unsafe_set(
#| self : FixedArray[T],
#| idx : Int,
#| val : T,
#|) -> Unit = "%fixedarray.unsafe_set"
#|#intrinsic("%fixedarray.set")
#|pub fn[T] FixedArray::op_set(self : FixedArray[T], idx : Int, val : T) -> Unit = "%fixedarray.set"
#|pub fn[T] FixedArray::set(self : FixedArray[T], idx : Int, val : T) -> Unit = "%fixedarray.set"
#|pub fn[T] FixedArray::length(self : FixedArray[T]) -> Int = "%fixedarray.length"
#|pub fn[T] FixedArray::make(len : Int, init : T) -> FixedArray[T] = "%fixedarray.make"
#|pub fn String::length(self : String) -> Int = "%string_length"
#|#deprecated("use `length` instead")
#|pub fn String::charcode_length(self : String) -> Int = "%string_length"
#|pub fn String::op_get(self : String, idx : Int) -> Int = "%string_get"
#|#internal(unsafe, "Panic if index is out of bounds.")
#|pub fn String::unsafe_charcode_at(self : String, idx : Int) -> Int = "%string.unsafe_get"
#|pub impl Add for String with add(self, other) = "%string_add"
#|pub impl Eq for String with equal(self : String, other : String) -> Bool = "%string_eq"
#|pub fn String::to_string(self : String) -> String = "%string_to_string"
#|priv type UnsafeMaybeUninit[_]
#|pub fn Byte::to_int(self : Byte) -> Int = "%byte_to_int"
#|pub fn Byte::to_char(self : Byte) -> Char {
#| self.to_int().unsafe_to_char()
#|}
#|pub fn Byte::to_int64(self : Byte) -> Int64 {
#| self.to_int().to_int64()
#|}
#|pub fn UInt::reinterpret_as_int(self : UInt) -> Int = "%u32.to_i32_reinterpret"
#|#deprecated("Use `reinterpret_as_int` instead")
#|#coverage.skip
#|pub fn UInt::to_int(self : UInt) -> Int = "%u32.to_i32_reinterpret"
#|pub impl Add for UInt with add(self, other) = "%u32.add"
#|pub impl Sub for UInt with sub(self, other) = "%u32.sub"
#|pub impl Mul for UInt with mul(self, other) = "%u32.mul"
#|pub impl Div for UInt with div(self, other) = "%u32.div"
#|pub impl Mod for UInt with mod(self, other) = "%u32.mod"
#|pub impl Eq for UInt with equal(self : UInt, other : UInt) -> Bool = "%u32.eq"
#|pub fn UInt::op_neq(self : UInt, other : UInt) -> Bool = "%u32.ne"
#|pub impl Compare for UInt with compare(self, other) = "%u32.compare"
#|pub fn UInt::land(self : UInt, other : UInt) -> UInt = "%u32.bitand"
#|pub fn UInt::lor(self : UInt, other : UInt) -> UInt = "%u32.bitor"
#|pub fn UInt::lxor(self : UInt, other : UInt) -> UInt = "%u32.bitxor"
#|pub fn UInt::lnot(self : UInt) -> UInt = "%u32.bitnot"
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn UInt::lsl(self : UInt, shift : Int) -> UInt = "%u32.shl"
#|#deprecated("Use infix operator `<<` instead")
#|#coverage.skip
#|pub fn UInt::shl(self : UInt, shift : Int) -> UInt = "%u32.shl"
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn UInt::lsr(self : UInt, shift : Int) -> UInt = "%u32.shr"
#|#deprecated("Use infix operator `>>` instead")
#|#coverage.skip
#|pub fn UInt::shr(self : UInt, shift : Int) -> UInt = "%u32.shr"
#|pub impl Shl for UInt with shl(self, shift) = "%u32.shl"
#|pub impl Shr for UInt with shr(self, shift) = "%u32.shr"
#|pub fn UInt::clz(self : UInt) -> Int = "%u32.clz"
#|pub fn UInt::ctz(self : UInt) -> Int = "%u32.ctz"
#|pub fn UInt::popcnt(self : UInt) -> Int = "%u32.popcnt"
#|pub fn UInt::to_uint64(self : UInt) -> UInt64 {
#| UInt64::extend_uint(self)
#|}
#|pub fn UInt::to_byte(self : UInt) -> Byte {
#| self.reinterpret_as_int().to_byte()
#|}
#|pub fn UInt::to_double(self : UInt) -> Double = "%u32.to_f64"
#|pub impl Neg for Float with neg(self) = "%f32.neg"
#|pub impl Add for Float with add(self, other) = "%f32.add"
#|pub impl Sub for Float with sub(self, other) = "%f32.sub"
#|pub impl Mul for Float with mul(self, other) = "%f32.mul"
#|pub impl Div for Float with div(self, other) = "%f32.div"
#|pub fn Float::sqrt(self : Float) -> Float = "%f32.sqrt"
#|pub impl Eq for Float with equal(self : Float, other : Float) -> Bool = "%f32.eq"
#|pub fn Float::op_neq(self : Float, other : Float) -> Bool = "%f32.ne"
#|pub impl Compare for Float with compare(self, other) = "%f32.compare"
#|pub fn Float::to_double(self : Float) -> Double = "%f32.to_f64"
#|pub fn Float::reinterpret_as_int(self : Float) -> Int = "%f32.to_i32_reinterpret"
#|pub fn Float::reinterpret_as_uint(self : Float) -> UInt = "%f32.to_i32_reinterpret"
#|pub fn Int::to_float(self : Int) -> Float = "%i32.to_f32"
#|pub fn Int::reinterpret_as_float(self : Int) -> Float = "%i32.to_f32_reinterpret"
#|pub fn UInt::reinterpret_as_float(self : UInt) -> Float = "%i32.to_f32_reinterpret"
#|pub fn Byte::to_float(self : Byte) -> Float = "%byte.to_f32"
#|pub fn Byte::to_double(self : Byte) -> Double {
#| self.to_int().to_double()
#|}
#|pub fn Double::to_float(self : Double) -> Float = "%f64.to_f32"
#|pub fn UInt::to_float(self : UInt) -> Float = "%u32.to_f32"
#|pub fn Int16::to_int(self : Int16) -> Int = "%i16_to_i32"
#|pub fn Int16::to_byte(self : Int16) -> Byte = "%i16_to_byte"
#|pub fn Int::to_int16(self : Int) -> Int16 = "%i32_to_i16"
#|pub fn Byte::to_int16(self : Byte) -> Int16 = "%byte_to_i16"
#|pub fn UInt16::to_int(self : UInt16) -> Int = "%u16_to_i32"
#|pub fn UInt16::to_byte(self : UInt16) -> Byte = "%u16_to_byte"
#|pub fn Int::to_uint16(self : Int) -> UInt16 = "%i32_to_u16"
#|pub fn Byte::to_uint16(self : Byte) -> UInt16 = "%byte_to_u16"
),
"iter.mbt": (
#|struct Iter[T](((T) -> IterResult) -> IterResult)
#|pub fn[T] Iter::run(self : Iter[T], f : (T) -> IterResult) -> IterResult {
#| self(f)
#|}
#|pub fn[T] Iter::just_run(self : Iter[T], f : (T) -> IterResult) -> Unit {
#| self(f) |> ignore
#|}
#|pub(all) enum IterResult {
#| IterEnd // false
#| IterContinue // true
#|} derive(Eq)
#|pub impl[T : Show] Show for Iter[T] with output(self, logger) {
#| logger.write_iter(self)
#|}
#|pub fn[T] Iter::each(self : Iter[T], f : (T) -> Unit raise?) -> Unit raise? {
#| for a in self {
#| f(a)
#| }
#|}
#|pub fn[T] Iter::any(self : Iter[T], f : (T) -> Bool) -> Bool {
#| self.run(k => if f(k) { IterEnd } else { IterContinue }) != IterContinue
#|}
#|pub fn[T] Iter::all(self : Iter[T], f : (T) -> Bool) -> Bool {
#| self.run(k => if !f(k) { IterEnd } else { IterContinue }) == IterContinue
#|}
#|pub fn[T] Iter::eachi(
#| self : Iter[T],
#| f : (Int, T) -> Unit raise?,
#|) -> Unit raise? {
#| let mut i = 0
#| for a in self {
#| f(i, a)
#| i += 1
#| }
#|}
#|#intrinsic("%iter.reduce")
#|#locals(f)
#|pub fn[T, B] Iter::fold(
#| self : Iter[T],
#| init~ : B,
#| f : (B, T) -> B raise?,
#|) -> B raise? {
#| let mut acc = init
#| for a in self {
#| acc = f(acc, a)
#| }
#| acc
#|}
#|pub fn[T] Iter::count(self : Iter[T]) -> Int {
#| self.fold((acc, _) => acc + 1, init=0)
#|}
#|pub fn[T] Iter::new(f : ((T) -> IterResult) -> IterResult) -> Iter[T] {
#| Iter(f)
#|}
#|pub fn[T] Iter::empty() -> Iter[T] {
#| _ => IterContinue
#|}
#|pub fn[T] Iter::singleton(a : T) -> Iter[T] {
#| yield_ => yield_(a)
#|}
#|#intrinsic("%iter.repeat")
#|pub fn[T] Iter::repeat(a : T) -> Iter[T] {
#| yield_ => loop yield_(a) {
#| IterContinue => continue yield_(a)
#| IterEnd => IterEnd
#| }
#|}
#|pub fn Int::until(
#| self : Int,
#| end : Int,
#| step? : Int = 1,
#| inclusive? : Bool = false,
#|) -> Iter[Int] {
#| if step == 0 {
#| return Iter::empty()
#| }
#| yield_ => {
#| let mut i = self
#| while (step > 0 && i < end) ||
#| (step < 0 && i > end) ||
#| (inclusive && i == end) {
#| if yield_(i) == IterEnd {
#| break IterEnd
#| }
#| let next = i + step
#| if (step > 0 && next >= i) || (step < 0 && next <= i) {
#| i = next
#| } else {
#| break IterContinue
#| }
#| } else {
#| IterContinue
#| }
#| }
#|}
#|pub fn Int64::until(
#| self : Int64,
#| end : Int64,
#| step? : Int64 = 1L,
#| inclusive? : Bool = false,
#|) -> Iter[Int64] {
#| if step == 0 {
#| return Iter::empty()
#| }
#| yield_ => {
#| let mut i = self
#| while (step > 0 && i < end) ||
#| (step < 0 && i > end) ||
#| (inclusive && i == end) {
#| if yield_(i) == IterEnd {
#| break IterEnd
#| }
#| let next = i + step
#| if (step > 0 && next >= i) || (step < 0 && next <= i) {
#| i = next
#| } else {
#| break IterContinue
#| }
#| } else {
#| IterContinue
#| }
#| }
#|}
#|pub fn Float::until(
#| self : Float,
#| end : Float,
#| step? : Float = 1.0,
#| inclusive? : Bool = false,
#|) -> Iter[Float] {
#| if step == 0.0 {
#| return Iter::empty()
#| }
#| yield_ => {
#| let mut i = self
#| while (step > 0.0 && i < end) ||
#| (step < 0.0 && i > end) ||
#| (inclusive && i == end) {
#| if yield_(i) == IterEnd {
#| break IterEnd
#| }
#| let next = i + step
#| if (step > 0.0 && next >= i) || (step < 0.0 && next <= i) {
#| i = next
#| } else {
#| break IterContinue
#| }
#| } else {
#| IterContinue
#| }
#| }
#|}
#|pub fn Double::until(
#| self : Double,
#| end : Double,
#| step? : Double = 1.0,
#| inclusive? : Bool = false,
#|) -> Iter[Double] {
#| if step == 0.0 {
#| return Iter::empty()
#| }
#| yield_ => {
#| let mut i = self
#| while (step > 0.0 && i < end) ||
#| (step < 0.0 && i > end) ||
#| (inclusive && i == end) {
#| if yield_(i) == IterEnd {
#| break IterEnd
#| }
#| let next = i + step
#| if (step > 0.0 && next >= i) || (step < 0.0 && next <= i) {
#| i = next
#| } else {
#| break IterContinue
#| }
#| } else {
#| IterContinue
#| }
#| }
#|}
#|#intrinsic("%iter.filter")
#|pub fn[T] Iter::filter(self : Iter[T], f : (T) -> Bool) -> Iter[T] {
#| yield_ => self.run(a => if f(a) { yield_(a) } else { IterContinue })
#|}
#|#intrinsic("%iter.map")
#|pub fn[T, R] Iter::map(self : Iter[T], f : (T) -> R) -> Iter[R] {
#| yield_ => self.run(a => yield_(f(a)))
#|}
#|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))
#| })
#| }
#|}
#|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
#| })
#|}
#|#deprecated("Use `Iter::filter_map` instead")
#|pub fn[A, B] Iter::map_option(self : Iter[A], f : (A) -> B?) -> Iter[B] {
#| self.filter_map(f)
#|}
#|#intrinsic("%iter.flat_map")
#|pub fn[T, R] Iter::flat_map(self : Iter[T], f : (T) -> Iter[R]) -> Iter[R] {
#| yield_ => self.run(x => f(x).run(yield_))
#|}
#|pub fn[T] Iter::flatten(self : Iter[Iter[T]]) -> Iter[T] {
#| yield_ => self.run(x => x.run(yield_))
#|}
#|pub fn[T] Iter::tap(self : Iter[T], f : (T) -> Unit) -> Iter[T] {
#| self.map(a => {
#| f(a)
#| a
#| })
#|}
#|#intrinsic("%iter.take")
#|pub fn[T] Iter::take(self : Iter[T], n : Int) -> Iter[T] {
#| yield_ => {
#| 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
#| }
#|}
#|pub fn[T] Iter::take_while(self : Iter[T], f : (T) -> Bool) -> Iter[T] {
#| yield_ => {
#| let mut r : IterResult = IterContinue
#| self.just_run(a => if f(a) {
#| if yield_(a) == IterContinue {
#| IterContinue
#| } else {
#| r = IterEnd
#| IterEnd
#| }
#| } else {
#| IterEnd
#| })
#| r
#| }
#|}
#|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
#| }
#|}
#|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)
#| })
#| }
#|}
#|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)
#| })
#| }
#|}
#|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
#| }
#|}
#|pub fn[T] Iter::peek(self : Iter[T]) -> T? {
#| let mut first = None
#| self.just_run(a => {
#| first = Some(a)
#| IterEnd
#| })
#| first
#|}
#|#deprecated("Use `Iter::singleton(a) + self` instead")
#|pub fn[T] Iter::prepend(self : Iter[T], a : T) -> Iter[T] {
#| yield_ => if yield_(a) == IterContinue { self.run(yield_) } else { IterEnd }
#|}
#|#deprecated("Use `self + Iter::singleton(a)` instead")
#|pub fn[T] Iter::append(self : Iter[T], a : T) -> Iter[T] {
#| yield_ => if self.run(yield_) == IterContinue { yield_(a) } else { IterEnd }
#|}
#|#intrinsic("%iter.concat")
#|pub fn[T] Iter::concat(self : Iter[T], other : Iter[T]) -> Iter[T] {
#| yield_ => if self.run(yield_) == IterContinue {
#| other.run(yield_)
#| } else {
#| IterEnd
#| }
#|}
#|pub impl[T] Add for Iter[T] with add(self, other) {
#| Iter::concat(self, other)
#|}
#|pub fn[T] Iter::to_array(self : Iter[T]) -> Array[T] {
#| let result = []
#| for e in self {
#| result.push(e)
#| }
#| result
#|}
#|pub fn[T] Iter::collect(self : Iter[T]) -> Array[T] {
#| let result = []
#| self.each(e => result.push(e))
#| result
#|}
#|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()
#|}
#|pub fn[T] Iter::iter(self : Iter[T]) -> Iter[T] {
#| self
#|}
#|pub fn[A] Iter::last(self : Iter[A]) -> A? {
#| let mut last = None
#| for a in self {
#| last = Some(a)
#| }
#| last
#|}
#|pub fn[A] Iter::head(self : Iter[A]) -> A? {
#| for i in self {
#| break Some(i)
#| } else {
#| None
#| }
#|}
#|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)
#| })
#| }
#|}
#|pub fn[A] Iter::op_as_view(
#| self : Iter[A],
#| start? : Int = 0,
#| end? : Int,
#|) -> Iter[A] {
#| match end {
#| Some(end) => self.drop(start).take(end - start)
#| None => self.drop(start)
#| }
#|}
#|pub fn[A : Eq] Iter::contains(self : Iter[A], value : A) -> Bool {
#| for v in self {
#| if v == value {
#| break true
#| }
#| } else {
#| false
#| }
#|}
#|pub fn[T] Iter::nth(self : Iter[T], n : Int) -> T? {
#| self.drop(n).head()
#|}
#|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
#|}
#|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
#|}
#|#deprecated
#|pub fn[T, K : Eq + Hash] Iter::group_by(
#| self : Iter[T],
#| f : (T) -> K,
#|) -> Map[K, Array[T]] {
#| let result = Map::new()
#| for element in self {
#| let key = f(element)
#| match result.get(key) {
#| Some(arr) => result.set(key, arr + [element])
#| None => result.set(key, [element])
#| }
#| }
#| result
#|}
#|pub fn[T] Iter::iter2(self : Iter[T]) -> Iter2[Int, T] {
#| yield_ => {
#| let mut index = -1
#| self.run(i => {
#| index += 1
#| yield_(index, i)
#| })
#| }
#|}
),
"iter2.mbt": (
#|struct Iter2[A, B](((A, B) -> IterResult) -> IterResult)
#|pub fn[A, B] Iter2::run(
#| self : Iter2[A, B],
#| f : (A, B) -> IterResult,
#|) -> IterResult {
#| self(f)
#|}
#|pub impl[A : Show, B : Show] Show for Iter2[A, B] with output(self, logger) {
#| logger.write_string("[")
#| let mut first = true
#| for k, v in self {
#| if !first {
#| logger.write_string(", ")
#| } else {
#| first = false
#| }
#| logger
#| ..write_string("(")
#| ..write_object(k)
#| ..write_string(", ")
#| ..write_object(v)
#| ..write_string(")")
#| }
#| logger.write_string("]")
#|}
#|pub fn[A, B] Iter2::new(
#| f : ((A, B) -> IterResult) -> IterResult,
#|) -> Iter2[A, B] {
#| Iter2(f)
#|}
#|pub fn[A, B] Iter2::each(self : Iter2[A, B], f : (A, B) -> Unit) -> Unit {
#| self.run((a, b) => {
#| f(a, b)
#| IterContinue
#| })
#| |> ignore
#|}
#|pub fn[A, B] Iter2::iter(self : Iter2[A, B]) -> Iter[(A, B)] {
#| Iter::new(yield_ => self.run((a, b) => yield_((a, b))))
#|}
#|pub fn[A, B] Iter2::iter2(self : Iter2[A, B]) -> Iter2[A, B] {
#| self
#|}
#|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
#|}
#|pub fn[A, B] Iter2::concat(
#| self : Iter2[A, B],
#| other : Iter2[A, B],
#|) -> Iter2[A, B] {
#| yield_ => {
#| guard self.run(yield_) == IterContinue else { IterEnd }
#| other.run(yield_)
#| }
#|}
),
"json.mbt": (
#|pub enum Json {
#| Null
#| True
#| False
#| Number(Double, repr~ : String?) // 1.0000000000000000000e100
#| String(String)
#| Array(Array[Json])
#| Object(Map[String, Json])
#|}
#|pub impl Eq for Json with equal(a, b) {
#| match (a, b) {
#| (Null, Null) => true
#| (True, True) => true
#| (False, False) => true
#| (Number(a_num, ..), Number(b_num, ..)) => a_num == b_num
#| (String(a_str), String(b_str)) => a_str == b_str
#| (Array(a_arr), Array(b_arr)) => a_arr == b_arr
#| (Object(a_obj), Object(b_obj)) => a_obj == b_obj
#| _ => false
#| }
#|}
#|pub fn Json::null() -> Json {
#| return Null
#|}
#|pub let null : Json = Null
#|pub fn Json::number(number : Double, repr? : String) -> Json {
#| return Number(number, repr~)
#|}
#|pub fn Json::string(string : String) -> Json {
#| return String(string)
#|}
#|pub fn Json::boolean(boolean : Bool) -> Json {
#| if boolean {
#| True
#| } else {
#| False
#| }
#|}
#|pub fn Json::array(array : Array[Json]) -> Json {
#| return Array(array)
#|}
#|pub fn Json::object(object : Map[String, Json]) -> Json {
#| return Object(object)
#|}
#|pub(open) trait ToJson {
#| to_json(Self) -> Json
#|}
#|pub impl ToJson for Bool with to_json(self : Bool) -> Json {
#| if self {
#| true
#| } else {
#| false
#| }
#|}
#|pub impl ToJson for Byte with to_json(self : Byte) -> Json {
#| Json::number(self.to_double())
#|}
#|pub impl ToJson for Int with to_json(self : Int) -> Json {
#| Json::number(self.to_double())
#|}
#|pub impl ToJson for Int64 with to_json(self : Int64) -> Json {
#| String::to_json(self.to_string())
#|}
#|pub impl ToJson for UInt with to_json(self : UInt) -> Json {
#| Json::number(self.to_uint64().to_double())
#|}
#|pub impl ToJson for UInt64 with to_json(self : UInt64) -> Json {
#| String::to_json(self.to_string())
#|}
#|pub impl ToJson for Double with to_json(self : Double) -> Json {
#| if self != self {
#| Json::string("NaN")
#| } else if self > 0x7FEFFFFFFFFFFFFFL.reinterpret_as_double() {
#| Json::string("Infinity")
#| } else if self < 0xFFEFFFFFFFFFFFFFL.reinterpret_as_double() {
#| Json::string("-Infinity")
#| } else {
#| Json::number(self)
#| }
#|}
#|pub impl ToJson for Float with to_json(self : Float) -> Json {
#| Json::number(self.to_double())
#|}
#|pub impl ToJson for String with to_json(self : String) -> Json {
#| String(self)
#|}
#|pub impl[X : ToJson] ToJson for Array[X] with to_json(self) {
#| Array(self.map(ToJson::to_json))
#|}
#|pub impl[X : ToJson] ToJson for FixedArray[X] with to_json(self) {
#| let len = self.length()
#| if len == 0 {
#| return []
#| }
#| let res = Array::make_uninit(self.length())
#| for i, x in self {
#| res.unsafe_set(i, ToJson::to_json(x))
#| }
#| Array(res)
#|}
#|pub impl[X : ToJson] ToJson for ArrayView[X] with to_json(self) {
#| let len = self.length()
#| if len == 0 {
#| return []
#| }
#| let res = Array::make_uninit(self.length())
#| for i, x in self {
#| res.unsafe_set(i, ToJson::to_json(x))
#| }
#| Array(res)
#|}
#|pub impl[K : Show, V : ToJson] ToJson for Map[K, V] with to_json(self) {
#| let object = Map::new(capacity=self.capacity)
#| for k, v in self {
#| object[k.to_string()] = v.to_json()
#| }
#| Object(object)
#|}
#|pub impl[T : ToJson] ToJson for T? with to_json(self) {
#| match self {
#| None => Null
#| Some(value) => [value]
#| }
#|}
#|pub impl[Ok : ToJson, Err : ToJson] ToJson for Result[Ok, Err] with to_json(
#| self : Result[Ok, Err],
#|) -> Json {
#| match self {
#| Ok(ok) => { "Ok": ok }
#| Err(err) => { "Err": err }
#| }
#|}
#|pub impl ToJson for Unit with to_json(_self) {
#| Null
#|}
#|pub impl Default for Json with default() {
#| false
#|}
),
"linked_hash_map.mbt": (
#|priv struct Entry[K, V] {
#| mut prev : Int
#| mut next : Entry[K, V]?
#| mut psl : Int
#| hash : Int
#| key : K
#| mut value : V
#|} derive(Show)
#|struct Map[K, V] {
#| mut entries : FixedArray[Entry[K, V]?]
#| mut size : Int // active key-value pairs count
#| mut capacity : Int // current capacity
#| mut capacity_mask : Int // capacity_mask = capacity - 1, used to find idx
#| mut grow_at : Int // threshold that triggers grow
#| mut head : Entry[K, V]? // head of linked list
#| mut tail : Int // tail of linked list
#|}
#|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,
#| }
#|}
#|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
#|}
#|pub fn[K : Hash + Eq, V] Map::set(self : Map[K, V], key : K, value : V) -> Unit {
#| self.set_with_hash(key, value, key.hash())
#|}
#|fn[K : Eq, V] set_with_hash(
#| self : Map[K, V],
#| key : K,
#| value : V,
#| hash : Int,
#|) -> Unit {
#| if self.size >= self.grow_at {
#| self.grow()
#| }
#| 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)
#|}
#|fn[K, V] Map::push_away(
#| self : Map[K, V],
#| idx : Int,
#| entry : Entry[K, V],
#|) -> Unit {
#| for psl = entry.psl + 1, idx = (idx + 1) & self.capacity_mask, entry = entry {
#| match self.entries[idx] {
#| None => {
#| entry.psl = psl
#| self.set_entry(entry, idx)
#| break
#| }
#| Some(curr_entry) =>
#| if psl > curr_entry.psl {
#| entry.psl = psl
#| self.set_entry(entry, idx)
#| continue curr_entry.psl + 1,
#| (idx + 1) & self.capacity_mask,
#| curr_entry
#| } else {
#| continue psl + 1, (idx + 1) & self.capacity_mask, entry
#| }
#| }
#| }
#|}
#|fn[K, V] Map::set_entry(
#| self : Map[K, V],
#| entry : Entry[K, V],
#| new_idx : Int,
#|) -> Unit {
#| self.entries[new_idx] = Some(entry)
#| match entry.next {
#| None => self.tail = new_idx
#| Some(next) => next.prev = new_idx
#| }
#|}
#|pub fn[K : Hash + Eq, V] Map::op_set(
#| self : Map[K, V],
#| key : K,
#| value : V,
#|) -> Unit {
#| self.set(key, value)
#|}
#|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
#| }
#|}
#|pub fn[K : Hash + Eq, V] Map::op_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)
#| if entry.hash == hash && entry.key == key {
#| return entry.value
#| }
#| guard i <= entry.psl
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#|}
#|pub fn[K : Hash + Eq, V] Map::get_or_default(
#| self : Map[K, V],
#| key : K,
#| default : V,
#|) -> V {
#| 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 entry.value
#| }
#| if i > entry.psl {
#| break default
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#| None => break default
#| }
#| }
#|}
#|pub fn[K : Hash + Eq, V] Map::get_or_init(
#| self : Map[K, V],
#| key : K,
#| default : () -> V,
#|) -> V {
#| let hash = key.hash()
#| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash &
#| self.capacity_mask {
#| match self.entries[idx] {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| return entry.value
#| }
#| if psl > entry.psl {
#| let new_value = default()
#| self.push_away(idx, entry)
#| break (idx, psl, new_value, Some(entry))
#| }
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| None => {
#| let new_value = default()
#| break (idx, psl, new_value, None)
#| }
#| }
#| }
#| if self.size >= self.grow_at {
#| self.grow()
#| self.set_with_hash(key, new_value, hash)
#| } else {
#| if push_away is Some(entry) {
#| self.push_away(idx, entry)
#| }
#| let entry = {
#| prev: self.tail,
#| next: None,
#| psl,
#| hash,
#| key,
#| value: new_value,
#| }
#| self.add_entry_to_tail(idx, entry)
#| }
#| new_value
#|}
#|pub fn[K : Hash + Eq, V] Map::contains(self : Map[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 { 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
#| }
#|}
#|pub fn[K : Hash + Eq, V : Eq] Map::contains_kv(
#| self : Map[K, V],
#| key : K,
#| value : V,
#|) -> Bool {
#| 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 && entry.value == value {
#| break true
#| }
#| if i > entry.psl {
#| break false
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#|}
#|pub fn[K : Hash + Eq, V] Map::remove(self : Map[K, V], key : K) -> Unit {
#| self.remove_with_hash(key, key.hash())
#|}
#|fn[K : Eq, V] Map::remove_with_hash(
#| self : Map[K, V],
#| key : K,
#| hash : Int,
#|) -> Unit {
#| 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
#| }
#|}
#|fn[K, V] Map::add_entry_to_tail(
#| self : Map[K, V],
#| idx : Int,
#| entry : Entry[K, V],
#|) -> Unit {
#| match self.tail {
#| -1 => self.head = Some(entry)
#| tail => self.entries[tail].unwrap().next = Some(entry)
#| }
#| self.tail = idx
#| self.entries[idx] = Some(entry)
#| self.size += 1
#|}
#|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
#| }
#|}
#|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)
#| }
#| }
#|}
#|fn[K : 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, hash, .. }) => {
#| self.set_with_hash(key, value, hash)
#| continue next
#| }
#| None => break
#| }
#|}
#|fn calc_grow_threshold(capacity : Int) -> Int {
#| capacity * 13 / 16
#|}
#|pub impl[K : Show, V : Show] Show for Map[K, V] with output(self, logger) {
#| logger.write_string("{")
#| loop (0, self.head) {
#| (_, None) => logger.write_string("}")
#| (i, Some({ key, value, next, .. })) => {
#| if i > 0 {
#| logger.write_string(", ")
#| }
#| logger..write_object(key)..write_string(": ")..write_object(value)
#| continue (i + 1, next)
#| }
#| }
#|}
#|pub fn[K, V] Map::size(self : Map[K, V]) -> Int {
#| self.size
#|}
#|pub fn[K, V] Map::capacity(self : Map[K, V]) -> Int {
#| self.capacity
#|}
#|pub fn[K, V] Map::is_empty(self : Map[K, V]) -> Bool {
#| self.size == 0
#|}
#|#locals(f)
#|pub fn[K, V] Map::each(
#| self : Map[K, V],
#| f : (K, V) -> Unit raise?,
#|) -> Unit raise? {
#| loop self.head {
#| Some({ key, value, next, .. }) => {
#| f(key, value)
#| continue next
#| }
#| None => break
#| }
#|}
#|#locals(f)
#|pub fn[K, V] Map::eachi(
#| self : Map[K, V],
#| f : (Int, K, V) -> Unit raise?,
#|) -> Unit raise? {
#| loop (0, self.head) {
#| (i, Some({ key, value, next, .. })) => {
#| f(i, key, value)
#| continue (i + 1, next)
#| }
#| (_, None) => break
#| }
#|}
#|pub fn[K, V] Map::clear(self : Map[K, V]) -> Unit {
#| self.entries.fill(None)
#| self.size = 0
#| self.head = None
#| self.tail = -1
#|}
#|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
#| })
#|}
#|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
#| })
#|}
#|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
#| })
#|}
#|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
#| })
#|}
#|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
#|}
#|pub impl[K : Hash + Eq, V : Eq] Eq for Map[K, V] with equal(
#| self : Map[K, V],
#| that : Map[K, V],
#|) -> Bool {
#| guard self.size == that.size else { return false }
#| for k, v in self {
#| guard that.contains_kv(k, v) else { return false }
#| } else {
#| true
#| }
#|}
#|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)
#| for i in 0.. Map[K, V] {
#| let m = {}
#| for e in iter {
#| m.set(e.0, e.1)
#| }
#| m
#|}
#|pub impl[K, V] Default for Map[K, V] with default() {
#| Map::new()
#|}
#|pub fn[K, V, V2] Map::map(self : Map[K, V], f : (K, V) -> V2) -> Map[K, V2] {
#| 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
#|}
#|pub fn[K, V] Map::copy(self : Map[K, V]) -> Map[K, V] {
#| 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
#|}
#|#locals(f)
#|pub fn[K, V] Map::retain(self : Map[K, V], f : (K, V) -> Bool) -> Unit {
#| loop (self.head, false) {
#| (Some({ key, value, next, prev: idx, .. }), remove_prev) => {
#| if remove_prev {
#| guard self.entries[idx] is Some(entry)
#| self.remove_entry(entry)
#| self.shift_back(idx)
#| self.size -= 1
#| }
#| continue (next, !f(key, value))
#| }
#| (None, remove_prev) =>
#| if remove_prev {
#| let idx = self.tail
#| guard self.entries[idx] is Some(entry)
#| self.remove_entry(entry)
#| self.shift_back(idx)
#| self.size -= 1
#| }
#| }
#|}
#|pub fn[K : Hash + Eq, V] Map::update(
#| self : Map[K, V],
#| key : K,
#| f : (V?) -> V?,
#|) -> Unit {
#| let hash = key.hash()
#| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash &
#| self.capacity_mask {
#| match self.entries[idx] {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| if f(Some(entry.value)) is Some(new_value) {
#| entry.value = new_value
#| } else {
#| self.remove_entry(entry)
#| self.shift_back(idx)
#| self.size -= 1
#| }
#| return
#| }
#| if psl > entry.psl {
#| guard f(None) is Some(new_value) else { return }
#| break (idx, psl, new_value, Some(entry))
#| }
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| None => {
#| guard f(None) is Some(new_value) else { return }
#| break (idx, psl, new_value, None)
#| }
#| }
#| }
#| if self.size >= self.grow_at {
#| self.grow()
#| self.set(key, new_value)
#| } else {
#| if push_away is Some(entry) {
#| self.push_away(idx, entry)
#| }
#| let entry = {
#| prev: self.tail,
#| next: None,
#| psl,
#| hash,
#| key,
#| value: new_value,
#| }
#| self.add_entry_to_tail(idx, entry)
#| }
#|}
),
"op.mbt": (
#|#coverage.skip
#|pub fn[T : Compare] op_lt(self_ : T, other : T) -> Bool {
#| self_.compare(other).is_neg()
#|}
#|#coverage.skip
#|pub fn[T : Compare] op_gt(self_ : T, other : T) -> Bool {
#| self_.compare(other).is_pos()
#|}
#|#coverage.skip
#|pub fn[T : Compare] op_le(self_ : T, other : T) -> Bool {
#| self_.compare(other).is_non_pos()
#|}
#|#coverage.skip
#|pub fn[T : Compare] op_ge(self_ : T, other : T) -> Bool {
#| self_.compare(other).is_non_neg()
#|}
#|#coverage.skip
#|pub fn[T : Eq] op_notequal(x : T, y : T) -> Bool {
#| !(x == y)
#|}
),
"operators.mbt": (
#|pub(open) trait Add {
#| add(Self, Self) -> Self = _
#| op_add(Self, Self) -> Self = _
#|}
#|pub(open) trait Sub {
#| sub(Self, Self) -> Self = _
#| op_sub(Self, Self) -> Self = _
#|}
#|pub(open) trait Mul {
#| mul(Self, Self) -> Self = _
#| op_mul(Self, Self) -> Self = _
#|}
#|pub(open) trait Div {
#| div(Self, Self) -> Self = _
#| op_div(Self, Self) -> Self = _
#|}
#|pub(open) trait Neg {
#| neg(Self) -> Self = _
#| op_neg(Self) -> Self = _
#|}
#|pub(open) trait Mod {
#| mod(Self, Self) -> Self = _
#| op_mod(Self, Self) -> Self = _
#|}
#|pub(open) trait BitAnd {
#| land(Self, Self) -> Self
#|}
#|pub(open) trait BitOr {
#| lor(Self, Self) -> Self
#|}
#|pub(open) trait BitXOr {
#| lxor(Self, Self) -> Self
#|}
#|pub(open) trait Shl {
#| shl(Self, Int) -> Self = _
#| op_shl(Self, Int) -> Self = _
#|}
#|pub(open) trait Shr {
#| shr(Self, Int) -> Self = _
#| op_shr(Self, Int) -> Self = _
#|}
#|#deprecated("replace `impl op_add` with `impl add`")
#|impl Add with add(self, other) {
#| Add::op_add(self, other)
#|}
#|impl Add with op_add(self, other) {
#| Add::add(self, other)
#|}
#|#deprecated("replace `impl op_sub` with `impl sub`")
#|impl Sub with sub(self, other) {
#| Sub::op_sub(self, other)
#|}
#|impl Sub with op_sub(self, other) {
#| Sub::sub(self, other)
#|}
#|#deprecated("replace `impl op_mul` with `impl mul`")
#|impl Mul with mul(self, other) {
#| Mul::op_mul(self, other)
#|}
#|impl Mul with op_mul(self, other) {
#| Mul::mul(self, other)
#|}
#|#deprecated("replace `impl op_div` with `impl div`")
#|impl Div with div(self, other) {
#| Div::op_div(self, other)
#|}
#|impl Div with op_div(self, other) {
#| Div::div(self, other)
#|}
#|#deprecated("replace `impl op_neg` with `impl neg`")
#|impl Neg with neg(self) {
#| Neg::op_neg(self)
#|}
#|impl Neg with op_neg(self) {
#| Neg::neg(self)
#|}
#|#deprecated("replace `impl op_mod` with `impl mod`")
#|impl Mod with mod(self, other) {
#| Mod::op_mod(self, other)
#|}
#|impl Mod with op_mod(self, other) {
#| Mod::mod(self, other)
#|}
#|#deprecated("replace `impl op_shl` with `impl shl`")
#|impl Shl with shl(self, i) {
#| Shl::op_shl(self, i)
#|}
#|impl Shl with op_shl(self, i) {
#| Shl::shl(self, i)
#|}
#|#deprecated("replace `impl op_shr` with `impl shr`")
#|impl Shr with shr(self, i) {
#| Shr::op_shr(self, i)
#|}
#|impl Shr with op_shr(self, i) {
#| Shr::shr(self, i)
#|}
),
"option.mbt": (
#|pub impl[X : Eq] Eq for X? with equal(self, other) {
#| match (self, other) {
#| (None, None) => true
#| (Some(x), Some(y)) => x == y
#| _ => false
#| }
#|}
#|pub fn[X : Show] Option::to_string(self : X?) -> String {
#| match self {
#| None => "None"
#| Some(x) => "Some(" + x.to_string() + ")"
#| }
#|}
#|pub fn[X] Option::unwrap(self : X?) -> X {
#| match self {
#| None => panic()
#| Some(x) => x
#| }
#|}
),
"output.mbt": (
#|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))
#|}
#|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))
#|}
#|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)
#|}
#|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)
#|}
#|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")
#| }
#|}
#|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")
#| }
#|}
#|fn UInt::output_size_hint(radix? : Int = 10) -> Int {
#| Int::output_size_hint(radix~)
#|}
#|fn UInt64::output_size_hint(radix? : Int = 10) -> Int {
#| Int64::output_size_hint(radix~)
#|}
),
"result.mbt": (
#|pub impl[T : Eq, E : Eq] Eq for Result[T, E] with equal(self, other) {
#| match (self, other) {
#| (Ok(x), Ok(y)) => x == y
#| (Err(x), Err(y)) => x == y
#| _ => false
#| }
#|}
),
"show.mbt": (
#|pub impl Show for Unit with output(_self, logger) {
#| logger.write_string("()")
#|}
#|pub impl Show for Bool with output(self, logger) {
#| if self {
#| logger.write_string("true")
#| } else {
#| logger.write_string("false")
#| }
#|}
#|pub impl Show for Int with output(self, logger) {
#| self.output(logger)
#|}
#|pub impl Show for Int64 with output(self, logger) {
#| self.output(logger)
#|}
#|pub impl Show for UInt with output(self, logger) {
#| self.output(logger)
#|}
#|pub impl Show for UInt64 with output(self, logger) {
#| self.output(logger)
#|}
#|pub impl Show for Byte with output(self, logger) {
#| logger.write_string(self.to_string())
#|}
#|pub impl Show for Int16 with output(self, logger) {
#| logger.write_string(self.to_string())
#|}
#|pub impl Show for UInt16 with output(self, logger) {
#| self.to_int().output(logger)
#|}
#|fn to_hex_digit(i : Int) -> Char {
#| if i < 10 {
#| (i + '0').unsafe_to_char()
#| } else {
#| (i + 'a' - 10).unsafe_to_char()
#| }
#|}
#|test "to_hex_digit" {
#| for i in 0..<10 {
#| guard to_hex_digit(i) == ('0'.to_int() + i).unsafe_to_char() else {
#| fail("to_hex_digit(\{i}) does not match")
#| }
#| }
#| for i in 10..<16 {
#| guard to_hex_digit(i) == ('a'.to_int() + (i - 10)).unsafe_to_char() else {
#| fail("to_hex_digit(\{i}) does not match")
#| }
#| }
#|}
#|pub impl Show for Bytes with output(self, logger) {
#| logger.write_string("b\"")
#| for b in self {
#| let byte = b.to_int()
#| logger
#| ..write_string("\\x")
#| ..write_char(to_hex_digit(byte / 16))
#| ..write_char(to_hex_digit(byte % 16))
#| }
#| logger.write_string("\"")
#|}
#|pub impl Show for String with output(self, logger) {
#| logger.write_char('"')
#| fn flush_segment(seg : Int, i : Int) {
#| if i > seg {
#| logger.write_substring(self, seg, i - seg)
#| }
#| }
#| let len = self.length()
#| for i = 0, seg = 0 {
#| if i >= len {
#| flush_segment(seg, i)
#| break
#| }
#| let code = self.unsafe_charcode_at(i)
#| match code {
#| '"' | '\\' as c => {
#| flush_segment(seg, i)
#| logger..write_char('\\')..write_char(c.unsafe_to_char())
#| continue i + 1, i + 1
#| }
#| '\n' => {
#| flush_segment(seg, i)
#| logger.write_string("\\n")
#| continue i + 1, i + 1
#| }
#| '\r' => {
#| flush_segment(seg, i)
#| logger.write_string("\\r")
#| continue i + 1, i + 1
#| }
#| '\b' => {
#| flush_segment(seg, i)
#| logger.write_string("\\b")
#| continue i + 1, i + 1
#| }
#| '\t' => {
#| flush_segment(seg, i)
#| logger.write_string("\\t")
#| continue i + 1, i + 1
#| }
#| code =>
#| if code < ' ' {
#| flush_segment(seg, i)
#| logger
#| ..write_string("\\u{")
#| ..write_char(to_hex_digit(code / 16))
#| ..write_char(to_hex_digit(code % 16))
#| ..write_char('}')
#| continue i + 1, i + 1
#| } else {
#| continue i + 1, seg
#| }
#| }
#| }
#| logger.write_char('"')
#|}
#|pub impl Show for String with to_string(self) {
#| self
#|}
#|pub fn String::escape(self : String) -> String {
#| let buf = StringBuilder::new()
#| Show::output(self, buf)
#| buf.to_string()
#|}
#|pub impl[X : Show] Show for X? with output(self, logger) {
#| match self {
#| None => logger.write_string("None")
#| Some(arg) =>
#| logger..write_string("Some(")..write_object(arg)..write_string(")")
#| }
#|}
#|pub impl[T : Show, E : Show] Show for Result[T, E] with output(self, logger) {
#| match self {
#| Ok(x) => logger..write_string("Ok(")..write_object(x)..write_string(")")
#| Err(e) => logger..write_string("Err(")..write_object(e)..write_string(")")
#| }
#|}
#|pub impl[X : Show] Show for Ref[X] with output(self, logger) {
#| logger..write_string("{val: ")..write_object(self.val)..write_string("}")
#|}
#|pub impl[X : Show] Show for FixedArray[X] with output(self, logger) {
#| logger.write_iter(self.iter())
#|}
#|pub impl[X : Show] Show for Array[X] with output(self, logger) {
#| logger.write_iter(self.iter())
#|}
),
"string.mbt": (
#|fn unsafe_make_string(length : Int, value : Char) -> String = "$moonbit.unsafe_make_string"
#|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()
#|}
#|pub fn String::char_length(
#| self : String,
#| start_offset? : Int = 0,
#| end_offset? : Int,
#|) -> Int {
#| let end_offset = if end_offset is Some(o) { o } else { self.length() }
#| guard start_offset >= 0 &&
#| start_offset <= end_offset &&
#| end_offset <= self.length() else {
#| abort("invalid start or end index for String::codepoint_length")
#| }
#| for utf16_index = start_offset, char_count = 0
#| utf16_index < end_offset
#| utf16_index = utf16_index + 1, char_count = char_count + 1 {
#| let c1 = self.unsafe_charcode_at(utf16_index)
#| if c1.is_leading_surrogate() && utf16_index + 1 < end_offset {
#| let c2 = self.unsafe_charcode_at(utf16_index + 1)
#| if c2.is_trailing_surrogate() {
#| continue utf16_index + 2, char_count + 1
#| } else {
#| abort("invalid surrogate pair")
#| }
#| }
#| } else {
#| char_count
#| }
#|}
#|#intrinsic("%string.substring")
#|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()
#|}
#|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)
#|}
#|test "substring/empty" {
#| let s = "test"
#| inspect(s.substring(start=2, end=2), content="")
#| inspect(s.substring(start=4, end=4), content="")
#| inspect("".substring(), content="")
#|}
#|test "panic substring/invalid_range" {
#| let s = "test"
#| ignore(s.substring(start=-1))
#| ignore(s.substring(end=5))
#| ignore(s.substring(start=3, end=2))
#|}
#|test "substring/basic" {
#| inspect("Hello world".substring(start=0, end=5), content="Hello")
#| inspect("Hello world".substring(start=6, end=11), content="world")
#| inspect("Hello world".substring(start=0), content="Hello world")
#| inspect("Hello world".substring(start=6), content="world")
#|}
#|test "substring/boundary" {
#| inspect("".substring(start=0, end=0), content="")
#| inspect("a".substring(start=0, end=1), content="a")
#| inspect("abc".substring(start=0), content="abc")
#| inspect("abc".substring(start=1), content="bc")
#| inspect("abc".substring(start=0, end=3), content="abc")
#|}
#|test "panic substring/out_of_bounds" {
#| ignore("hello".substring(start=-1, end=4))
#| ignore("hello".substring(start=6, end=4))
#| ignore("hello".substring(start=0, end=6))
#|}
),
"stringbuilder.mbt": (
#|pub fn[T : Show] StringBuilder::write_object(
#| self : StringBuilder,
#| obj : T,
#|) -> Unit {
#| obj.output(self)
#|}
#|pub fn StringBuilder::write_iter(
#| self : StringBuilder,
#| iter : Iter[Char],
#|) -> Unit {
#| for ch in iter {
#| self.write_char(ch)
#| }
#|}
),
"stringbuilder_buffer.mbt": (
#|struct StringBuilder {
#| mut data : FixedArray[Byte]
#| mut len : Int
#|}
#|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 }
#|}
#|pub fn StringBuilder::is_empty(self : StringBuilder) -> Bool {
#| self.len == 0
#|}
#|fn StringBuilder::grow_if_necessary(
#| self : StringBuilder,
#| required : Int,
#|) -> Unit {
#| let current_len = self.data.length()
#| if required <= current_len {
#| return
#| }
#| let mut enough_space = current_len
#| while enough_space < required {
#| enough_space = enough_space * 2
#| }
#| let new_data = FixedArray::make(enough_space, Byte::default())
#| new_data.unsafe_blit(0, self.data, 0, self.len)
#| self.data = new_data
#|}
#|pub impl Logger for StringBuilder with write_string(self, str) {
#| self.grow_if_necessary(self.len + str.length() * 2)
#| self.data.blit_from_string(self.len, str, 0, str.length())
#| self.len += str.length() * 2
#|}
#|pub impl Logger for StringBuilder with write_char(self, ch) {
#| self.grow_if_necessary(self.len + 4)
#| let inc = self.data.set_utf16le_char(self.len, ch)
#| self.len += inc
#|}
#|pub impl Logger for StringBuilder with write_substring(
#| self : StringBuilder,
#| str : String,
#| start : Int,
#| len : Int,
#|) -> Unit {
#| guard start >= 0 && len >= 0 && start + len <= str.length()
#| self.grow_if_necessary(self.len + len * 2)
#| self.data.blit_from_string(self.len, str, start, len)
#| self.len += len * 2
#|}
#|pub fn StringBuilder::to_string(self : StringBuilder) -> String {
#| self.data
#| .unsafe_reinterpret_as_bytes()
#| .to_unchecked_string(offset=0, length=self.len)
#|}
#|pub impl Show for StringBuilder with output(self, logger) {
#| logger.write_string(
#| self.data
#| .unsafe_reinterpret_as_bytes()
#| .to_unchecked_string(offset=0, length=self.len),
#| )
#|}
#|pub fn StringBuilder::reset(self : StringBuilder) -> Unit {
#| self.len = 0
#|}
),
"stringbuilder_concat.mbt": (
#|struct StringBuilder(Ref[String])
#|pub fn StringBuilder::new(size_hint? : Int = 0) -> StringBuilder {
#| ignore(size_hint)
#| { val: "" }
#|}
#|pub fn StringBuilder::is_empty(self : StringBuilder) -> Bool {
#| self.val == ""
#|}
#|pub impl Logger for StringBuilder with write_string(self, str) {
#| self.val += str
#|}
#|#intrinsic("%char.to_string")
#|fn char_to_string(char : Char) -> String {
#| [char]
#|}
#|pub impl Logger for StringBuilder with write_char(self, ch) {
#| self.val += char_to_string(ch)
#|}
#|pub impl Logger for StringBuilder with write_substring(
#| self : StringBuilder,
#| str : String,
#| start : Int,
#| len : Int,
#|) -> Unit {
#| self.val += str.substring(start~, end=start + len)
#|}
#|pub impl Show for StringBuilder with output(self, logger) {
#| logger.write_string(self.val)
#|}
#|pub fn StringBuilder::to_string(self : StringBuilder) -> String {
#| self.val
#|}
#|pub fn StringBuilder::reset(self : StringBuilder) -> Unit {
#| self.val = ""
#|}
),
"to_string.mbt": (
#|const ALPHABET : String = "0123456789abcdefghijklmnopqrstuvwxyz"
#|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()
#|}
#|pub impl Show for Int64 with to_string(self) {
#| self.to_string(radix=10)
#|}
#|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()
#|}
#|pub impl Show for Int with to_string(self) {
#| self.to_string(radix=10)
#|}
#|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()
#|}
#|pub impl Show for UInt with to_string(self) {
#| self.to_string(radix=10)
#|}
#|test "UInt::to_string" {
#| inspect(0U, content="0")
#| inspect(17U, content="17")
#| inspect(4294967295U, content="4294967295")
#|}
#|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()
#|}
#|pub impl Show for UInt64 with to_string(self) {
#| self.to_string(radix=10)
#|}
#|pub fn Int16::to_string(self : Int16, radix? : Int = 10) -> String {
#| self.to_int().to_string(radix~)
#|}
#|pub impl Show for Int16 with to_string(self) {
#| self.to_string(radix=10)
#|}
#|pub fn UInt16::to_string(self : UInt16, radix? : Int = 10) -> String {
#| self.to_int().to_string(radix~)
#|}
#|pub impl Show for UInt16 with to_string(self) {
#| self.to_string(radix=10)
#|}
#|test "to_string" {
#| assert_eq((0x100).to_string(), "256")
#| assert_eq("\{0x100}", "256")
#| assert_eq(0x200U.to_string(), "512")
#| assert_eq("\{0x200U}", "512")
#| assert_eq(0x300L.to_string(), "768")
#| assert_eq("\{0x300L}", "768")
#| assert_eq(0x400UL.to_string(), "1024")
#| assert_eq("\{0x400UL}", "1024")
#|}
#|test "to_string with radix" {
#| inspect((0).to_string(radix=2), content="0")
#| inspect((1).to_string(radix=2), content="1")
#| inspect((2).to_string(radix=2), content="10")
#| inspect((255).to_string(radix=2), content="11111111")
#| inspect((-255).to_string(radix=2), content="-11111111")
#| inspect((0).to_string(radix=8), content="0")
#| inspect((8).to_string(radix=8), content="10")
#| inspect((64).to_string(radix=8), content="100")
#| inspect((-64).to_string(radix=8), content="-100")
#| inspect((0).to_string(radix=10), content="0")
#| inspect((123).to_string(radix=10), content="123")
#| inspect((-123).to_string(radix=10), content="-123")
#| inspect(
#| 0x7fff_ffff_ffff_ffffL.to_string(radix=10),
#| content="9223372036854775807",
#| )
#| inspect(
#| 0x8000_0000_0000_0000L.to_string(radix=10),
#| content="-9223372036854775808",
#| )
#| inspect((0).to_string(radix=16), content="0")
#| inspect((0x11).to_string(radix=16), content="11")
#| inspect((0x15ef).to_string(radix=16), content="15ef")
#| inspect((-0xabcd).to_string(radix=16), content="-abcd")
#| inspect(
#| (1.0 : Float).reinterpret_as_int().to_string(radix=16),
#| content="3f800000",
#| )
#| inspect(0U.to_string(radix=16), content="0")
#| inspect(0x1AU.to_string(radix=16), content="1a")
#| inspect(0xabcdU.to_string(radix=16), content="abcd")
#| inspect(
#| (-2.0 : Float).reinterpret_as_uint().to_string(radix=16),
#| content="c0000000",
#| )
#| inspect((-1).reinterpret_as_uint().to_string(radix=16), content="ffffffff")
#| inspect(0L.to_string(radix=16), content="0")
#| inspect(0x2fL.to_string(radix=16), content="2f")
#| inspect(0xf0aeL.to_string(radix=16), content="f0ae")
#| inspect((-0x1234eacbL).to_string(radix=16), content="-1234eacb")
#| inspect(
#| 1.0.reinterpret_as_uint64().to_string(radix=16),
#| content="3ff0000000000000",
#| )
#| inspect(0b101L.to_string(radix=2), content="101")
#| inspect(0o17L.to_string(radix=8), content="17")
#| inspect(0UL.to_string(radix=16), content="0")
#| inspect(0x11UL.to_string(radix=16), content="11")
#| inspect(0x12bdUL.to_string(radix=16), content="12bd")
#| inspect(
#| (-1L).reinterpret_as_uint64().to_string(radix=16),
#| content="ffffffffffffffff",
#| )
#| inspect(
#| 2.0.reinterpret_as_uint64().to_string(radix=16),
#| content="4000000000000000",
#| )
#|}
#|test "panic to_string_by_radix/illegal_radix" {
#| ignore((1).to_string(radix=1))
#| ignore((1).to_string(radix=37))
#| ignore(1L.to_string(radix=0))
#| ignore(1L.to_string(radix=42))
#| ignore(1U.to_string(radix=-1))
#| ignore(1U.to_string(radix=73))
#| ignore(1UL.to_string(radix=-100))
#| ignore(1UL.to_string(radix=100))
#|}
),
"traits.mbt": (
#|pub(open) trait Eq {
#| equal(Self, Self) -> Bool = _
#| op_equal(Self, Self) -> Bool = _
#|}
#|pub(open) trait Compare: Eq {
#| compare(Self, Self) -> Int
#|}
#|pub(open) trait Hash {
#| hash_combine(Self, Hasher) -> Unit
#| hash(Self) -> Int = _
#|}
#|impl Hash with hash(self) {
#| Hasher::new()..combine(self).finalize()
#|}
#|pub(open) trait Default {
#| default() -> Self
#|}
#|pub(open) trait Logger {
#| write_string(Self, String) -> Unit
#| write_substring(Self, String, Int, Int) -> Unit
#| write_char(Self, Char) -> Unit = _
#|}
#|impl Logger with write_char(self, value) {
#| self.write_string([value])
#|}
#|pub(open) trait Show {
#| output(Self, &Logger) -> Unit
#| to_string(Self) -> String = _
#|}
#|impl Show with to_string(self) {
#| let logger = StringBuilder::new()
#| self.output(logger)
#| logger.to_string()
#|}
#|pub fn[Obj : Show] &Logger::write_object(self : &Logger, obj : Obj) -> Unit {
#| obj.output(self)
#|}
#|pub fn[T : Show] &Logger::write_iter(
#| self : &Logger,
#| iter : Iter[T],
#| prefix? : String = "[",
#| suffix? : String = "]",
#| sep? : String = ", ",
#| trailing? : Bool = false,
#|) -> Unit {
#| self.write_string(prefix)
#| if trailing {
#| for x in iter {
#| self.write_object(x)
#| self.write_string(sep)
#| }
#| } else {
#| let mut first = true
#| for x in iter {
#| if first {
#| first = false
#| } else {
#| self.write_string(sep)
#| }
#| self.write_object(x)
#| }
#| }
#| self.write_string(suffix)
#|}
#|pub fn[T : Show] repr(t : T) -> String {
#| let logger = StringBuilder::new()
#| t.output(logger)
#| logger.to_string()
#|}
#|#deprecated("replace `impl op_equal` with `impl equal`")
#|impl Eq with equal(self, other) {
#| Eq::op_equal(self, other)
#|}
#|impl Eq with op_equal(self, other) {
#| Eq::equal(self, other)
#|}
),
"tuple_compare.mbt": (
#|pub impl[T0 : Compare, T1 : Compare] Compare for (T0, T1) with compare(
#| self : (T0, T1),
#| other : (T0, T1),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| self.1.compare(other.1)
#|}
#|pub impl[T0 : Compare, T1 : Compare, T2 : Compare] Compare for (T0, T1, T2) with compare(
#| self : (T0, T1, T2),
#| other : (T0, T1, T2),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| self.2.compare(other.2)
#|}
#|pub impl[T0 : Compare, T1 : Compare, T2 : Compare, T3 : Compare] Compare for (
#| T0,
#| T1,
#| T2,
#| T3,
#|) with compare(self : (T0, T1, T2, T3), other : (T0, T1, T2, T3)) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| self.3.compare(other.3)
#|}
#|pub impl[T0 : Compare, T1 : Compare, T2 : Compare, T3 : Compare, T4 : Compare] Compare for (
#| T0,
#| T1,
#| T2,
#| T3,
#| T4,
#|) with compare(self : (T0, T1, T2, T3, T4), other : (T0, T1, T2, T3, T4)) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| let t3 = self.3.compare(other.3)
#| guard t3 == 0 else { return t3 }
#| self.4.compare(other.4)
#|}
#|pub impl[
#| T0 : Compare,
#| T1 : Compare,
#| T2 : Compare,
#| T3 : Compare,
#| T4 : Compare,
#| T5 : Compare,
#|] Compare for (T0, T1, T2, T3, T4, T5) with compare(
#| self : (T0, T1, T2, T3, T4, T5),
#| other : (T0, T1, T2, T3, T4, T5),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| let t3 = self.3.compare(other.3)
#| guard t3 == 0 else { return t3 }
#| let t4 = self.4.compare(other.4)
#| guard t4 == 0 else { return t4 }
#| self.5.compare(other.5)
#|}
#|pub impl[
#| T0 : Compare,
#| T1 : Compare,
#| T2 : Compare,
#| T3 : Compare,
#| T4 : Compare,
#| T5 : Compare,
#| T6 : Compare,
#|] Compare for (T0, T1, T2, T3, T4, T5, T6) with compare(
#| self : (T0, T1, T2, T3, T4, T5, T6),
#| other : (T0, T1, T2, T3, T4, T5, T6),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| let t3 = self.3.compare(other.3)
#| guard t3 == 0 else { return t3 }
#| let t4 = self.4.compare(other.4)
#| guard t4 == 0 else { return t4 }
#| let t5 = self.5.compare(other.5)
#| guard t5 == 0 else { return t5 }
#| self.6.compare(other.6)
#|}
#|pub impl[
#| T0 : Compare,
#| T1 : Compare,
#| T2 : Compare,
#| T3 : Compare,
#| T4 : Compare,
#| T5 : Compare,
#| T6 : Compare,
#| T7 : Compare,
#|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7) with compare(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| let t3 = self.3.compare(other.3)
#| guard t3 == 0 else { return t3 }
#| let t4 = self.4.compare(other.4)
#| guard t4 == 0 else { return t4 }
#| let t5 = self.5.compare(other.5)
#| guard t5 == 0 else { return t5 }
#| let t6 = self.6.compare(other.6)
#| guard t6 == 0 else { return t6 }
#| self.7.compare(other.7)
#|}
#|pub impl[
#| T0 : Compare,
#| T1 : Compare,
#| T2 : Compare,
#| T3 : Compare,
#| T4 : Compare,
#| T5 : Compare,
#| T6 : Compare,
#| T7 : Compare,
#| T8 : Compare,
#|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8) with compare(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| let t3 = self.3.compare(other.3)
#| guard t3 == 0 else { return t3 }
#| let t4 = self.4.compare(other.4)
#| guard t4 == 0 else { return t4 }
#| let t5 = self.5.compare(other.5)
#| guard t5 == 0 else { return t5 }
#| let t6 = self.6.compare(other.6)
#| guard t6 == 0 else { return t6 }
#| let t7 = self.7.compare(other.7)
#| guard t7 == 0 else { return t7 }
#| self.8.compare(other.8)
#|}
#|pub impl[
#| T0 : Compare,
#| T1 : Compare,
#| T2 : Compare,
#| T3 : Compare,
#| T4 : Compare,
#| T5 : Compare,
#| T6 : Compare,
#| T7 : Compare,
#| T8 : Compare,
#| T9 : Compare,
#|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) with compare(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| let t3 = self.3.compare(other.3)
#| guard t3 == 0 else { return t3 }
#| let t4 = self.4.compare(other.4)
#| guard t4 == 0 else { return t4 }
#| let t5 = self.5.compare(other.5)
#| guard t5 == 0 else { return t5 }
#| let t6 = self.6.compare(other.6)
#| guard t6 == 0 else { return t6 }
#| let t7 = self.7.compare(other.7)
#| guard t7 == 0 else { return t7 }
#| let t8 = self.8.compare(other.8)
#| guard t8 == 0 else { return t8 }
#| self.9.compare(other.9)
#|}
#|pub impl[
#| T0 : Compare,
#| T1 : Compare,
#| T2 : Compare,
#| T3 : Compare,
#| T4 : Compare,
#| T5 : Compare,
#| T6 : Compare,
#| T7 : Compare,
#| T8 : Compare,
#| T9 : Compare,
#| T10 : Compare,
#|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) with compare(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| let t3 = self.3.compare(other.3)
#| guard t3 == 0 else { return t3 }
#| let t4 = self.4.compare(other.4)
#| guard t4 == 0 else { return t4 }
#| let t5 = self.5.compare(other.5)
#| guard t5 == 0 else { return t5 }
#| let t6 = self.6.compare(other.6)
#| guard t6 == 0 else { return t6 }
#| let t7 = self.7.compare(other.7)
#| guard t7 == 0 else { return t7 }
#| let t8 = self.8.compare(other.8)
#| guard t8 == 0 else { return t8 }
#| let t9 = self.9.compare(other.9)
#| guard t9 == 0 else { return t9 }
#| self.10.compare(other.10)
#|}
#|pub impl[
#| T0 : Compare,
#| T1 : Compare,
#| T2 : Compare,
#| T3 : Compare,
#| T4 : Compare,
#| T5 : Compare,
#| T6 : Compare,
#| T7 : Compare,
#| T8 : Compare,
#| T9 : Compare,
#| T10 : Compare,
#| T11 : Compare,
#|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) with compare(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| let t3 = self.3.compare(other.3)
#| guard t3 == 0 else { return t3 }
#| let t4 = self.4.compare(other.4)
#| guard t4 == 0 else { return t4 }
#| let t5 = self.5.compare(other.5)
#| guard t5 == 0 else { return t5 }
#| let t6 = self.6.compare(other.6)
#| guard t6 == 0 else { return t6 }
#| let t7 = self.7.compare(other.7)
#| guard t7 == 0 else { return t7 }
#| let t8 = self.8.compare(other.8)
#| guard t8 == 0 else { return t8 }
#| let t9 = self.9.compare(other.9)
#| guard t9 == 0 else { return t9 }
#| let t10 = self.10.compare(other.10)
#| guard t10 == 0 else { return t10 }
#| self.11.compare(other.11)
#|}
#|pub impl[
#| T0 : Compare,
#| T1 : Compare,
#| T2 : Compare,
#| T3 : Compare,
#| T4 : Compare,
#| T5 : Compare,
#| T6 : Compare,
#| T7 : Compare,
#| T8 : Compare,
#| T9 : Compare,
#| T10 : Compare,
#| T11 : Compare,
#| T12 : Compare,
#|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) with compare(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| let t3 = self.3.compare(other.3)
#| guard t3 == 0 else { return t3 }
#| let t4 = self.4.compare(other.4)
#| guard t4 == 0 else { return t4 }
#| let t5 = self.5.compare(other.5)
#| guard t5 == 0 else { return t5 }
#| let t6 = self.6.compare(other.6)
#| guard t6 == 0 else { return t6 }
#| let t7 = self.7.compare(other.7)
#| guard t7 == 0 else { return t7 }
#| let t8 = self.8.compare(other.8)
#| guard t8 == 0 else { return t8 }
#| let t9 = self.9.compare(other.9)
#| guard t9 == 0 else { return t9 }
#| let t10 = self.10.compare(other.10)
#| guard t10 == 0 else { return t10 }
#| let t11 = self.11.compare(other.11)
#| guard t11 == 0 else { return t11 }
#| self.12.compare(other.12)
#|}
#|pub impl[
#| T0 : Compare,
#| T1 : Compare,
#| T2 : Compare,
#| T3 : Compare,
#| T4 : Compare,
#| T5 : Compare,
#| T6 : Compare,
#| T7 : Compare,
#| T8 : Compare,
#| T9 : Compare,
#| T10 : Compare,
#| T11 : Compare,
#| T12 : Compare,
#| T13 : Compare,
#|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) with compare(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| let t3 = self.3.compare(other.3)
#| guard t3 == 0 else { return t3 }
#| let t4 = self.4.compare(other.4)
#| guard t4 == 0 else { return t4 }
#| let t5 = self.5.compare(other.5)
#| guard t5 == 0 else { return t5 }
#| let t6 = self.6.compare(other.6)
#| guard t6 == 0 else { return t6 }
#| let t7 = self.7.compare(other.7)
#| guard t7 == 0 else { return t7 }
#| let t8 = self.8.compare(other.8)
#| guard t8 == 0 else { return t8 }
#| let t9 = self.9.compare(other.9)
#| guard t9 == 0 else { return t9 }
#| let t10 = self.10.compare(other.10)
#| guard t10 == 0 else { return t10 }
#| let t11 = self.11.compare(other.11)
#| guard t11 == 0 else { return t11 }
#| let t12 = self.12.compare(other.12)
#| guard t12 == 0 else { return t12 }
#| self.13.compare(other.13)
#|}
#|pub impl[
#| T0 : Compare,
#| T1 : Compare,
#| T2 : Compare,
#| T3 : Compare,
#| T4 : Compare,
#| T5 : Compare,
#| T6 : Compare,
#| T7 : Compare,
#| T8 : Compare,
#| T9 : Compare,
#| T10 : Compare,
#| T11 : Compare,
#| T12 : Compare,
#| T13 : Compare,
#| T14 : Compare,
#|] Compare for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) with compare(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| let t3 = self.3.compare(other.3)
#| guard t3 == 0 else { return t3 }
#| let t4 = self.4.compare(other.4)
#| guard t4 == 0 else { return t4 }
#| let t5 = self.5.compare(other.5)
#| guard t5 == 0 else { return t5 }
#| let t6 = self.6.compare(other.6)
#| guard t6 == 0 else { return t6 }
#| let t7 = self.7.compare(other.7)
#| guard t7 == 0 else { return t7 }
#| let t8 = self.8.compare(other.8)
#| guard t8 == 0 else { return t8 }
#| let t9 = self.9.compare(other.9)
#| guard t9 == 0 else { return t9 }
#| let t10 = self.10.compare(other.10)
#| guard t10 == 0 else { return t10 }
#| let t11 = self.11.compare(other.11)
#| guard t11 == 0 else { return t11 }
#| let t12 = self.12.compare(other.12)
#| guard t12 == 0 else { return t12 }
#| let t13 = self.13.compare(other.13)
#| guard t13 == 0 else { return t13 }
#| self.14.compare(other.14)
#|}
#|pub impl[
#| T0 : Compare,
#| T1 : Compare,
#| T2 : Compare,
#| T3 : Compare,
#| T4 : Compare,
#| T5 : Compare,
#| T6 : Compare,
#| T7 : Compare,
#| T8 : Compare,
#| T9 : Compare,
#| T10 : Compare,
#| T11 : Compare,
#| T12 : Compare,
#| T13 : Compare,
#| T14 : Compare,
#| T15 : Compare,
#|] Compare for (
#| T0,
#| T1,
#| T2,
#| T3,
#| T4,
#| T5,
#| T6,
#| T7,
#| T8,
#| T9,
#| T10,
#| T11,
#| T12,
#| T13,
#| T14,
#| T15,
#|) with compare(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15),
#|) -> Int {
#| let t0 = self.0.compare(other.0)
#| guard t0 == 0 else { return t0 }
#| let t1 = self.1.compare(other.1)
#| guard t1 == 0 else { return t1 }
#| let t2 = self.2.compare(other.2)
#| guard t2 == 0 else { return t2 }
#| let t3 = self.3.compare(other.3)
#| guard t3 == 0 else { return t3 }
#| let t4 = self.4.compare(other.4)
#| guard t4 == 0 else { return t4 }
#| let t5 = self.5.compare(other.5)
#| guard t5 == 0 else { return t5 }
#| let t6 = self.6.compare(other.6)
#| guard t6 == 0 else { return t6 }
#| let t7 = self.7.compare(other.7)
#| guard t7 == 0 else { return t7 }
#| let t8 = self.8.compare(other.8)
#| guard t8 == 0 else { return t8 }
#| let t9 = self.9.compare(other.9)
#| guard t9 == 0 else { return t9 }
#| let t10 = self.10.compare(other.10)
#| guard t10 == 0 else { return t10 }
#| let t11 = self.11.compare(other.11)
#| guard t11 == 0 else { return t11 }
#| let t12 = self.12.compare(other.12)
#| guard t12 == 0 else { return t12 }
#| let t13 = self.13.compare(other.13)
#| guard t13 == 0 else { return t13 }
#| let t14 = self.14.compare(other.14)
#| guard t14 == 0 else { return t14 }
#| self.15.compare(other.15)
#|}
),
"tuple_eq.mbt": (
#|pub impl[T0 : Eq, T1 : Eq] Eq for (T0, T1) with equal(
#| self : (T0, T1),
#| other : (T0, T1),
#|) -> Bool {
#| self.0 == other.0 && self.1 == other.1
#|}
#|pub impl[T0 : Eq, T1 : Eq, T2 : Eq] Eq for (T0, T1, T2) with equal(
#| self : (T0, T1, T2),
#| other : (T0, T1, T2),
#|) -> Bool {
#| self.0 == other.0 && self.1 == other.1 && self.2 == other.2
#|}
#|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq] Eq for (T0, T1, T2, T3) with equal(
#| self : (T0, T1, T2, T3),
#| other : (T0, T1, T2, T3),
#|) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3
#|}
#|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq] Eq for (
#| T0,
#| T1,
#| T2,
#| T3,
#| T4,
#|) with equal(self : (T0, T1, T2, T3, T4), other : (T0, T1, T2, T3, T4)) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3 &&
#| self.4 == other.4
#|}
#|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq] Eq for (
#| T0,
#| T1,
#| T2,
#| T3,
#| T4,
#| T5,
#|) with equal(self : (T0, T1, T2, T3, T4, T5), other : (T0, T1, T2, T3, T4, T5)) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3 &&
#| self.4 == other.4 &&
#| self.5 == other.5
#|}
#|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq, T6 : Eq] Eq for (
#| T0,
#| T1,
#| T2,
#| T3,
#| T4,
#| T5,
#| T6,
#|) with equal(
#| self : (T0, T1, T2, T3, T4, T5, T6),
#| other : (T0, T1, T2, T3, T4, T5, T6),
#|) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3 &&
#| self.4 == other.4 &&
#| self.5 == other.5 &&
#| self.6 == other.6
#|}
#|pub impl[T0 : Eq, T1 : Eq, T2 : Eq, T3 : Eq, T4 : Eq, T5 : Eq, T6 : Eq, T7 : Eq] Eq for (
#| T0,
#| T1,
#| T2,
#| T3,
#| T4,
#| T5,
#| T6,
#| T7,
#|) with equal(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7),
#|) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3 &&
#| self.4 == other.4 &&
#| self.5 == other.5 &&
#| self.6 == other.6 &&
#| self.7 == other.7
#|}
#|pub impl[
#| T0 : Eq,
#| T1 : Eq,
#| T2 : Eq,
#| T3 : Eq,
#| T4 : Eq,
#| T5 : Eq,
#| T6 : Eq,
#| T7 : Eq,
#| T8 : Eq,
#|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8) with equal(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8),
#|) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3 &&
#| self.4 == other.4 &&
#| self.5 == other.5 &&
#| self.6 == other.6 &&
#| self.7 == other.7 &&
#| self.8 == other.8
#|}
#|pub impl[
#| T0 : Eq,
#| T1 : Eq,
#| T2 : Eq,
#| T3 : Eq,
#| T4 : Eq,
#| T5 : Eq,
#| T6 : Eq,
#| T7 : Eq,
#| T8 : Eq,
#| T9 : Eq,
#|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) with equal(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9),
#|) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3 &&
#| self.4 == other.4 &&
#| self.5 == other.5 &&
#| self.6 == other.6 &&
#| self.7 == other.7 &&
#| self.8 == other.8 &&
#| self.9 == other.9
#|}
#|pub impl[
#| T0 : Eq,
#| T1 : Eq,
#| T2 : Eq,
#| T3 : Eq,
#| T4 : Eq,
#| T5 : Eq,
#| T6 : Eq,
#| T7 : Eq,
#| T8 : Eq,
#| T9 : Eq,
#| T10 : Eq,
#|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) with equal(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10),
#|) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3 &&
#| self.4 == other.4 &&
#| self.5 == other.5 &&
#| self.6 == other.6 &&
#| self.7 == other.7 &&
#| self.8 == other.8 &&
#| self.9 == other.9 &&
#| self.10 == other.10
#|}
#|pub impl[
#| T0 : Eq,
#| T1 : Eq,
#| T2 : Eq,
#| T3 : Eq,
#| T4 : Eq,
#| T5 : Eq,
#| T6 : Eq,
#| T7 : Eq,
#| T8 : Eq,
#| T9 : Eq,
#| T10 : Eq,
#| T11 : Eq,
#|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) with equal(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11),
#|) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3 &&
#| self.4 == other.4 &&
#| self.5 == other.5 &&
#| self.6 == other.6 &&
#| self.7 == other.7 &&
#| self.8 == other.8 &&
#| self.9 == other.9 &&
#| self.10 == other.10 &&
#| self.11 == other.11
#|}
#|pub impl[
#| T0 : Eq,
#| T1 : Eq,
#| T2 : Eq,
#| T3 : Eq,
#| T4 : Eq,
#| T5 : Eq,
#| T6 : Eq,
#| T7 : Eq,
#| T8 : Eq,
#| T9 : Eq,
#| T10 : Eq,
#| T11 : Eq,
#| T12 : Eq,
#|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) with equal(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12),
#|) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3 &&
#| self.4 == other.4 &&
#| self.5 == other.5 &&
#| self.6 == other.6 &&
#| self.7 == other.7 &&
#| self.8 == other.8 &&
#| self.9 == other.9 &&
#| self.10 == other.10 &&
#| self.11 == other.11 &&
#| self.12 == other.12
#|}
#|pub impl[
#| T0 : Eq,
#| T1 : Eq,
#| T2 : Eq,
#| T3 : Eq,
#| T4 : Eq,
#| T5 : Eq,
#| T6 : Eq,
#| T7 : Eq,
#| T8 : Eq,
#| T9 : Eq,
#| T10 : Eq,
#| T11 : Eq,
#| T12 : Eq,
#| T13 : Eq,
#|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) with equal(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13),
#|) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3 &&
#| self.4 == other.4 &&
#| self.5 == other.5 &&
#| self.6 == other.6 &&
#| self.7 == other.7 &&
#| self.8 == other.8 &&
#| self.9 == other.9 &&
#| self.10 == other.10 &&
#| self.11 == other.11 &&
#| self.12 == other.12 &&
#| self.13 == other.13
#|}
#|pub impl[
#| T0 : Eq,
#| T1 : Eq,
#| T2 : Eq,
#| T3 : Eq,
#| T4 : Eq,
#| T5 : Eq,
#| T6 : Eq,
#| T7 : Eq,
#| T8 : Eq,
#| T9 : Eq,
#| T10 : Eq,
#| T11 : Eq,
#| T12 : Eq,
#| T13 : Eq,
#| T14 : Eq,
#|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) with equal(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14),
#|) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3 &&
#| self.4 == other.4 &&
#| self.5 == other.5 &&
#| self.6 == other.6 &&
#| self.7 == other.7 &&
#| self.8 == other.8 &&
#| self.9 == other.9 &&
#| self.10 == other.10 &&
#| self.11 == other.11 &&
#| self.12 == other.12 &&
#| self.13 == other.13 &&
#| self.14 == other.14
#|}
#|pub impl[
#| T0 : Eq,
#| T1 : Eq,
#| T2 : Eq,
#| T3 : Eq,
#| T4 : Eq,
#| T5 : Eq,
#| T6 : Eq,
#| T7 : Eq,
#| T8 : Eq,
#| T9 : Eq,
#| T10 : Eq,
#| T11 : Eq,
#| T12 : Eq,
#| T13 : Eq,
#| T14 : Eq,
#| T15 : Eq,
#|] Eq for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) with equal(
#| self : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15),
#| other : (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15),
#|) -> Bool {
#| self.0 == other.0 &&
#| self.1 == other.1 &&
#| self.2 == other.2 &&
#| self.3 == other.3 &&
#| self.4 == other.4 &&
#| self.5 == other.5 &&
#| self.6 == other.6 &&
#| self.7 == other.7 &&
#| self.8 == other.8 &&
#| self.9 == other.9 &&
#| self.10 == other.10 &&
#| self.11 == other.11 &&
#| self.12 == other.12 &&
#| self.13 == other.13 &&
#| self.14 == other.14 &&
#| self.15 == other.15
#|}
),
"tuple_hash.mbt": (
#|pub impl[A : Hash, B : Hash] Hash for (A, B) with hash_combine(self, hasher) {
#| let (a, b) = self
#| hasher..combine(a)..combine(b)
#|}
#|pub impl[A : Hash, B : Hash, C : Hash] Hash for (A, B, C) with hash_combine(
#| self,
#| hasher,
#|) {
#| let (a, b, c) = self
#| hasher..combine(a)..combine(b)..combine(c)
#|}
#|pub impl[A : Hash, B : Hash, C : Hash, D : Hash] Hash for (A, B, C, D) with hash_combine(
#| self,
#| hasher,
#|) {
#| let (a, b, c, d) = self
#| hasher..combine(a)..combine(b)..combine(c)..combine(d)
#|}
#|pub impl[A : Hash, B : Hash, C : Hash, D : Hash, E : Hash] Hash for (
#| A,
#| B,
#| C,
#| D,
#| E,
#|) with hash_combine(self, hasher) {
#| let (a, b, c, d, e) = self
#| hasher..combine(a)..combine(b)..combine(c)..combine(d)..combine(e)
#|}
#|pub impl[A : Hash, B : Hash, C : Hash, D : Hash, E : Hash, F : Hash] Hash for (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#|) with hash_combine(self, hasher) {
#| let (a, b, c, d, e, f) = self
#| hasher..combine(a)..combine(b)..combine(c)..combine(d)..combine(e)..combine(f)
#|}
#|pub impl[A : Hash, B : Hash, C : Hash, D : Hash, E : Hash, F : Hash, G : Hash] Hash for (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#|) with hash_combine(self, hasher) {
#| let (a, b, c, d, e, f, g) = self
#| hasher
#| ..combine(a)
#| ..combine(b)
#| ..combine(c)
#| ..combine(d)
#| ..combine(e)
#| ..combine(f)
#| ..combine(g)
#|}
),
"tuple_show.mbt": (
#|pub impl[A : Show, B : Show] Show for (A, B) with output(self, logger) {
#| let (a, b) = self
#| logger
#| ..write_string("(")
#| ..write_object(a)
#| ..write_string(", ")
#| ..write_object(b)
#| ..write_string(")")
#|}
#|pub impl[A : Show, B : Show, C : Show] Show for (A, B, C) with output(
#| self,
#| logger,
#|) {
#| let (a, b, c) = self
#| logger
#| ..write_string("(")
#| ..write_object(a)
#| ..write_string(", ")
#| ..write_object(b)
#| ..write_string(", ")
#| ..write_object(c)
#| ..write_string(")")
#|}
#|pub impl[A : Show, B : Show, C : Show, D : Show] Show for (A, B, C, D) with output(
#| self,
#| logger,
#|) {
#| let (a, b, c, d) = self
#| logger
#| ..write_string("(")
#| ..write_object(a)
#| ..write_string(", ")
#| ..write_object(b)
#| ..write_string(", ")
#| ..write_object(c)
#| ..write_string(", ")
#| ..write_object(d)
#| ..write_string(")")
#|}
#|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show] Show for (
#| A,
#| B,
#| C,
#| D,
#| E,
#|) with output(self, logger) {
#| let (a, b, c, d, e) = self
#| logger
#| ..write_string("(")
#| ..write_object(a)
#| ..write_string(", ")
#| ..write_object(b)
#| ..write_string(", ")
#| ..write_object(c)
#| ..write_string(", ")
#| ..write_object(d)
#| ..write_string(", ")
#| ..write_object(e)
#| ..write_string(")")
#|}
#|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show, F : Show] Show for (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#|) with output(self, logger) {
#| let (a, b, c, d, e, f) = self
#| logger
#| ..write_string("(")
#| ..write_object(a)
#| ..write_string(", ")
#| ..write_object(b)
#| ..write_string(", ")
#| ..write_object(c)
#| ..write_string(", ")
#| ..write_object(d)
#| ..write_string(", ")
#| ..write_object(e)
#| ..write_string(", ")
#| ..write_object(f)
#| ..write_string(")")
#|}
#|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show, F : Show, G : Show] Show for (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#|) with output(self, logger) {
#| let (a, b, c, d, e, f, g) = self
#| logger
#| ..write_string("(")
#| ..write_object(a)
#| ..write_string(", ")
#| ..write_object(b)
#| ..write_string(", ")
#| ..write_object(c)
#| ..write_string(", ")
#| ..write_object(d)
#| ..write_string(", ")
#| ..write_object(e)
#| ..write_string(", ")
#| ..write_object(f)
#| ..write_string(", ")
#| ..write_object(g)
#| ..write_string(")")
#|}
#|pub impl[
#| T0 : Show,
#| T1 : Show,
#| T2 : Show,
#| T3 : Show,
#| T4 : Show,
#| T5 : Show,
#| T6 : Show,
#| T7 : Show,
#|] Show for (T0, T1, T2, T3, T4, T5, T6, T7) with output(self, logger) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7) = self
#| logger
#| ..write_string("(")
#| ..write_object(x0)
#| ..write_string(", ")
#| ..write_object(x1)
#| ..write_string(", ")
#| ..write_object(x2)
#| ..write_string(", ")
#| ..write_object(x3)
#| ..write_string(", ")
#| ..write_object(x4)
#| ..write_string(", ")
#| ..write_object(x5)
#| ..write_string(", ")
#| ..write_object(x6)
#| ..write_string(", ")
#| ..write_object(x7)
#| ..write_string(")")
#|}
#|pub impl[
#| T0 : Show,
#| T1 : Show,
#| T2 : Show,
#| T3 : Show,
#| T4 : Show,
#| T5 : Show,
#| T6 : Show,
#| T7 : Show,
#| T8 : Show,
#|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8) with output(self, logger) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8) = self
#| logger
#| ..write_string("(")
#| ..write_object(x0)
#| ..write_string(", ")
#| ..write_object(x1)
#| ..write_string(", ")
#| ..write_object(x2)
#| ..write_string(", ")
#| ..write_object(x3)
#| ..write_string(", ")
#| ..write_object(x4)
#| ..write_string(", ")
#| ..write_object(x5)
#| ..write_string(", ")
#| ..write_object(x6)
#| ..write_string(", ")
#| ..write_object(x7)
#| ..write_string(", ")
#| ..write_object(x8)
#| ..write_string(")")
#|}
#|pub impl[
#| T0 : Show,
#| T1 : Show,
#| T2 : Show,
#| T3 : Show,
#| T4 : Show,
#| T5 : Show,
#| T6 : Show,
#| T7 : Show,
#| T8 : Show,
#| T9 : Show,
#|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) with output(self, logger) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) = self
#| logger
#| ..write_string("(")
#| ..write_object(x0)
#| ..write_string(", ")
#| ..write_object(x1)
#| ..write_string(", ")
#| ..write_object(x2)
#| ..write_string(", ")
#| ..write_object(x3)
#| ..write_string(", ")
#| ..write_object(x4)
#| ..write_string(", ")
#| ..write_object(x5)
#| ..write_string(", ")
#| ..write_object(x6)
#| ..write_string(", ")
#| ..write_object(x7)
#| ..write_string(", ")
#| ..write_object(x8)
#| ..write_string(", ")
#| ..write_object(x9)
#| ..write_string(")")
#|}
#|pub impl[
#| T0 : Show,
#| T1 : Show,
#| T2 : Show,
#| T3 : Show,
#| T4 : Show,
#| T5 : Show,
#| T6 : Show,
#| T7 : Show,
#| T8 : Show,
#| T9 : Show,
#| T10 : Show,
#|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) with output(
#| self,
#| logger,
#|) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) = self
#| logger
#| ..write_string("(")
#| ..write_object(x0)
#| ..write_string(", ")
#| ..write_object(x1)
#| ..write_string(", ")
#| ..write_object(x2)
#| ..write_string(", ")
#| ..write_object(x3)
#| ..write_string(", ")
#| ..write_object(x4)
#| ..write_string(", ")
#| ..write_object(x5)
#| ..write_string(", ")
#| ..write_object(x6)
#| ..write_string(", ")
#| ..write_object(x7)
#| ..write_string(", ")
#| ..write_object(x8)
#| ..write_string(", ")
#| ..write_object(x9)
#| ..write_string(", ")
#| ..write_object(x10)
#| ..write_string(")")
#|}
#|pub impl[
#| T0 : Show,
#| T1 : Show,
#| T2 : Show,
#| T3 : Show,
#| T4 : Show,
#| T5 : Show,
#| T6 : Show,
#| T7 : Show,
#| T8 : Show,
#| T9 : Show,
#| T10 : Show,
#| T11 : Show,
#|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) with output(
#| self,
#| logger,
#|) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) = self
#| logger
#| ..write_string("(")
#| ..write_object(x0)
#| ..write_string(", ")
#| ..write_object(x1)
#| ..write_string(", ")
#| ..write_object(x2)
#| ..write_string(", ")
#| ..write_object(x3)
#| ..write_string(", ")
#| ..write_object(x4)
#| ..write_string(", ")
#| ..write_object(x5)
#| ..write_string(", ")
#| ..write_object(x6)
#| ..write_string(", ")
#| ..write_object(x7)
#| ..write_string(", ")
#| ..write_object(x8)
#| ..write_string(", ")
#| ..write_object(x9)
#| ..write_string(", ")
#| ..write_object(x10)
#| ..write_string(", ")
#| ..write_object(x11)
#| ..write_string(")")
#|}
#|pub impl[
#| T0 : Show,
#| T1 : Show,
#| T2 : Show,
#| T3 : Show,
#| T4 : Show,
#| T5 : Show,
#| T6 : Show,
#| T7 : Show,
#| T8 : Show,
#| T9 : Show,
#| T10 : Show,
#| T11 : Show,
#| T12 : Show,
#|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) with output(
#| self,
#| logger,
#|) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) = self
#| logger
#| ..write_string("(")
#| ..write_object(x0)
#| ..write_string(", ")
#| ..write_object(x1)
#| ..write_string(", ")
#| ..write_object(x2)
#| ..write_string(", ")
#| ..write_object(x3)
#| ..write_string(", ")
#| ..write_object(x4)
#| ..write_string(", ")
#| ..write_object(x5)
#| ..write_string(", ")
#| ..write_object(x6)
#| ..write_string(", ")
#| ..write_object(x7)
#| ..write_string(", ")
#| ..write_object(x8)
#| ..write_string(", ")
#| ..write_object(x9)
#| ..write_string(", ")
#| ..write_object(x10)
#| ..write_string(", ")
#| ..write_object(x11)
#| ..write_string(", ")
#| ..write_object(x12)
#| ..write_string(")")
#|}
#|pub impl[
#| T0 : Show,
#| T1 : Show,
#| T2 : Show,
#| T3 : Show,
#| T4 : Show,
#| T5 : Show,
#| T6 : Show,
#| T7 : Show,
#| T8 : Show,
#| T9 : Show,
#| T10 : Show,
#| T11 : Show,
#| T12 : Show,
#| T13 : Show,
#|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) with output(
#| self,
#| logger,
#|) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13) = self
#| logger
#| ..write_string("(")
#| ..write_object(x0)
#| ..write_string(", ")
#| ..write_object(x1)
#| ..write_string(", ")
#| ..write_object(x2)
#| ..write_string(", ")
#| ..write_object(x3)
#| ..write_string(", ")
#| ..write_object(x4)
#| ..write_string(", ")
#| ..write_object(x5)
#| ..write_string(", ")
#| ..write_object(x6)
#| ..write_string(", ")
#| ..write_object(x7)
#| ..write_string(", ")
#| ..write_object(x8)
#| ..write_string(", ")
#| ..write_object(x9)
#| ..write_string(", ")
#| ..write_object(x10)
#| ..write_string(", ")
#| ..write_object(x11)
#| ..write_string(", ")
#| ..write_object(x12)
#| ..write_string(", ")
#| ..write_object(x13)
#| ..write_string(")")
#|}
#|pub impl[
#| T0 : Show,
#| T1 : Show,
#| T2 : Show,
#| T3 : Show,
#| T4 : Show,
#| T5 : Show,
#| T6 : Show,
#| T7 : Show,
#| T8 : Show,
#| T9 : Show,
#| T10 : Show,
#| T11 : Show,
#| T12 : Show,
#| T13 : Show,
#| T14 : Show,
#|] Show for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) with output(
#| self,
#| logger,
#|) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14) = self
#| logger
#| ..write_string("(")
#| ..write_object(x0)
#| ..write_string(", ")
#| ..write_object(x1)
#| ..write_string(", ")
#| ..write_object(x2)
#| ..write_string(", ")
#| ..write_object(x3)
#| ..write_string(", ")
#| ..write_object(x4)
#| ..write_string(", ")
#| ..write_object(x5)
#| ..write_string(", ")
#| ..write_object(x6)
#| ..write_string(", ")
#| ..write_object(x7)
#| ..write_string(", ")
#| ..write_object(x8)
#| ..write_string(", ")
#| ..write_object(x9)
#| ..write_string(", ")
#| ..write_object(x10)
#| ..write_string(", ")
#| ..write_object(x11)
#| ..write_string(", ")
#| ..write_object(x12)
#| ..write_string(", ")
#| ..write_object(x13)
#| ..write_string(", ")
#| ..write_object(x14)
#| ..write_string(")")
#|}
#|pub impl[
#| T0 : Show,
#| T1 : Show,
#| T2 : Show,
#| T3 : Show,
#| T4 : Show,
#| T5 : Show,
#| T6 : Show,
#| T7 : Show,
#| T8 : Show,
#| T9 : Show,
#| T10 : Show,
#| T11 : Show,
#| T12 : Show,
#| T13 : Show,
#| T14 : Show,
#| T15 : Show,
#|] Show for (
#| T0,
#| T1,
#| T2,
#| T3,
#| T4,
#| T5,
#| T6,
#| T7,
#| T8,
#| T9,
#| T10,
#| T11,
#| T12,
#| T13,
#| T14,
#| T15,
#|) with output(self, logger) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) = self
#| logger
#| ..write_string("(")
#| ..write_object(x0)
#| ..write_string(", ")
#| ..write_object(x1)
#| ..write_string(", ")
#| ..write_object(x2)
#| ..write_string(", ")
#| ..write_object(x3)
#| ..write_string(", ")
#| ..write_object(x4)
#| ..write_string(", ")
#| ..write_object(x5)
#| ..write_string(", ")
#| ..write_object(x6)
#| ..write_string(", ")
#| ..write_object(x7)
#| ..write_string(", ")
#| ..write_object(x8)
#| ..write_string(", ")
#| ..write_object(x9)
#| ..write_string(", ")
#| ..write_object(x10)
#| ..write_string(", ")
#| ..write_object(x11)
#| ..write_string(", ")
#| ..write_object(x12)
#| ..write_string(", ")
#| ..write_object(x13)
#| ..write_string(", ")
#| ..write_object(x14)
#| ..write_string(", ")
#| ..write_object(x15)
#| ..write_string(")")
#|}
),
"tuple_to_json.mbt": (
#|pub impl[A : ToJson, B : ToJson] ToJson for (A, B) with to_json(self) {
#| let (a0, a1) = self
#| [a0, a1]
#|}
#|pub impl[A : ToJson, B : ToJson, C : ToJson] ToJson for (A, B, C) with to_json(
#| self,
#|) {
#| let (a0, a1, a2) = self
#| [a0, a1, a2]
#|}
#|pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson] ToJson for (A, B, C, D) with to_json(
#| self,
#|) {
#| let (a0, a1, a2, a3) = self
#| [a0, a1, a2, a3]
#|}
#|pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson, E : ToJson] ToJson for (
#| A,
#| B,
#| C,
#| D,
#| E,
#|) with to_json(self) {
#| let (a0, a1, a2, a3, a4) = self
#| [a0, a1, a2, a3, a4]
#|}
#|pub impl[A : ToJson, B : ToJson, C : ToJson, D : ToJson, E : ToJson, F : ToJson] ToJson for (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#|) with to_json(self) {
#| let (a0, a1, a2, a3, a4, a5) = self
#| [a0, a1, a2, a3, a4, a5]
#|}
#|pub impl[
#| A : ToJson,
#| B : ToJson,
#| C : ToJson,
#| D : ToJson,
#| E : ToJson,
#| F : ToJson,
#| G : ToJson,
#|] ToJson for (A, B, C, D, E, F, G) with to_json(self) {
#| let (a0, a1, a2, a3, a4, a5, a6) = self
#| [a0, a1, a2, a3, a4, a5, a6]
#|}
#|pub impl[
#| A : ToJson,
#| B : ToJson,
#| C : ToJson,
#| D : ToJson,
#| E : ToJson,
#| F : ToJson,
#| G : ToJson,
#| H : ToJson,
#|] ToJson for (A, B, C, D, E, F, G, H) with to_json(self) {
#| let (a0, a1, a2, a3, a4, a5, a6, a7) = self
#| [a0, a1, a2, a3, a4, a5, a6, a7]
#|}
#|pub impl[
#| A : ToJson,
#| B : ToJson,
#| C : ToJson,
#| D : ToJson,
#| E : ToJson,
#| F : ToJson,
#| G : ToJson,
#| H : ToJson,
#| I : ToJson,
#|] ToJson for (A, B, C, D, E, F, G, H, I) with to_json(self) {
#| let (a0, a1, a2, a3, a4, a5, a6, a7, a8) = self
#| [a0, a1, a2, a3, a4, a5, a6, a7, a8]
#|}
#|pub impl[
#| A : ToJson,
#| B : ToJson,
#| C : ToJson,
#| D : ToJson,
#| E : ToJson,
#| F : ToJson,
#| G : ToJson,
#| H : ToJson,
#| I : ToJson,
#| J : ToJson,
#|] ToJson for (A, B, C, D, E, F, G, H, I, J) with to_json(self) {
#| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) = self
#| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]
#|}
#|pub impl[
#| A : ToJson,
#| B : ToJson,
#| C : ToJson,
#| D : ToJson,
#| E : ToJson,
#| F : ToJson,
#| G : ToJson,
#| H : ToJson,
#| I : ToJson,
#| J : ToJson,
#| K : ToJson,
#|] ToJson for (A, B, C, D, E, F, G, H, I, J, K) with to_json(self) {
#| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) = self
#| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]
#|}
#|pub impl[
#| A : ToJson,
#| B : ToJson,
#| C : ToJson,
#| D : ToJson,
#| E : ToJson,
#| F : ToJson,
#| G : ToJson,
#| H : ToJson,
#| I : ToJson,
#| J : ToJson,
#| K : ToJson,
#| L : ToJson,
#|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L) with to_json(self) {
#| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) = self
#| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11]
#|}
#|pub impl[
#| A : ToJson,
#| B : ToJson,
#| C : ToJson,
#| D : ToJson,
#| E : ToJson,
#| F : ToJson,
#| G : ToJson,
#| H : ToJson,
#| I : ToJson,
#| J : ToJson,
#| K : ToJson,
#| L : ToJson,
#| M : ToJson,
#|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M) with to_json(self) {
#| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) = self
#| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12]
#|}
#|pub impl[
#| A : ToJson,
#| B : ToJson,
#| C : ToJson,
#| D : ToJson,
#| E : ToJson,
#| F : ToJson,
#| G : ToJson,
#| H : ToJson,
#| I : ToJson,
#| J : ToJson,
#| K : ToJson,
#| L : ToJson,
#| M : ToJson,
#| N : ToJson,
#|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M, N) with to_json(self) {
#| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) = self
#| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13]
#|}
#|pub impl[
#| A : ToJson,
#| B : ToJson,
#| C : ToJson,
#| D : ToJson,
#| E : ToJson,
#| F : ToJson,
#| G : ToJson,
#| H : ToJson,
#| I : ToJson,
#| J : ToJson,
#| K : ToJson,
#| L : ToJson,
#| M : ToJson,
#| N : ToJson,
#| O : ToJson,
#|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) with to_json(self) {
#| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) = self
#| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14]
#|}
#|pub impl[
#| A : ToJson,
#| B : ToJson,
#| C : ToJson,
#| D : ToJson,
#| E : ToJson,
#| F : ToJson,
#| G : ToJson,
#| H : ToJson,
#| I : ToJson,
#| J : ToJson,
#| K : ToJson,
#| L : ToJson,
#| M : ToJson,
#| N : ToJson,
#| O : ToJson,
#| P : ToJson,
#|] ToJson for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) with to_json(self) {
#| let (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) = self
#| [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15]
#|}
),
"uint64.mbt": (
#|pub impl Default for UInt64 with default() {
#| 0
#|}
#|test {
#| inspect(0x7000_0001_1F00_100FUL.popcnt(), content="14")
#|}
),
"uninitialized_array.mbt": (
#|struct UninitializedArray[T](FixedArray[UnsafeMaybeUninit[T]])
#|pub fn[T] UninitializedArray::make(size : Int) -> UninitializedArray[T] = "%fixedarray.make_uninit"
#|pub fn[T] UninitializedArray::op_get(
#| self : UninitializedArray[T],
#| index : Int,
#|) -> T = "%fixedarray.get"
#|pub fn[T] UninitializedArray::op_set(
#| self : UninitializedArray[T],
#| index : Int,
#| value : T,
#|) = "%fixedarray.set"
#|pub fn[T] UninitializedArray::op_as_view(
#| self : UninitializedArray[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let len = self.length()
#| let end = match end {
#| None => len
#| Some(end) => end
#| }
#| guard start >= 0 && start <= end && end <= len else {
#| abort("View start index out of bounds")
#| }
#| ArrayView::make(self, start, end - start)
#|}
#|pub fn[A] UninitializedArray::length(self : UninitializedArray[A]) -> Int {
#| let UninitializedArray(self) = self
#| self.length()
#|}
#|#internal(unsafe, "For internal use only.")
#|pub fn[T] UninitializedArray::unsafe_blit(
#| dst : UninitializedArray[T],
#| dst_offset : Int,
#| src : UninitializedArray[T],
#| src_offset : Int,
#| len : Int,
#|) -> Unit {
#| FixedArray::unsafe_blit(dst.0, dst_offset, src.0, src_offset, len)
#|}
#|test "op_as_view with valid_range" {
#| let arr : UninitializedArray[Int] = UninitializedArray::make(5)
#| let view = arr[1:4]
#| inspect(view.start(), content="1")
#| inspect(view.len(), content="3")
#|}
#|test "panic op_as_view with invalid_start" {
#| let arr : UninitializedArray[Int] = UninitializedArray::make(5)
#| ignore(arr[-1:])
#|}
#|test "panic op_as_view with invalid_end" {
#| let arr : UninitializedArray[Int] = UninitializedArray::make(5)
#| ignore(arr[2:10])
#|}
#|#intrinsic("%fixedarray.fill")
#|#cfg(not(target="js"))
#|fn[T] UninitializedArray::unchecked_fill(
#| self : UninitializedArray[T],
#| start : Int,
#| value : T,
#| len : Int,
#|) -> Unit {
#| for i in start..<(start + len) {
#| self[i] = value
#| }
#|}
),
"unit.mbt": (
#|pub impl Eq for Unit with equal(self : Unit, _other : Unit) -> Bool {
#| let _ = self
#| true
#|}
#|pub impl Eq for Unit with op_equal(self : Unit, _other : Unit) -> Bool {
#| let _ = self
#| true
#|}
),
},
)
///|
let moonbitlang_core_byte_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/byte",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin"]
#|}
),
"byte.mbt": (
#|pub let max_value : Byte = b'\xFF'
#|pub let min_value : Byte = b'\x00'
#|pub fn to_uint64(self : Byte) -> UInt64 {
#| self.to_uint().to_uint64()
#|}
#|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 : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/bytes",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin"],
#| "test-import": [
#| "moonbitlang/core/array",
#| "moonbitlang/core/double",
#| "moonbitlang/core/uint",
#| "moonbitlang/core/uint64",
#| "moonbitlang/core/test",
#| "moonbitlang/core/quickcheck",
#| "moonbitlang/core/error"
#| ]
#|}
),
"bitstring.mbt": (
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn View::unsafe_extract_bit(bs : View, offset : Int, _len : Int) -> UInt {
#| let byte_index = offset >> 3
#| let bit_mask = (1 << (7 - (offset & 7))).to_byte()
#| if (bs.unsafe_get(byte_index) & bit_mask) != 0 {
#| 1
#| } else {
#| 0
#| }
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn View::unsafe_extract_byte(bs : View, offset : Int, len : Int) -> UInt {
#| let byte_index = offset >> 3
#| if (offset & 7) == 0 {
#| let byte = bs.unsafe_get(byte_index)
#| (byte >> (8 - len)).to_uint()
#| } else if (offset & 7) + len <= 8 {
#| let byte = bs.unsafe_get(byte_index).to_uint()
#| let shift = 8 - ((offset & 7) + len)
#| let mask = (1U << len) - 1
#| (byte >> shift) & mask
#| } else {
#| let b0 = bs.unsafe_get(byte_index).to_uint()
#| let b1 = bs.unsafe_get(byte_index + 1).to_uint()
#| let data = (b0 << 8) | b1
#| let bit_mask = (1U << (16 - (offset & 7))) - 1
#| let data = data & bit_mask
#| let shift = 16 - ((offset & 7) + len)
#| data >> shift
#| }
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn View::unsafe_extract_uint_le(bs : View, offset : Int, len : Int) -> UInt {
#| let bytes_needed = (len + 7) / 8
#| let b0 = bs.unsafe_extract_byte(offset, 8)
#| match bytes_needed {
#| 2 => {
#| let b1 = bs.unsafe_extract_byte(offset + 8, len - 8)
#| (b1 << 8) | b0
#| }
#| 3 => {
#| let b1 = bs.unsafe_extract_byte(offset + 8, 8)
#| let b2 = bs.unsafe_extract_byte(offset + 16, len - 16)
#| (b2 << 16) | (b1 << 8) | b0
#| }
#| 4 => {
#| let b1 = bs.unsafe_extract_byte(offset + 8, 8)
#| let b2 = bs.unsafe_extract_byte(offset + 16, 8)
#| let b3 = bs.unsafe_extract_byte(offset + 24, len - 24)
#| (b3 << 24) | (b2 << 16) | (b1 << 8) | b0
#| }
#| _ => abort("Invalid byte count for int32 extraction")
#| }
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn View::unsafe_extract_uint_be(bs : View, offset : Int, len : Int) -> UInt {
#| let bytes_needed = (len + 7) / 8
#| let b0 = bs.unsafe_extract_byte(offset, 8)
#| match bytes_needed {
#| 2 => {
#| let b1 = bs.unsafe_extract_byte(offset + 8, len - 8)
#| let shift = 16 - len
#| let data = (b0 << 8) | (b1 << shift)
#| data >> shift
#| }
#| 3 => {
#| let b1 = bs.unsafe_extract_byte(offset + 8, 8)
#| let b2 = bs.unsafe_extract_byte(offset + 16, len - 16)
#| let shift = 24 - len
#| let data = (b0 << 16) | (b1 << 8) | (b2 << shift)
#| data >> shift
#| }
#| 4 => {
#| let b1 = bs.unsafe_extract_byte(offset + 8, 8)
#| let b2 = bs.unsafe_extract_byte(offset + 16, 8)
#| let b3 = bs.unsafe_extract_byte(offset + 24, len - 24)
#| let shift = 32 - len
#| let data = (b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << shift)
#| data >> shift
#| }
#| _ => abort("Invalid byte count for int32 extraction")
#| }
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn View::unsafe_extract_uint64_le(
#| bs : View,
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| let bytes_needed = (len + 7) / 8
#| let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64()
#| let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64()
#| let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64()
#| let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64()
#| match bytes_needed {
#| 5 => {
#| let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64()
#| (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0
#| }
#| 6 => {
#| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64()
#| let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64()
#| (b5 << 40) | (b4 << 32) | (b3 << 24) | (b2 << 16) | (b1 << 8) | b0
#| }
#| 7 => {
#| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64()
#| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64()
#| let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64()
#| (b6 << 48) |
#| (b5 << 40) |
#| (b4 << 32) |
#| (b3 << 24) |
#| (b2 << 16) |
#| (b1 << 8) |
#| b0
#| }
#| 8 => {
#| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64()
#| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64()
#| let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64()
#| let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64()
#| (b7 << 56) |
#| (b6 << 48) |
#| (b5 << 40) |
#| (b4 << 32) |
#| (b3 << 24) |
#| (b2 << 16) |
#| (b1 << 8) |
#| b0
#| }
#| _ => abort("Invalid byte count for int64 extraction")
#| }
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn View::unsafe_extract_uint64_be(
#| bs : View,
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| let bytes_needed = (len + 7) / 8
#| let b0 = bs.unsafe_extract_byte(offset, 8).to_uint64()
#| let b1 = bs.unsafe_extract_byte(offset + 8, 8).to_uint64()
#| let b2 = bs.unsafe_extract_byte(offset + 16, 8).to_uint64()
#| let b3 = bs.unsafe_extract_byte(offset + 24, 8).to_uint64()
#| match bytes_needed {
#| 5 => {
#| let b4 = bs.unsafe_extract_byte(offset + 32, len - 32).to_uint64()
#| let shift = 40 - len
#| let data = (b0 << 32) |
#| (b1 << 24) |
#| (b2 << 16) |
#| (b3 << 8) |
#| (b4 << shift)
#| data >> shift
#| }
#| 6 => {
#| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64()
#| let b5 = bs.unsafe_extract_byte(offset + 40, len - 40).to_uint64()
#| let shift = 48 - len
#| let data = (b0 << 40) |
#| (b1 << 32) |
#| (b2 << 24) |
#| (b3 << 16) |
#| (b4 << 8) |
#| (b5 << shift)
#| data >> shift
#| }
#| 7 => {
#| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64()
#| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64()
#| let b6 = bs.unsafe_extract_byte(offset + 48, len - 48).to_uint64()
#| let shift = 56 - len
#| let data = (b0 << 48) |
#| (b1 << 40) |
#| (b2 << 32) |
#| (b3 << 24) |
#| (b4 << 16) |
#| (b5 << 8) |
#| (b6 << shift)
#| data >> shift
#| }
#| 8 => {
#| let b4 = bs.unsafe_extract_byte(offset + 32, 8).to_uint64()
#| let b5 = bs.unsafe_extract_byte(offset + 40, 8).to_uint64()
#| let b6 = bs.unsafe_extract_byte(offset + 48, 8).to_uint64()
#| let b7 = bs.unsafe_extract_byte(offset + 56, len - 56).to_uint64()
#| let shift = 64 - len
#| let data = (b0 << 56) |
#| (b1 << 48) |
#| (b2 << 40) |
#| (b3 << 32) |
#| (b4 << 24) |
#| (b5 << 16) |
#| (b6 << 8) |
#| (b7 << shift)
#| data >> shift
#| }
#| _ => abort("Invalid byte count for int64 extraction")
#| }
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn View::unsafe_extract_bytesview(
#| bs : View,
#| offset : Int,
#| len : Int,
#|) -> View {
#| View::make(bs.bytes(), bs.start() + (offset >> 3), len >> 3)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn Bytes::unsafe_extract_bit(bs : Bytes, offset : Int, len : Int) -> UInt {
#| bs[:].unsafe_extract_bit(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn Bytes::unsafe_extract_byte(bs : Bytes, offset : Int, len : Int) -> UInt {
#| bs[:].unsafe_extract_byte(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn Bytes::unsafe_extract_uint_le(
#| bs : Bytes,
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn Bytes::unsafe_extract_uint_be(
#| bs : Bytes,
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn Bytes::unsafe_extract_uint64_le(
#| bs : Bytes,
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| bs[:].unsafe_extract_uint64_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn Bytes::unsafe_extract_uint64_be(
#| bs : Bytes,
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| bs[:].unsafe_extract_uint64_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|pub fn Bytes::unsafe_extract_bytesview(
#| bs : Bytes,
#| offset : Int,
#| len : Int,
#|) -> View {
#| bs[:].unsafe_extract_bytesview(offset, len)
#|}
),
"bytes.mbt": (
#|pub fn Bytes::from_array(arr : Array[Byte]) -> Bytes {
#| Bytes::makei(arr.length(), i => arr[i])
#|}
#|pub fn from_array(arr : Array[Byte]) -> Bytes {
#| Bytes::makei(arr.length(), i => arr[i])
#|}
#|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])
#|}
#|pub fn from_fixedarray(arr : FixedArray[Byte], len? : Int) -> Bytes {
#| Bytes::from_fixedarray(arr, len?)
#|}
#|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())
#|}
#|pub fn from_iter(iter : Iter[Byte]) -> Bytes {
#| from_array(iter.collect())
#|}
#|pub fn Bytes::of(arr : FixedArray[Byte]) -> Bytes {
#| Bytes::makei(arr.length(), i => arr[i])
#|}
#|pub fn of(arr : FixedArray[Byte]) -> Bytes {
#| Bytes::makei(arr.length(), i => arr[i])
#|}
#|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])
#|}
#|pub fn default() -> Bytes {
#| b""
#|}
#|fn unsafe_to_bytes(array : FixedArray[Byte]) -> Bytes = "%identity"
#|pub impl Add for Bytes with add(self : Bytes, other : Bytes) -> Bytes {
#| let len_self = self.length()
#| let len_other = other.length()
#| let rv : FixedArray[Byte] = FixedArray::make(len_self + len_other, 0)
#| for i in 0.. Int? {
#| let target_len = target.length()
#| let pattern_len = pattern.length()
#| for i in 0..=(target_len - pattern_len) {
#| for j in 0.. Int? {
#| target[:].find(pattern)
#|}
#|pub fn View::rev_find(target : View, pattern : View) -> Int? {
#| let target_len = target.length()
#| let pattern_len = pattern.length()
#| for i = target_len - pattern_len; i >= 0; i = i - 1 {
#| for j in 0.. Int? {
#| target[:].rev_find(pattern)
#|}
),
"view.mbt": (
#|#builtin.valtype
#|type View
#|fn View::bytes(self : View) -> Bytes = "%bytesview.bytes"
#|fn View::start(self : View) -> Int = "%bytesview.start"
#|fn View::make(b : Bytes, start : Int, len : Int) -> View = "%bytesview.make"
#|pub fn View::length(self : View) -> Int {
#| self.len()
#|}
#|fn View::len(self : View) -> Int = "%bytesview.len"
#|pub fn View::op_get(self : View, index : Int) -> Byte {
#| 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}",
#| )
#| }
#| self.bytes()[self.start() + index]
#|}
#|pub fn View::get(self : View, index : Int) -> Byte? {
#| guard index >= 0 && index < self.length() else { None }
#| Some(self.bytes().unsafe_get(self.start() + index))
#|}
#|#internal(unsafe, "Panic if index is out of bounds")
#|pub fn View::unsafe_get(self : View, index : Int) -> Byte {
#| self.bytes()[self.start() + index]
#|}
#|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)
#|}
#|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)
#|}
#|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()
#|}
#|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)
#|}
#|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()
#|}
#|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)
#|}
#|pub fn View::to_int_be(self : View) -> Int {
#| self.to_uint_be().reinterpret_as_int()
#|}
#|pub fn View::to_int_le(self : View) -> Int {
#| self.to_uint_le().reinterpret_as_int()
#|}
#|pub fn View::to_int64_be(self : View) -> Int64 {
#| self.to_uint64_be().reinterpret_as_int64()
#|}
#|pub fn View::to_int64_le(self : View) -> Int64 {
#| self.to_uint64_le().reinterpret_as_int64()
#|}
#|pub fn View::to_float_be(self : View) -> Float {
#| self.to_uint_be().reinterpret_as_float()
#|}
#|pub fn View::to_float_le(self : View) -> Float {
#| self.to_uint_le().reinterpret_as_float()
#|}
#|pub fn View::to_double_be(self : View) -> Double {
#| self.to_uint64_be().reinterpret_as_double()
#|}
#|pub fn View::to_double_le(self : View) -> Double {
#| self.to_uint64_le().reinterpret_as_double()
#|}
#|pub impl Show for View with output(self, logger) {
#| 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()
#| }
#| }
#| logger.write_string("b\"")
#| for i in 0.. Bool {
#| guard self.length() == other.length() else { return false }
#| for i in 0.. Int {
#| let self_len = self.length()
#| let other_len = other.length()
#| let cmp = self_len.compare(other_len)
#| guard cmp == 0 else { return cmp }
#| for i in 0.. Bytes {
#| self.bytes()
#|}
#|pub fn View::start_offset(self : View) -> Int {
#| self.start()
#|}
#|pub fn View::to_bytes(self : View) -> Bytes {
#| if self.length() == 0 && self.length() == self.bytes().length() {
#| return self.bytes()
#| }
#| let bytes = FixedArray::make(self.length(), (0 : Byte))
#| bytes.blit_from_bytes(0, self.bytes(), self.start_offset(), self.length())
#| unsafe_to_bytes(bytes)
#|}
#|pub impl Hash for View with hash_combine(self : View, hasher : Hasher) {
#| for i in 0.. Int {
#| xxhash32(self.data(), 0, offset=self.start_offset(), len=self.length())
#|}
),
"xxhash.mbt": (
#|let gPRIME1 = 0x9E3779B1
#|let gPRIME2 = 0x85EBCA77
#|let gPRIME3 = 0xC2B2AE3D
#|let gPRIME4 = 0x27D4EB2F
#|let gPRIME5 = 0x165667B1
#|fn xxhash32(
#| input : Bytes,
#| offset? : Int = 0,
#| len? : Int = input.length(),
#| seed : Int,
#|) -> Int {
#| let h = (if len >= 16 {
#| h16bytes(input, offset, len, seed)
#| } else {
#| seed + gPRIME5
#| }) +
#| len
#| finalize(h, input, offset + (len & -16), len & 0xF)
#|}
#|pub impl Hash for Bytes with hash(self) {
#| xxhash32(self, 0)
#|}
#|pub impl Hash for Bytes with hash_combine(self, hasher) {
#| hasher.combine_bytes(self)
#|}
#|fn rotl(x : Int, r : Int) -> Int {
#| (x << r) | (x.reinterpret_as_uint() >> (32 - r)).reinterpret_as_int()
#|}
#|fn round(acc : Int, input : Int) -> Int {
#| rotl(acc + input * gPRIME2, 13) * gPRIME1
#|}
#|fn avalanche_step(h : Int, rshift : Int, prime : Int) -> Int {
#| (h ^ (h.reinterpret_as_uint() >> rshift).reinterpret_as_int()) * prime
#|}
#|fn avalanche(h : Int) -> Int {
#| avalanche_step(
#| avalanche_step(avalanche_step(h, 15, gPRIME2), 13, gPRIME3),
#| 16,
#| 1,
#| )
#|}
#|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))
#| )
#|}
#|fn fetch32(input : Bytes, cur : Int, v : Int) -> Int {
#| round(v, endian32(input, cur))
#|}
#|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)
#| }
#|}
#|fn _h16bytes(
#| input : Bytes,
#| cur : Int,
#| remain : Int,
#| v1 : Int,
#| v2 : Int,
#| v3 : Int,
#| v4 : Int,
#|) -> Int {
#| if remain >= 16 {
#| _h16bytes(
#| input,
#| cur + 16,
#| remain - 16,
#| fetch32(input, cur, v1),
#| fetch32(input, cur + 4, v2),
#| fetch32(input, cur + 8, v3),
#| fetch32(input, cur + 12, v4),
#| )
#| } else {
#| rotl(v1, 1) + rotl(v2, 7) + rotl(v3, 12) + rotl(v4, 18)
#| }
#|}
#|fn h16bytes(input : Bytes, cur : Int, len : Int, seed : Int) -> Int {
#| _h16bytes(
#| input,
#| cur,
#| len,
#| seed + gPRIME1 + gPRIME2,
#| seed + gPRIME2,
#| seed,
#| seed - gPRIME1,
#| )
#|}
#|test "Bytes hash_combine" {
#| let data : Bytes = [1, 2, 3, 4]
#| let hasher = Hasher::new()
#| data.hash_combine(hasher)
#| assert_true(hasher.finalize() != 0)
#|}
),
},
)
///|
let moonbitlang_core_char_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/char",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin"]
#|}
),
"char.mbt": (
#|pub impl Hash for Char with hash(self) {
#| self.to_int()
#|}
#|pub impl Hash for Char with hash_combine(self, hasher) -> Unit {
#| hasher.combine_char(self)
#|}
#|pub fn Char::is_ascii(self : Self) -> Bool {
#| self is ('\u{00}'..='\u{7F}')
#|}
#|pub fn Char::is_ascii_alphabetic(self : Self) -> Bool {
#| self is ('A'..='Z' | 'a'..='z')
#|}
#|pub fn Char::is_ascii_control(self : Self) -> Bool {
#| self is ('\u{00}'..='\u{1F}' | '\u{7F}')
#|}
#|pub fn Char::is_ascii_digit(self : Self) -> Bool {
#| self is ('0'..='9')
#|}
#|pub fn Char::is_ascii_graphic(self : Self) -> Bool {
#| self is ('\u{21}'..='\u{7E}')
#|}
#|pub fn Char::is_ascii_hexdigit(self : Self) -> Bool {
#| self is ('0'..='9' | 'A'..='F' | 'a'..='f')
#|}
#|pub fn Char::is_ascii_lowercase(self : Self) -> Bool {
#| self is ('a'..='z')
#|}
#|pub fn Char::is_ascii_octdigit(self : Self) -> Bool {
#| self is ('0'..='7')
#|}
#|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}')
#|}
#|pub fn Char::is_ascii_uppercase(self : Self) -> Bool {
#| self is ('A'..='Z')
#|}
#|pub fn Char::is_ascii_whitespace(self : Self) -> Bool {
#| self is ('\u{20}' | '\u{09}' | '\u{0A}' | '\u{0B}' | '\u{0C}' | '\u{0D}')
#|}
#|pub fn Char::is_control(self : Self) -> Bool {
#| self is ('\u0000'..='\u001F' | '\u007F'..='\u009F')
#|}
#|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()
#| }
#|}
#|pub fn Char::is_whitespace(self : Self) -> Bool {
#| self
#| is ('\u0009'..='\u000D'
#| | '\u0020'
#| | '\u0085'
#| | '\u00A0'
#| | '\u1680'
#| | '\u2000'..='\u200A'
#| | '\u2028'
#| | '\u2029'
#| | '\u202F'
#| | '\u205F'
#| | '\u3000')
#|}
#|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}')
#|}
#|pub fn Char::is_printable(self : Self) -> Bool {
#| if self.is_control() {
#| return false
#| }
#| let self = self.to_int()
#| if self is (0xE000..=0xF8FF | 0xF0000..=0xFFFFD | 0x100000..=0x10FFFD) {
#| return false
#| }
#| 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
#| }
#| if self.is_surrogate() {
#| return false
#| }
#| if self == '\u{2028}' || self == '\u{2029}' {
#| return false
#| }
#| 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
#|}
#|pub fn Char::to_ascii_lowercase(self : Self) -> Char {
#| if self.is_ascii_uppercase() {
#| return (self.to_int() + 32).unsafe_to_char()
#| }
#| self
#|}
#|pub fn Char::to_ascii_uppercase(self : Self) -> Char {
#| if self.is_ascii_lowercase() {
#| return (self.to_int() - 32).unsafe_to_char()
#| }
#| self
#|}
#|pub impl Show for Char with to_string(self : Char) -> String {
#| char_to_string(self)
#|}
#|#intrinsic("%char.to_string")
#|fn char_to_string(char : Char) -> String {
#| [char]
#|}
#|pub impl Show for Char with output(self, logger) {
#| fn to_hex_digit(i : Int) -> Char {
#| if i < 10 {
#| (i + '0').unsafe_to_char()
#| } else {
#| (i + 'a' - 10).unsafe_to_char()
#| }
#| }
#| logger.write_char('\'')
#| match self {
#| '\'' | '\\' => logger..write_char('\\')..write_char(self)
#| '\n' => logger.write_string("\\n")
#| '\r' => logger.write_string("\\r")
#| '\b' => logger.write_string("\\b")
#| '\t' => logger.write_string("\\t")
#| ' '..='~' => logger.write_char(self)
#| _ =>
#| if !self.is_printable() {
#| let code = self.to_int()
#| let hex_len = if code <= 0xFF {
#| 2
#| } else if code <= 0xFFF {
#| 3
#| } else if code <= 0xFFFF {
#| 4
#| } else if code <= 0xFFFFF {
#| 5
#| } else {
#| 6
#| }
#| logger.write_string("\\u{")
#| if hex_len >= 6 {
#| logger.write_char(to_hex_digit((code >> 20) & 0xF))
#| }
#| if hex_len >= 5 {
#| logger.write_char(to_hex_digit((code >> 16) & 0xF))
#| }
#| if hex_len >= 4 {
#| logger.write_char(to_hex_digit((code >> 12) & 0xF))
#| }
#| if hex_len >= 3 {
#| logger.write_char(to_hex_digit((code >> 8) & 0xF))
#| }
#| if hex_len >= 2 {
#| logger.write_char(to_hex_digit((code >> 4) & 0xF))
#| }
#| logger.write_char(to_hex_digit(code & 0xF))
#| logger.write_char('}')
#| } else {
#| logger.write_char(self)
#| }
#| }
#| logger.write_char('\'')
#|}
#|pub impl ToJson for Char with to_json(self : Char) -> Json {
#| Json::string(self.to_string())
#|}
#|pub fn Char::utf16_len(self : Self) -> Int {
#| let code = self.to_int()
#| if code <= 0xFFFF {
#| 1
#| } else {
#| 2
#| }
#|}
#|pub fn Char::is_bmp(self : Self) -> Bool {
#| self.to_int() <= 0xFFFF
#|}
),
},
)
///|
let moonbitlang_core_cmp_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/cmp",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin"
#| ],
#| "test-import": [
#| "moonbitlang/core/int"
#| ]
#|}
),
"cmp.mbt": (
#|pub fn[T, K : Compare] maximum_by_key(x : T, y : T, f : (T) -> K) -> T {
#| if f(x) > f(y) {
#| x
#| } else {
#| y
#| }
#|}
#|pub fn[T, K : Compare] minimum_by_key(x : T, y : T, f : (T) -> K) -> T {
#| if f(x) > f(y) {
#| y
#| } else {
#| x
#| }
#|}
#|pub fn[T : Compare] maximum(x : T, y : T) -> T {
#| if x > y {
#| x
#| } else {
#| y
#| }
#|}
#|pub fn[T : Compare] minimum(x : T, y : T) -> T {
#| if x > y {
#| y
#| } else {
#| x
#| }
#|}
),
},
)
///|
let moonbitlang_core_deque_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/json",
#| "moonbitlang/core/array",
#| "moonbitlang/core/string"
#| ],
#| "targets": {
#| "panic_test.mbt": ["not", "native", "llvm"]
#| }
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `unsafe_pop_front` instead")
#|#coverage.skip
#|pub fn[A] pop_front_exn(self : Deque[A]) -> Unit {
#| self.unsafe_pop_front()
#|}
#|#deprecated("Use `unsafe_pop_back` instead")
#|#coverage.skip
#|pub fn[A] pop_back_exn(self : Deque[A]) -> Unit {
#| self.unsafe_pop_back()
#|}
#|#deprecated("Use `@deque.retain_map` instead")
#|pub fn[A] filter_map_inplace(self : Deque[A], f : (A) -> A?) -> Unit {
#| self.retain_map(f)
#|}
),
"deque.mbt": (
#|fn[T] set_null(buffer : UninitializedArray[T], index : Int) = "%fixedarray.set_null"
#|pub fn[A] new(capacity? : Int = 0) -> Deque[A] {
#| Deque::{ buf: UninitializedArray::make(capacity), len: 0, head: 0, tail: 0 }
#|}
#|pub impl[A : Show] Show for Deque[A] with output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@deque.of([", suffix="])")
#|}
#|pub fn[A] from_array(arr : Array[A]) -> Deque[A] {
#| let deq = Deque::{
#| buf: UninitializedArray::make(arr.length()),
#| len: arr.length(),
#| head: 0,
#| tail: arr.length() - 1,
#| }
#| for i in 0.. Deque[A] {
#| let len = self.len
#| let deq = Deque::{
#| buf: UninitializedArray::make(len),
#| len,
#| head: 0,
#| tail: len - 1,
#| }
#| for i, x in self {
#| deq.buf[i] = x
#| }
#| deq
#|}
#|pub fn[A] append(self : Deque[A], other : Deque[A]) -> Unit {
#| guard other.len != 0 else { return }
#| let space = if self.buf.length() != 0 {
#| (self.head - self.tail - 1 + self.buf.length()) % self.buf.length()
#| } else {
#| 0
#| }
#| if space < other.len {
#| let new_cap = if self.len + other.len > self.buf.length() * 2 {
#| self.len + other.len
#| } else {
#| self.buf.length() * 2
#| }
#| let new_buf = UninitializedArray::make(new_cap)
#| for i, x in self {
#| new_buf[i] = x
#| }
#| self.buf = new_buf
#| self.head = 0
#| self.tail = self.len - 1
#| }
#| for _, y in other {
#| self.tail = (self.tail + 1) % self.buf.length()
#| self.buf[self.tail] = y
#| self.len += 1
#| }
#|}
#|pub fn[A] of(arr : FixedArray[A]) -> Deque[A] {
#| let deq = Deque::{
#| buf: UninitializedArray::make(arr.length()),
#| len: arr.length(),
#| head: 0,
#| tail: arr.length() - 1,
#| }
#| for i in 0.. Int {
#| self.len
#|}
#|pub fn[A] capacity(self : Deque[A]) -> Int {
#| self.buf.length()
#|}
#|fn[A] realloc(self : Deque[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])
#| }
#|}
#|pub fn[A] back(self : Deque[A]) -> A? {
#| if self.len == 0 {
#| None
#| } else {
#| Some(self.buf[self.tail])
#| }
#|}
#|pub fn[A] push_front(self : Deque[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
#|}
#|pub fn[A] push_back(self : Deque[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
#|}
#|#internal(unsafe, "Panic if the deque is empty.")
#|pub fn[A] unsafe_pop_front(self : Deque[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
#| }
#| }
#|}
#|#internal(unsafe, "Panic if the deque is empty.")
#|pub fn[A] unsafe_pop_back(self : Deque[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
#| }
#| }
#|}
#|pub fn[A] pop_front(self : Deque[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)
#| }
#| }
#|}
#|pub fn[A] pop_back(self : Deque[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)
#| }
#| }
#|}
#|pub fn[A] op_get(self : Deque[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()]
#| }
#|}
#|pub fn[A] op_set(self : Deque[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
#| }
#|}
#|pub fn[A] Deque::as_views(self : Deque[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])
#| }
#|}
#|pub impl[A : Eq] Eq for Deque[A] with equal(self, other) {
#| if self.len != other.len {
#| return false
#| }
#| for i in 0.. Unit) -> Unit {
#| for v in self {
#| f(v)
#| }
#|}
#|pub fn[A] eachi(self : Deque[A], f : (Int, A) -> Unit) -> Unit {
#| for i, v in self {
#| f(i, v)
#| }
#|}
#|pub fn[A] rev_each(self : Deque[A], f : (A) -> Unit) -> Unit {
#| for v in self.rev_iter() {
#| f(v)
#| }
#|}
#|pub fn[A] rev_eachi(self : Deque[A], f : (Int, A) -> Unit) -> Unit {
#| for i, v in self.rev_iter2() {
#| f(i, v)
#| }
#|}
#|pub fn[A] clear(self : Deque[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) -> Deque[U] {
#| if self.len == 0 {
#| new()
#| } else {
#| let buf : UninitializedArray[U] = UninitializedArray::make(self.len)
#| for i in 0.. U) -> Deque[U] {
#| if self.len == 0 {
#| new()
#| } else {
#| let buf : UninitializedArray[U] = UninitializedArray::make(self.len)
#| for i in 0.. Bool {
#| self.len == 0
#|}
#|pub fn[A : Eq] search(self : Deque[A], value : A) -> Int? {
#| for i in 0.. Bool {
#| self.iter().contains(value)
#|}
#|pub fn[A] reserve_capacity(self : Deque[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 = if len == 0 { 0 } else { len - 1 }
#| 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 = if len == 0 { 0 } else { len - 1 }
#| 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 {
#| 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)
#| }
#|}
#|pub fn[A] retain(self : Deque[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)
#| }
#|}
#|pub fn[A] iter(self : Deque[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
#| })
#|}
#|pub fn[A] rev_iter2(self : Deque[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
#| })
#|}
#|pub fn[A] from_iter(iter : Iter[A]) -> Deque[A] {
#| let dq = new()
#| iter.each(e => dq.push_back(e))
#| dq
#|}
#|pub fn[A] to_array(self : Deque[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)
#|}
#|pub impl[A : ToJson] ToJson for Deque[A] with to_json(self : Deque[A]) -> Json {
#| let res = Array::make(self.length(), null)
#| for i, x in self {
#| res[i] = x.to_json()
#| }
#| Json::array(res)
#|}
#|pub impl[A : @json.FromJson] @json.FromJson for Deque[A] with from_json(
#| json,
#| path,
#|) {
#| guard json is Array(arr) else {
#| raise @json.JsonDecodeError((path, "Deque::from_json: expected array"))
#| }
#| let len = arr.length()
#| let buf = UninitializedArray::make(len)
#| let head = 0
#| let tail = if len == 0 { 0 } else { len - 1 }
#| for i, x in arr {
#| buf[i] = @json.FromJson::from_json(x, path.add_index(i))
#| }
#| { len, buf, head, tail }
#|}
#|pub fn[A] Deque::flatten(self : Deque[Deque[A]]) -> Deque[A] {
#| let mut len = 0
#| for deque in self {
#| len += deque.length()
#| }
#| let target = Deque::{
#| 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
#|}
#|pub fn[A] Deque::drain(self : Deque[A], start~ : Int, len? : Int) -> Deque[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 = Deque::{
#| 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
#| 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
#|}
#|#locals(cmp)
#|pub fn[A] binary_search_by(
#| self : Deque[A],
#| cmp : (A) -> Int,
#|) -> Result[Int, Int] {
#| let len = self.len
#| for i = 0, j = len; i < j; {
#| let h = i + (j - i) / 2
#| let ord = cmp(self[h])
#| if ord < 0 {
#| continue h + 1, j
#| } else {
#| continue i, h
#| }
#| } else {
#| if i < len && cmp(self[i]) == 0 {
#| Ok(i)
#| } else {
#| Err(i)
#| }
#| }
#|}
#|pub fn[A] get(self : Deque[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
#| }
#|}
#|pub fn[A : Compare] binary_search(
#| self : Deque[A],
#| value : A,
#|) -> Result[Int, Int] {
#| self.binary_search_by(x => x.compare(value))
#|}
#|pub impl[A : Compare] Compare for Deque[A] with compare(self, other) {
#| let len_self = self.length()
#| let len_other = other.length()
#| let cmp = len_self.compare(len_other)
#| guard cmp is 0 else { return cmp }
#| for i in 0.. 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
#| }
#|}
#|pub fn[A] Deque::rev(self : Deque[A]) -> Deque[A] {
#| let len = self.len
#| let new_buf = UninitializedArray::make(len)
#| 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)
#| let i_pos = (self.head + i) % buf_length
#| let j_pos = (self.head + j) % buf_length
#| let tmp = self.buf[i_pos]
#| self.buf[i_pos] = self.buf[j_pos]
#| self.buf[j_pos] = tmp
#| }
#|}
#|pub fn[A] shuffle(self : Deque[A], rand~ : (Int) -> Int) -> Deque[A] {
#| let new_deque = self.copy()
#| new_deque.shuffle_in_place(rand~)
#| new_deque
#|}
),
"types.mbt": (
#|struct Deque[A] {
#| mut buf : UninitializedArray[A]
#| mut len : Int
#| mut head : Int
#| mut tail : Int
#|}
#|#deprecated("Use `Deque` instead of `T`")
#|pub typealias Deque as T
),
},
)
///|
let moonbitlang_core_double_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/int64",
#| "moonbitlang/core/uint64",
#| "moonbitlang/core/double/internal/ryu"
#| ],
#| "targets": {
#| "exp_js.mbt": ["js"],
#| "exp_nonjs.mbt": ["not", "js"],
#| "log_js.mbt": ["js"],
#| "log_nonjs.mbt": ["not", "js"],
#| "mod_js.mbt": ["js"],
#| "mod_nonjs.mbt": ["not", "js"],
#| "pow_js.mbt": ["js"],
#| "pow_nonjs.mbt": ["not", "js"],
#| "trig_js.mbt" : ["js"],
#| "trig_nonjs.mbt" : ["not", "js"],
#| "round_js.mbt": ["js"],
#| "round_wasm.mbt": ["wasm", "wasm-gc"],
#| "round.mbt": ["not", "js", "wasm", "wasm-gc"],
#| "to_uint_wasm.mbt": ["wasm", "wasm-gc"],
#| "to_uint.mbt": ["not", "wasm", "wasm-gc"],
#| "hyperbolic_js.mbt": ["js"],
#| "hyperbolic_nonjs.mbt": ["not", "js"],
#| "cbrt_js.mbt" : ["js"],
#| "cbrt_nonjs.mbt" : ["not", "js"],
#| "hypot_js.mbt" : ["js"],
#| "hypot_nonjs.mbt" : ["not", "js"],
#| "scalbn.mbt" : ["not", "js"]
#| }
#|}
),
"cbrt_js.mbt": (
#|#deprecated("use `@math.cbrt` instead")
#|#coverage.skip
#|pub fn Double::cbrt(self : Double) -> Double = "Math" "cbrt"
),
"cbrt_nonjs.mbt": (
#|#deprecated("use `@math.cbrt` instead")
#|#coverage.skip
#|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
#| }
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `@double.not_a_number` instead")
#|#coverage.skip
#|pub fn Double::nan() -> Double {
#| not_a_number
#|}
#|#deprecated("Use `@double.infinity` and `@double.neg_infinity` instead")
#|#coverage.skip
#|pub fn Double::inf(sign : Int) -> Double {
#| if sign >= 0 {
#| infinity
#| } else {
#| neg_infinity
#| }
#|}
#|#deprecated("Use `@double.min_positive` instead")
#|#coverage.skip
#|pub fn Double::min_normal() -> Double {
#| min_positive
#|}
),
"double.mbt": (
#|pub let not_a_number : Double = 0x7FF8000000000001L.reinterpret_as_double()
#|pub let infinity : Double = 0x7FF0000000000000L.reinterpret_as_double()
#|pub let neg_infinity : Double = 0xFFF0000000000000L.reinterpret_as_double()
#|pub let max_value : Double = 0x7FEFFFFFFFFFFFFFL.reinterpret_as_double()
#|pub let min_value : Double = 0xFFEFFFFFFFFFFFFFL.reinterpret_as_double()
#|pub let min_positive : Double = 0x0010000000000000L.reinterpret_as_double()
#|pub fn Double::from_int(i : Int) -> Double {
#| i.to_double()
#|}
#|pub fn from_int(i : Int) -> Double {
#| i.to_double()
#|}
#|pub fn Double::abs(self : Double) -> Double = "%f64.abs"
#|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
#| }
#|}
#|pub fn is_nan(self : Double) -> Bool {
#| self != self
#|}
#|pub fn is_inf(self : Double) -> Bool {
#| self > max_value || self < min_value
#|}
#|pub fn is_pos_inf(self : Double) -> Bool {
#| self > max_value
#|}
#|pub fn is_neg_inf(self : Double) -> Bool {
#| self < min_value
#|}
#|test "from_int" {
#| assert_eq(from_int(1), 1.0)
#| assert_eq(from_int(0), 0.0)
#| assert_eq(from_int(100000), 1.0e5)
#|}
#|test "abs" {
#| let d = -1.0
#| assert_eq(d.abs(), 1.0)
#| assert_eq(1.0.abs(), 1.0)
#|}
#|test "signum" {
#| let d = -2.0
#| assert_eq(d.signum(), -1.0)
#| assert_eq(1.0.signum(), 1.0)
#| assert_eq(0.0.signum(), 0.0)
#| assert_true(not_a_number.signum().is_nan())
#|}
#|test "is_nan" {
#| assert_true(not_a_number.is_nan())
#| assert_false(0.0.is_nan())
#| assert_false(12345.678.is_nan())
#| assert_false(infinity.is_nan())
#| assert_false(neg_infinity.is_nan())
#|}
#|test "is_inf" {
#| assert_true(infinity.is_inf())
#| assert_true(neg_infinity.is_inf())
#| assert_false(0.0.is_inf())
#| assert_false(12345.678.is_inf())
#|}
#|test "is_pos_inf" {
#| assert_true(infinity.is_pos_inf())
#| assert_false(neg_infinity.is_pos_inf())
#| assert_false(0.0.is_pos_inf())
#| assert_false(12345.678.is_pos_inf())
#|}
#|test "is_neg_inf" {
#| assert_false(infinity.is_neg_inf())
#| assert_true(neg_infinity.is_neg_inf())
#| assert_false(0.0.is_neg_inf())
#| assert_false(12345.678.is_neg_inf())
#|}
#|test "min equal to neg max" {
#| assert_true(min_value == -max_value)
#|}
#|pub impl Hash for Double with hash(self) {
#| self.reinterpret_as_int64() |> Hash::hash()
#|}
#|pub impl Hash for Double with hash_combine(self, hasher) {
#| hasher.combine_double(self)
#|}
#|#intrinsic("%f64.to_string")
#|pub fn to_string(self : Double) -> String {
#| @ryu.ryu_to_string(self)
#|}
#|pub impl Show for Double with output(self, logger) {
#| logger.write_string(self.to_string())
#|}
#|pub fn Double::is_close(
#| self : Self,
#| other : Self,
#| relative_tolerance? : Self = 1.0e-09,
#| absolute_tolerance? : Self = 0.0,
#|) -> Bool {
#| if relative_tolerance < 0.0 || absolute_tolerance < 0.0 {
#| abort("Tolerances must be non-negative")
#| }
#| if self == other {
#| return true
#| }
#| if self.is_inf() || other.is_inf() {
#| return false
#| }
#| let diff = (other - self).abs()
#| return (
#| diff <= (relative_tolerance * other).abs() ||
#| diff <= (relative_tolerance * self).abs()
#| ) ||
#| diff <= absolute_tolerance
#|}
#|pub fn to_be_bytes(self : Double) -> Bytes {
#| self.reinterpret_as_uint64().to_be_bytes()
#|}
#|pub fn to_le_bytes(self : Double) -> Bytes {
#| self.reinterpret_as_uint64().to_le_bytes()
#|}
),
"exp_js.mbt": (
#|#deprecated("use `Double::exp` instead")
#|#coverage.skip
#|pub fn Double::exp(self : Double) -> Double = "Math" "exp"
#|#deprecated("use `Double::expm1` instead")
#|#coverage.skip
#|pub fn Double::expm1(self : Double) -> Double = "Math" "expm1"
),
"exp_nonjs.mbt": (
#|#deprecated("use `@math.exp` instead")
#|#coverage.skip
#|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
#| }
#|}
#|#deprecated("use `@math.expm1` instead")
#|#coverage.skip
#|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
#|}
),
"hyperbolic_js.mbt": (
#|#deprecated("use `@math.sinh` instead")
#|#coverage.skip
#|pub fn Double::sinh(self : Double) -> Double = "Math" "sinh"
#|#deprecated("use `@math.cosh` instead")
#|#coverage.skip
#|pub fn Double::cosh(self : Double) -> Double = "Math" "cosh"
#|#deprecated("use `@math.tanh` instead")
#|#coverage.skip
#|pub fn Double::tanh(self : Double) -> Double = "Math" "tanh"
#|#deprecated("use `@math.asinh` instead")
#|#coverage.skip
#|pub fn Double::asinh(self : Double) -> Double = "Math" "asinh"
#|#deprecated("use `@math.acosh` instead")
#|#coverage.skip
#|pub fn Double::acosh(self : Double) -> Double = "Math" "acosh"
#|#deprecated("use `@math.atanh` instead")
#|#coverage.skip
#|pub fn Double::atanh(self : Double) -> Double = "Math" "atanh"
),
"hyperbolic_nonjs.mbt": (
#|#deprecated("use `@math.sinh` instead")
#|#coverage.skip
#|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 = Double::exp(0.5 * abs_x)
#| let t = h * w
#| return t * w
#| }
#| self * shuge
#|}
#|#deprecated("use `@math.cosh` instead")
#|#coverage.skip
#|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 = Double::exp(0.5 * self.abs())
#| let t = 0.5 * w
#| return t * w
#| }
#| infinity
#|}
#|#deprecated("use `@math.tanh` instead")
#|#coverage.skip
#|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
#| }
#|}
#|#deprecated("use `@math.asinh` instead")
#|#coverage.skip
#|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
#| }
#|}
#|#deprecated("use `@math.acosh` instead")
#|#coverage.skip
#|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()
#| }
#|}
#|#deprecated("use `@math.atanh` instead")
#|#coverage.skip
#|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
#| }
#|}
),
"hypot_js.mbt": (
#|#deprecated("use `@math.hypot` instead")
#|#coverage.skip
#|pub fn Double::hypot(self : Double, y : Double) -> Double = "Math" "hypot"
),
"hypot_nonjs.mbt": (
#|#deprecated("use `@math.hypot` instead")
#|#coverage.skip
#|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()
#|}
),
"log_js.mbt": (
#|#deprecated("use `@math.ln` instead")
#|#converage.skip
#|pub fn Double::ln(self : Double) -> Double = "Math" "log"
#|#deprecated("use `@math.log2` instead")
#|#converage.skip
#|pub fn Double::log2(self : Double) -> Double = "Math" "log2"
#|#deprecated("use `@math.log10` instead")
#|#converage.skip
#|pub fn Double::log10(self : Double) -> Double = "Math" "log10"
#|#deprecated("use `@math.ln_1p` instead")
#|#converage.skip
#|pub fn Double::ln_1p(self : Double) -> Double = "Math" "log1p"
),
"log_nonjs.mbt": (
#|let sqrt2 = 1.41421356237309504880168872420969807856967187537694807317667974
#|let ln2 = 0.693147180559945309417232121458176568075500134360255254120680009
#|let ln2_hi = 6.93147180369123816490e-01 // 3fe62e42 fee00000
#|let ln2_lo = 1.90821492927058770002e-10 // 3dea39ef 35793c76
#|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
#|fn normalize(f : Double) -> (Double, Int) {
#| if f.abs() < min_positive {
#| return (f * (1L << 52).to_double(), -52)
#| }
#| (f, 0)
#|}
#|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)
#|}
#|#deprecated("use `@math.ln` instead")
#|#coverage.skip
#|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)
#|}
#|#deprecated("use `@math.log2` instead")
#|#coverage.skip
#|pub fn Double::log2(self : Double) -> Double {
#| let (f, e) = frexp(self)
#| if f == 0.5 {
#| return e.to_double() - 1.0
#| }
#| Double::ln(f) / ln2 + e.to_double()
#|}
#|#deprecated("use `@math.log10` instead")
#|#coverage.skip
#|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
#|}
#|#deprecated("use `@math.ln_1p` instead")
#|#coverage.skip
#|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)
#| }
#|}
),
"math_functions.mbt": (
#|pub fnalias Double::(
#| sin,
#| cos,
#| tan,
#| asin,
#| acos,
#| atan,
#| atan2,
#| exp,
#| expm1,
#| pow,
#| ln,
#| log2,
#| log10,
#| ln_1p,
#| sinh,
#| cosh,
#| tanh,
#| asinh,
#| acosh,
#| atanh,
#| hypot,
#| cbrt,
#| is_close,
#| trunc,
#| floor,
#| ceil,
#| round,
#| abs
#|)
),
"mod_js.mbt": (
#|extern "js" fn mod_ffi(self : Double, other : Double) -> Double =
#| #| (a, b) => (a % b)
#|pub impl Mod for Double with mod(self, other) {
#| self.mod_ffi(other)
#|}
),
"mod_nonjs.mbt": (
#|pub impl Mod for Double with mod(self : Double, other : Double) -> Double {
#| let x = self
#| let y = other
#| let mut uint64_x = x.reinterpret_as_uint64()
#| let mut uint64_y = y.reinterpret_as_uint64()
#| let mut ex = ((uint64_x >> 52) & 0x7FF).to_int()
#| let mut ey = ((uint64_y >> 52) & 0x7FF).to_int()
#| let sign_x = uint64_x >> 63
#| let mut i : UInt64 = 0
#| if uint64_y << 1 == 0 || y.is_nan() || ex == 0x7ff {
#| return x * y / (x * y)
#| }
#| if uint64_x << 1 <= uint64_y << 1 {
#| if uint64_x << 1 == uint64_y << 1 {
#| return 0.0 * x
#| }
#| return x
#| }
#| if ex == 0 {
#| i = uint64_x << 12
#| while i >> 63 == 0 {
#| ex -= 1
#| i = i << 1
#| }
#| uint64_x = uint64_x << (-ex + 1)
#| } else {
#| uint64_x = uint64_x & (18446744073709551615UL >> 12)
#| uint64_x = uint64_x | (1UL << 52)
#| }
#| if ey == 0 {
#| i = uint64_y << 12
#| while i >> 63 == 0 {
#| ey -= 1
#| i = i << 1
#| }
#| uint64_y = uint64_y << (-ey + 1)
#| } else {
#| uint64_y = uint64_y & (18446744073709551615UL >> 12)
#| uint64_y = uint64_y | (1UL << 52)
#| }
#| while ex > ey {
#| i = uint64_x - uint64_y
#| if i >> 63 == 0 {
#| if i == 0 {
#| return 0.0 * x
#| }
#| uint64_x = i
#| }
#| uint64_x = uint64_x << 1
#| ex -= 1
#| }
#| i = uint64_x - uint64_y
#| if i >> 63 == 0 {
#| if i == 0 {
#| return 0.0 * x
#| }
#| uint64_x = i
#| }
#| while uint64_x >> 52 == 0 {
#| uint64_x = uint64_x << 1
#| ex -= 1
#| }
#| if ex > 0 {
#| uint64_x = uint64_x - (1UL << 52)
#| uint64_x = uint64_x | (ex.to_uint64() << 52)
#| } else {
#| uint64_x = uint64_x >> (-ex + 1)
#| }
#| uint64_x = uint64_x | (sign_x << 63)
#| uint64_x.reinterpret_as_double()
#|}
),
"pow_js.mbt": (
#|pub fn Double::pow(self : Double, other : Double) -> Double = "Math" "pow"
),
"pow_nonjs.mbt": (
#|let pow_bp : FixedArray[Double] = [1.0, 1.5]
#|let pow_dp_h : FixedArray[Double] = [0.0, 5.84962487220764160156e-01]
#|let pow_dp_l : FixedArray[Double] = [0.0, 1.35003920212974897128e-08]
#|const ZERO = 0.0
#|const ONE = 1.0
#|const TWO = 2.0
#|const POW_two53 = 9007199254740992.0
#|const POW_huge = 1.0e300
#|const POW_tiny = 1.0e-300
#|const POW_L1 = 5.99999999999994648725e-01
#|const POW_L2 = 4.28571428578550184252e-01
#|const POW_L3 = 3.33333329818377432918e-01
#|const POW_L4 = 2.72728123808534006489e-01
#|const POW_L5 = 2.30660745775561754067e-01
#|const POW_L6 = 2.06975017800338417784e-01
#|const POW_P1 = 1.66666666666666019037e-01
#|const POW_P2 = -2.77777777770155933842e-03
#|const POW_P3 = 6.61375632143793436117e-05
#|const POW_P4 = -1.65339022054652515390e-06
#|const POW_P5 = 4.13813679705723846039e-08
#|const POW_lg2 = 6.93147180559945286227e-01
#|const POW_lg2_h = 6.93147182464599609375e-01
#|const POW_lg2_l = -1.90465429995776804525e-09
#|const POW_ovt = 8.0085662595372944372e-0017
#|const POW_cp = 9.61796693925975554329e-01
#|const POW_cp_h = 9.61796700954437255859e-01
#|const POW_cp_l = -7.02846165095275826516e-09
#|const POW_ivln2 = 1.44269504088896338700e+00
#|const POW_ivln2_h = 1.44269502162933349609e+00
#|const POW_ivln2_l = 1.92596299112661746887e-08
#|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
#| 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
#| 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
#| 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 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
#| if (iy.reinterpret_as_uint() | ly) == 0 {
#| return ONE
#| }
#| if ix > 0x7FF00000 ||
#| (ix == 0x7FF00000 && lx != 0) ||
#| iy > 0x7FF00000 ||
#| (iy == 0x7FF00000 && ly != 0) {
#| return x + y
#| }
#| 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)
#| }
#| }
#| }
#| }
#| 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()
#| 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 {
#| z = not_a_number
#| } else if yisint == 1 {
#| z = -z // (x<0)**odd = -(|x|**odd)
#| }
#| }
#| return z
#| }
#| }
#| n = (hx >> 31) + 1
#| 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)
#| }
#| 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 }
#| }
#| }
#| 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
#| }
#| }
#| 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
#| if ix < 0x00100000 {
#| ax *= POW_two53
#| n -= 53
#| ix = get_high_word(ax).reinterpret_as_int()
#| }
#| n += (ix >> 20) - 0x3ff
#| j = ix & 0x000fffff
#| 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)
#| 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 = s_h * t_h
#| v = s_l * t_h + t_l * 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]
#| 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)
#| }
#| 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
#| }
#| }
#| 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
#|}
),
"round.mbt": (
#|let sign_mask : UInt64 = 0x8000_0000_0000_0000
#|let exp_bias = 1023
#|let exp_bits = 11
#|let frac_bits = 52
#|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()
#|}
#|pub fn Double::ceil(self : Double) -> Double {
#| let trunced = self.trunc()
#| if self > trunced {
#| return trunced + 1.0
#| } else {
#| return trunced
#| }
#|}
#|pub fn Double::floor(self : Double) -> Double {
#| let trunced = self.trunc()
#| if self < trunced {
#| return trunced - 1.0
#| } else {
#| return trunced
#| }
#|}
#|pub fn Double::round(self : Double) -> Double {
#| floor(self + 0.5)
#|}
),
"round_js.mbt": (
#|pub fn Double::trunc(self : Double) -> Double = "Math" "trunc"
#|pub fn Double::ceil(self : Double) -> Double = "Math" "ceil"
#|pub fn Double::floor(self : Double) -> Double = "Math" "floor"
#|pub fn Double::round(self : Double) -> Double = "Math" "round"
),
"round_wasm.mbt": (
#|pub fn Double::trunc(self : Double) -> Double = "(func (param $d f64) (result f64) (f64.trunc (local.get $d)))"
#|pub fn Double::ceil(self : Double) -> Double = "(func (param $d f64) (result f64) (f64.ceil (local.get $d)))"
#|pub fn Double::floor(self : Double) -> Double = "(func (param $d f64) (result f64) (f64.floor (local.get $d)))"
#|pub fn Double::round(self : Double) -> Double {
#| floor(self + 0.5)
#|}
),
"scalbn.mbt": (
#|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 {
#| 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()
#|}
),
"to_uint.mbt": (
#|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)
#| }
#|}
),
"to_uint_wasm.mbt": (
#|pub fn to_uint(self : Double) -> UInt = "%f64.to_u32_saturate"
),
"trig_js.mbt": (
#|#deprecated("use `@math.sin` instead")
#|#coverage.skip
#|pub fn Double::sin(self : Double) -> Double = "Math" "sin"
#|#deprecated("use `@math.cos` instead")
#|#coverage.skip
#|pub fn Double::cos(self : Double) -> Double = "Math" "cos"
#|#deprecated("use `@math.tan` instead")
#|#coverage.skip
#|pub fn Double::tan(self : Double) -> Double = "Math" "tan"
#|#deprecated("use `@math.asin` instead")
#|#coverage.skip
#|pub fn Double::asin(self : Double) -> Double = "Math" "asin"
#|#deprecated("use `@math.acos` instead")
#|#coverage.skip
#|pub fn Double::acos(self : Double) -> Double = "Math" "acos"
#|#deprecated("use `@math.atan` instead")
#|#coverage.skip
#|pub fn Double::atan(self : Double) -> Double = "Math" "atan"
#|#deprecated("use `@math.atan2` instead")
#|#coverage.skip
#|pub fn Double::atan2(self : Double, x : Double) -> Double = "Math" "atan2"
),
"trig_nonjs.mbt": (
#|let two_over_pi : FixedArray[Int] = [
#| 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041,
#| 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C,
#| 0xFE1DEB, 0x1CB129, 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
#| 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F,
#| 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D,
#| 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
#| 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 0x91615E, 0xE61B08,
#| 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9,
#| 0x60E27B, 0xC08C6B,
#|]
#|let pi_over_2 : FixedArray[Double] = [
#| 1.57079625129699707031e+00, // 0x3FF921FB, 0x40000000 */
#| 7.54978941586159635335e-08, // 0x3E74442D, 0x00000000 */
#| 5.39030252995776476554e-15, // 0x3CF84698, 0x80000000 */
#| 3.28200341580791294123e-22, // 0x3B78CC51, 0x60000000 */
#| 1.27065575308067607349e-29, // 0x39F01B83, 0x80000000 */
#| 1.22933308981111328932e-36, // 0x387A2520, 0x40000000 */
#| 2.73370053816464559624e-44, // 0x36E38222, 0x80000000 */
#| 2.16741683877804819444e-51, // 0x3569F31D, 0x00000000 */
#|]
#|let npio2_hw : FixedArray[Int] = [
#| 0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C, 0x4025FDBB,
#| 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C, 0x40346B9C, 0x4035FDBB,
#| 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A, 0x403DD85A, 0x403F6A7A, 0x40407E4C,
#| 0x4041475C, 0x4042106C, 0x4042D97C, 0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB,
#| 0x4046C6CB, 0x40478FDB, 0x404858EB, 0x404921FB,
#|]
#|const PI_OVER_4 : Double = 0.785398163397448309616
#|const PIO2_1 : Double = 1.5707963267341256e+00 // 0x3FF921FB, 0x54400000 */
#|const PIO2_1T : Double = 6.0771005065061922e-11 // 0x3DD0B461, 0x1A600000 */
#|const PIO2_2 : Double = 6.0771005063039660e-11 // 0x3DD0B461, 0x1A600000 */
#|const PIO2_2T : Double = 2.0222662487959506e-21 // 0x3BA3198A, 0x2E037073 */
#|const PIO2_3 : Double = 2.0222662487111665e-21 // 0x3BA3198A, 0x2E037073 */
#|const PIO2_3T : Double = 8.4784276603688996e-32 // 0x397B839A, 0x252049C1 */
#|const INV_PIO2 : Double = 6.3661977236758138e-01 // 0x3FE45F30, 0x6DC9C883 */
#|const HALF : Double = 0.5
#|const TWO24 : Double = 16777216.0 // 0x41700000, 0x00000000 */
#|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()
#|}
#|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 {
#| y[0] = x
#| y[1] = 0.0
#| return 0
#| }
#| if ix < 0x4002d97c {
#| if hx > 0 {
#| z = x - PIO2_1
#| if ix != 0x3ff921fb {
#| y[0] = z - PIO2_1T
#| y[1] = z - y[0] - PIO2_1T
#| } else {
#| z = z - PIO2_2
#| y[0] = z - PIO2_2T
#| y[1] = z - y[0] - PIO2_2T
#| }
#| return 1
#| } else {
#| z = x + PIO2_1
#| if ix != 0x3ff921fb {
#| y[0] = z + PIO2_1T
#| y[1] = z - y[0] + PIO2_1T
#| } else {
#| let z = z + PIO2_2
#| y[0] = z + PIO2_2T
#| y[1] = z - y[0] + PIO2_2T
#| }
#| return -1
#| }
#| }
#| if ix <= 0x413921fb {
#| 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 {
#| 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 {
#| 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
#| }
#| }
#| if ix >= 0x7ff00000 {
#| y[0] = x - x
#| y[1] = y[0]
#| return 0
#| }
#| 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
#| }
#|}
#|fn __kernel_rem_pio2(
#| x : Array[Double],
#| y : Array[Double],
#| e0 : Int,
#| nx : Int,
#| prec : Int,
#|) -> Int {
#| let init_jk = [2, 3, 4, 6]
#| let two24 : Double = 16777216.0 // 0x41700000, 0x00000000
#| let twon24 : Double = 5.96046447753906250000e-08 // 0x3E700000, 0x00000000
#| let mut jz : Int = 0
#| let mut jx : Int = 0
#| let mut jv : Int = 0
#| let mut jp : Int = 0
#| let mut jk : Int = 0
#| let mut carry : Int = 0
#| let mut n : Int = 0
#| let iq : Array[Int] = Array::make(20, 0)
#| let mut i : Int = 0
#| let mut j : Int = 0
#| let mut k : Int = 0
#| let mut m : Int = 0
#| let mut q0 : Int = 0
#| let mut ih : Int = 0
#| let mut z : Double = 0
#| let mut fw : Double = 0
#| let f : Array[Double] = Array::make(20, 0.0)
#| let fq : Array[Double] = Array::make(20, 0.0)
#| let q : Array[Double] = Array::make(20, 0.0)
#| jk = init_jk[prec]
#| jp = jk
#| jx = nx - 1
#| jv = (e0 - 3) / 24
#| if jv < 0 {
#| jv = 0
#| }
#| q0 = e0 - 24 * (jv + 1)
#| j = jv - jx
#| m = jx + jk
#| i = 0
#| while i <= m {
#| f[i] = if j < 0 { 0.0 } else { two_over_pi[j].to_double() }
#| i += 1
#| j += 1
#| }
#| i = 0
#| while i <= jk {
#| j = 0
#| fw = 0.0
#| while j <= jx {
#| fw += x[j] * f[jx + i - j]
#| j += 1
#| }
#| q[i] = fw
#| i += 1
#| }
#| jz = jk
#| let mut recompute = true
#| while recompute {
#| recompute = false
#| i = 0
#| j = jz
#| z = q[jz]
#| while j > 0 {
#| fw = (twon24 * z).floor()
#| iq[i] = (z - two24 * fw).to_int()
#| z = q[j - 1] + fw
#| i += 1
#| j -= 1
#| }
#| z = scalbn(z, q0) // actual value of z
#| z -= 8.0 * (z * 0.125).floor() // trim off integer >= 8
#| n = z.to_int()
#| z -= n.to_double()
#| ih = 0
#| if q0 > 0 {
#| i = iq[jz - 1] >> (24 - q0)
#| n += i
#| iq[jz - 1] -= i << (24 - q0)
#| ih = iq[jz - 1] >> (23 - q0)
#| } else if q0 == 0 {
#| ih = iq[jz - 1] >> 23
#| } else if z >= 0.5 {
#| ih = 2
#| }
#| if ih > 0 {
#| n += 1
#| carry = 0
#| i = 0
#| while i < jz {
#| j = iq[i]
#| if carry == 0 {
#| if j != 0 {
#| carry = 1
#| iq[i] = 0x1000000 - j
#| }
#| } else {
#| iq[i] = 0xffffff - j
#| }
#| i += 1
#| }
#| if q0 > 0 {
#| match q0 {
#| 1 => iq[jz - 1] = iq[jz - 1] & 0x7fffff
#| 2 => iq[jz - 1] = iq[jz - 1] & 0x3fffff
#| _ => ()
#| }
#| }
#| if ih == 2 {
#| z = 1.0 - z
#| if carry != 0 {
#| z -= scalbn(1.0, q0)
#| }
#| }
#| }
#| if z == 0.0 {
#| j = 0
#| i = jz - 1
#| while i >= jk {
#| j = j | iq[i]
#| i -= 1
#| }
#| if j == 0 {
#| k = 1
#| while iq[jk - k] == 0 {
#| k += 1
#| }
#| i = jz + 1
#| while i <= jz + k {
#| f[jx + i] = two_over_pi[jv + i].to_double()
#| j = 0
#| fw = 0.0
#| while j <= jx {
#| fw += x[j] * f[jx + i - j]
#| j += 1
#| }
#| q[i] = fw
#| i += 1
#| }
#| jz += k
#| recompute = true // Continue to recompute
#| continue
#| }
#| } // Skip the rest of the loop and recompute
#| if z == 0.0 {
#| jz -= 1
#| q0 -= 24
#| while iq[jz] == 0 {
#| jz -= 1
#| q0 -= 24
#| }
#| } else {
#| z = scalbn(z, -q0)
#| if z >= two24 {
#| fw = (twon24 * z).floor()
#| iq[jz] = (z - two24 * fw).to_int()
#| jz += 1
#| q0 += 24
#| iq[jz] = fw.to_int()
#| } else {
#| iq[jz] = z.to_int()
#| }
#| }
#| fw = scalbn(1.0, q0)
#| i = jz
#| while i >= 0 {
#| q[i] = fw * iq[i].to_double()
#| fw *= twon24
#| i -= 1
#| }
#| i = jz
#| while i >= 0 {
#| fw = 0.0
#| k = 0
#| while k <= jp && k <= jz - i {
#| fw += pi_over_2[k] * q[i + k]
#| k += 1
#| }
#| fq[jz - i] = fw
#| i -= 1
#| }
#| match prec {
#| 0 => {
#| fw = 0.0
#| i = jz
#| while i >= 0 {
#| fw += fq[i]
#| i -= 1
#| }
#| y[0] = if ih == 0 { fw } else { -fw }
#| }
#| 1 | 2 => {
#| fw = 0.0
#| i = jz
#| while i >= 0 {
#| fw += fq[i]
#| i -= 1
#| }
#| y[0] = if ih == 0 { fw } else { -fw }
#| fw = fq[0] - fw
#| i = 1
#| while i <= jz {
#| fw += fq[i]
#| i += 1
#| }
#| y[1] = if ih == 0 { fw } else { -fw }
#| }
#| 3 => {
#| i = jz
#| while i > 0 {
#| fw = fq[i - 1] + fq[i]
#| fq[i] += fq[i - 1] - fw
#| fq[i - 1] = fw
#| i -= 1
#| }
#| i = jz
#| while i > 1 {
#| fw = fq[i - 1] + fq[i]
#| fq[i] += fq[i - 1] - fw
#| fq[i - 1] = fw
#| i -= 1
#| }
#| fw = 0.0
#| i = jz
#| while i >= 2 {
#| fw += fq[i]
#| i -= 1
#| }
#| if ih == 0 {
#| y[0] = fq[0]
#| y[1] = fq[1]
#| y[2] = fw
#| } else {
#| y[0] = -fq[0]
#| y[1] = -fq[1]
#| y[2] = -fw
#| }
#| }
#| _ => ()
#| }
#| }
#| n & 7
#|}
#|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)
#| }
#|}
#|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))
#| }
#|}
#|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)
#| }
#|}
#|#deprecated("use `@math.sin` instead")
#|#coverage.skip
#|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])
#| }
#| }
#|}
#|#deprecated("use `@math.cos` instead")
#|#coverage.skip
#|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)
#| }
#| }
#|}
#|#deprecated("use `@math.tan` instead")
#|#coverage.skip
#|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))
#| }
#|}
#|#deprecated("use `@math.asin` instead")
#|#coverage.skip
#|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 }
#| }
#|}
#|#deprecated("use `@math.acos` instead")
#|#coverage.skip
#|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)
#| }
#|}
#|#deprecated("use `@math.atan` instead")
#|#coverage.skip
#|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
#| }
#| }
#|}
#|#deprecated("use `@math.atan2` instead")
#|#coverage.skip
#|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
#| }
#|}
),
},
)
///|
let moonbitlang_core_double_internal_ryu_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/double/internal/ryu",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/bool": moonbitlang_core_bool_module,
},
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin", "moonbitlang/core/bool"]
#|}
),
"common.mbt": (
#|fn pow5bits(e : Int) -> Int {
#| ((e * 1217359).reinterpret_as_uint() >> 19).reinterpret_as_int() + 1
#|}
#|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"
#|}
#|fn log10Pow5(e : Int) -> Int {
#| ((e * 732923).reinterpret_as_uint() >> 20).reinterpret_as_int()
#|}
#|fn log10Pow2(e : Int) -> Int {
#| ((e * 78913).reinterpret_as_uint() >> 18).reinterpret_as_int()
#|}
),
"ryu.mbt": (
#|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)
#|}
#|fn shiftright128(lo : UInt64, hi : UInt64, dist : Int) -> UInt64 {
#| (hi << (64 - dist)) | (lo >> dist)
#|}
#|fn pow5Factor(value : UInt64) -> Int {
#| 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}")
#|}
#|fn multipleOfPowerOf5(value : UInt64, p : Int) -> Bool {
#| pow5Factor(value) >= p
#|}
#|fn multipleOfPowerOf2(value : UInt64, p : Int) -> Bool {
#| (value & ((1UL << p) - 1UL)) == 0UL
#|}
#|fn mulShiftAll64(
#| m : UInt64,
#| mul : (UInt64, UInt64),
#| j : Int,
#| mmShift : Bool,
#|) -> (UInt64, UInt64, UInt64) {
#| let m = m << 1
#| let (lo, tmp) = umul128(m, mul.0)
#| let (lo2, hi2) = umul128(m, mul.1)
#| let mid = tmp + lo2
#| let hi = hi2 + (if mid < tmp { 1 } else { 0 })
#| let lo2 = lo + mul.0
#| let mid2 = mid + mul.1 + (if lo2 < lo { 1 } else { 0 })
#| let hi2 = hi + (if mid2 < mid { 1 } else { 0 })
#| let vp = shiftright128(mid2, hi2, j - 64 - 1)
#| let mut vm : UInt64 = 0UL
#| if mmShift {
#| let lo3 = lo - mul.0
#| let mid3 = mid - mul.1 - (if lo < lo3 { 1 } else { 0 })
#| let hi3 = hi - (if mid < mid3 { 1 } else { 0 })
#| vm = shiftright128(mid3, hi3, j - 64 - 1)
#| } else {
#| let lo3 : UInt64 = lo + lo
#| let mid3 : UInt64 = mid + mid + (if lo3 < lo { 1 } else { 0 })
#| let hi3 : UInt64 = hi + hi + (if mid3 < mid { 1 } else { 0 })
#| let lo4 : UInt64 = lo3 - mul.0
#| let mid4 : UInt64 = mid3 - mul.1 - (if lo3 < lo4 { 1 } else { 0 })
#| let hi4 : UInt64 = hi3 - (if mid3 < mid4 { 1 } else { 0 })
#| vm = shiftright128(mid4, hi4, j - 64)
#| }
#| let vr = shiftright128(mid, hi, j - 64 - 1)
#| (vr, vp, vm)
#|}
#|let gPOW5_TABLE_SIZE = 26
#|let gDOUBLE_POW5_INV_SPLIT2 : FixedArray[UInt64] = [
#| 1, 2305843009213693952, 5955668970331000884, 1784059615882449851, 8982663654677661702,
#| 1380349269358112757, 7286864317269821294, 2135987035920910082, 7005857020398200553,
#| 1652639921975621497, 17965325103354776697, 1278668206209430417, 8928596168509315048,
#| 1978643211784836272, 10075671573058298858, 1530901034580419511, 597001226353042382,
#| 1184477304306571148, 1527430471115325346, 1832889850782397517, 12533209867169019542,
#| 1418129833677084982, 5577825024675947042, 2194449627517475473, 11006974540203867551,
#| 1697873161311732311, 10313493231639821582, 1313665730009899186, 12701016819766672773,
#| 2032799256770390445,
#|]
#|let gPOW5_INV_OFFSETS : FixedArray[UInt] = [
#| 0x54544554, 0x04055545, 0x10041000, 0x00400414, 0x40010000, 0x41155555, 0x00000454,
#| 0x00010044, 0x40000000, 0x44000041, 0x50454450, 0x55550054, 0x51655554, 0x40004000,
#| 0x01000001, 0x00010500, 0x51515411, 0x05555554, 0x00000000,
#|]
#|let gDOUBLE_POW5_SPLIT2 : FixedArray[UInt64] = [
#| 0, 1152921504606846976, 0, 1490116119384765625, 1032610780636961552, 1925929944387235853,
#| 7910200175544436838, 1244603055572228341, 16941905809032713930, 1608611746708759036,
#| 13024893955298202172, 2079081953128979843, 6607496772837067824, 1343575221513417750,
#| 17332926989895652603, 1736530273035216783, 13037379183483547984, 2244412773384604712,
#| 1605989338741628675, 1450417759929778918, 9630225068416591280, 1874621017369538693,
#| 665883850346957067, 1211445438634777304, 14931890668723713708, 1565756531257009982,
#|]
#|let gPOW5_OFFSETS : FixedArray[UInt] = [
#| 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40000000, 0x59695995, 0x55545555,
#| 0x56555515, 0x41150504, 0x40555410, 0x44555145, 0x44504540, 0x45555550, 0x40004000,
#| 0x96440440, 0x55565565, 0x54454045, 0x40154151, 0x55559155, 0x51405555, 0x00000105,
#|]
#|let gDOUBLE_POW5_TABLE : FixedArray[UInt64] = [
#| 1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625,
#| 1220703125, 6103515625, 30517578125, 152587890625, 762939453125, 3814697265625,
#| 19073486328125, 95367431640625, 476837158203125, 2384185791015625, 11920928955078125,
#| 59604644775390625, 298023223876953125,
#|]
#|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)
#|}
#|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)
#|}
#|let gDOUBLE_MANTISSA_BITS : Int = 52
#|let gDOUBLE_EXPONENT_BITS : Int = 11
#|let gDOUBLE_BIAS : Int = 1023
#|let gDOUBLE_POW5_INV_BITCOUNT : Int = 125
#|let gDOUBLE_POW5_BITCOUNT : Int = 125
#|fn decimal_length17(v : UInt64) -> Int {
#| 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
#|}
#|priv struct FloatingDecimal64 {
#| mantissa : UInt64
#| exponent : Int
#|}
#|fn d2d(ieeeMantissa : UInt64, ieeeExponent : UInt) -> FloatingDecimal64 {
#| let mut e2 : Int = 0
#| let mut m2 : UInt64 = 0
#| if ieeeExponent == 0 {
#| e2 = 1 - gDOUBLE_BIAS - gDOUBLE_MANTISSA_BITS - 2
#| m2 = ieeeMantissa
#| } else {
#| 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 *
#| m2
#| let mmShift = ieeeMantissa != 0UL || ieeeExponent <= 1
#| 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 {
#| 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 {
#| let mvMod5 : Int = mv.to_int() - 5 * (mv / 5UL).to_int()
#| if mvMod5 == 0 {
#| vrIsTrailingZeros = multipleOfPowerOf5(mv, q)
#| } else if even {
#| vmIsTrailingZeros = multipleOfPowerOf5(
#| mv - 1UL - mmShift.to_uint64(),
#| q,
#| )
#| } else {
#| vp = vp - multipleOfPowerOf5(mv + 2UL, q).to_uint64()
#| }
#| }
#| } else {
#| 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 {
#| vrIsTrailingZeros = true
#| if even {
#| vmIsTrailingZeros = mmShift.to_int() == 1
#| } else {
#| vp = vp - 1
#| }
#| } else if q < 63 {
#| vrIsTrailingZeros = multipleOfPowerOf2(mv, q)
#| }
#| }
#| let mut removed : Int = 0
#| let mut lastRemovedDigit : Int = 0
#| let mut output : UInt64 = 0UL
#| if vmIsTrailingZeros || vrIsTrailingZeros {
#| 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 {
#| 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
#| }
#| 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
#|}
#|fn to_chars(v : FloatingDecimal64, sign : Bool) -> String {
#| 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 {
#| for i in 0..<(olength - 1) {
#| let c = output % 10
#| output /= 10
#| 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 {
#| index -= 1
#| }
#| index += olength + 1
#| 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 {
#| if exp < 0 {
#| 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 {
#| for i in 0.. FloatingDecimal64? {
#| let m2 : UInt64 = (1UL << gDOUBLE_MANTISSA_BITS) | ieeeMantissa
#| let e2 : Int = ieeeExponent - gDOUBLE_BIAS - gDOUBLE_MANTISSA_BITS
#| if e2 > 0 {
#| return None
#| }
#| if e2 < -52 {
#| return None
#| }
#| let mask : UInt64 = (1UL << -e2) - 1UL
#| let fraction : UInt64 = m2 & mask
#| if fraction != 0UL {
#| return None
#| }
#| Some({ mantissa: m2 >> -e2, exponent: 0 })
#|}
#|pub fn ryu_to_string(val : Double) -> String {
#| if val == 0.0 {
#| return "0"
#| }
#| let bits : UInt64 = val.reinterpret_as_uint64()
#| 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)
#|}
#|test "double/ryu.mbt:205" {
#| let m = 123456789UL
#| let mul0 = 987654321UL
#| let (_, high0) = umul128(m, mul0)
#| let low1 = 111111111UL
#| let high1 = 222222222UL
#| let sum = high0 + low1
#| let mut high1 = high1
#| if sum < high0 {
#| high1 = high1 + 1
#| }
#| inspect(high1, content="222222222")
#|}
#|test "double/ryu.mbt:230" {
#| let m = 123456789UL
#| let mul0 = 987654321UL
#| let (_, high0) = umul128(m, mul0)
#| let low1 = 111111111UL
#| let high1 = 222222222UL
#| let sum = high0 + low1
#| let mut high1 = high1
#| if sum < high0 {
#| high1 = high1 + 1UL
#| }
#| assert_eq(high1, 222222222UL)
#|}
#|test "double/ryu.mbt:252" {
#| inspect(gDOUBLE_POW5_BITCOUNT, content="125")
#|}
#|test "double/ryu.mbt:205" {
#| let m = 123456789UL
#| let mul0 = 987654321UL
#| let (_, high0) = umul128(m, mul0)
#| let low1 = 111111111UL
#| let high1 = 222222222UL
#| let sum = high0 + low1
#| let mut high1 = high1
#| if sum < high0 {
#| high1 = high1 + 1UL
#| }
#| assert_eq(high1, 222222222UL)
#|}
#|test "double/ryu.mbt:230" {
#| let m = 123456789UL
#| let mul0 = 987654321UL
#| let (_, high0) = umul128(m, mul0)
#| let low1 = 111111111UL
#| let high1 = 222222222UL
#| let sum = high0 + low1
#| let mut high1 = high1
#| if sum < high0 {
#| high1 = high1 + 1UL
#| }
#| assert_eq(high1, 222222222UL)
#|}
#|test "double/ryu.mbt:252" {
#| inspect(gDOUBLE_POW5_BITCOUNT, content="125")
#|}
),
},
)
///|
let moonbitlang_core_env_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/env",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin"
#| ],
#| "test-import": [
#| "moonbitlang/core/option"
#| ],
#| "targets": {
#| "env_wasm.mbt": ["wasm", "wasm-gc"],
#| "env_js.mbt": ["js"],
#| "env_native.mbt": ["native", "llvm"]
#| }
#|}
),
"env.mbt": (
#|pub fn args() -> Array[String] {
#| get_cli_args_internal()
#|}
#|pub fn now() -> UInt64 {
#| now_internal()
#|}
#|pub fn current_dir() -> String? {
#| current_dir_internal()
#|}
),
"env_js.mbt": (
#|extern "js" fn get_cli_args_internal() -> Array[String] =
#| #| function() {
#| #| if (typeof process !== "undefined" && typeof process.argv !== "undefined") {
#| #| return process.argv;
#| #| } else {
#| #| return [];
#| #| }
#| #| }
#|extern "js" fn now_internal() -> UInt64 =
#| #| function() {
#| #| const nowMs = Date.now();
#| #| return ({ hi : Number(BigInt(nowMs) >> 32n), lo : nowMs & 0xFFFFFFFF });
#| #| }
#|extern "js" fn current_dir_internal() -> String? =
#| #| function() {
#| #| if (typeof process !== "undefined" && typeof process.cwd === "function") {
#| #| return process.cwd();
#| #| } else {
#| #| return null;
#| #| }
#| #| }
),
"env_native.mbt": (
#|fn get_cli_args_ffi() -> FixedArray[Bytes] = "$moonbit.get_cli_args"
#|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()
#| 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()
#|}
#|extern "c" fn time(ptr : Int) -> UInt64 = "time"
#|fn now_internal() -> UInt64 {
#| time(0) * 1000
#|}
#|#borrow(ptr)
#|extern "c" fn getcwd(ptr : Bytes, size : Int) -> Int = "getcwd"
#|fn current_dir_internal() -> String? {
#| let buf = Bytes::new(4096)
#| let res = getcwd(buf, buf.length())
#| if res == 0 {
#| None
#| } else {
#| Some(utf8_bytes_to_mbt_string(buf))
#| }
#|}
),
"env_wasm.mbt": (
#|#external
#|priv type XStringReadHandle
#|#external
#|priv type XExternString
#|fn begin_read_string(s : XExternString) -> XStringReadHandle = "__moonbit_fs_unstable" "begin_read_string"
#|fn string_read_char(handle : XStringReadHandle) -> Int = "__moonbit_fs_unstable" "string_read_char"
#|fn finish_read_string(handle : XStringReadHandle) = "__moonbit_fs_unstable" "finish_read_string"
#|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()
#|}
#|#external
#|priv type XStringArrayReadHandle
#|#external
#|priv type XExternStringArray
#|fn begin_read_string_array(sa : XExternStringArray) -> XStringArrayReadHandle = "__moonbit_fs_unstable" "begin_read_string_array"
#|fn string_array_read_string(handle : XStringArrayReadHandle) -> XExternString = "__moonbit_fs_unstable" "string_array_read_string"
#|fn finish_read_string_array(handle : XStringArrayReadHandle) = "__moonbit_fs_unstable" "finish_read_string_array"
#|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)
#| if str == "ffi_end_of_/string_array" {
#| break
#| } else {
#| buf.push(str)
#| }
#| }
#| finish_read_string_array(handle)
#| buf
#|}
#|fn get_cli_args_internal() -> Array[String] {
#| let args = get_cli_args_ffi()
#| string_array_from_extern(args)
#|}
#|fn get_cli_args_ffi() -> XExternStringArray = "__moonbit_fs_unstable" "args_get"
#|fn now_internal() -> UInt64 = "__moonbit_time_unstable" "now"
#|fn current_dir_internal() -> String? {
#| let dir = current_dir_ffi()
#| let dir = string_from_extern(dir)
#| if dir == "" {
#| None
#| } else {
#| Some(dir)
#| }
#|}
#|fn current_dir_ffi() -> XExternString = "__moonbit_fs_unstable" "current_dir"
),
},
)
///|
let moonbitlang_core_error_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/error",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin"],
#| "test-import": [
#| "moonbitlang/core/json"
#| ]
#|}
),
"error.mbt": (
#|fn Error::to_string(self : Error) -> String = "%error.to_string"
#|pub impl Show for Error with output(self, logger) {
#| logger.write_string(self.to_string())
#|}
#|fn Error::to_json(self : Error) -> Json = "%error.to_json"
#|pub impl ToJson for Error with to_json(self) {
#| self.to_json()
#|}
),
},
)
///|
let moonbitlang_core_float_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin", "moonbitlang/core/double", "moonbitlang/core/uint"],
#| "targets": {
#| "round_js.mbt": ["js"],
#| "round_wasm.mbt": ["wasm", "wasm-gc"],
#| "round.mbt": ["not", "js", "wasm", "wasm-gc"],
#| "to_int.mbt": ["not", "wasm", "wasm-gc"],
#| "to_int_wasm.mbt": ["wasm", "wasm-gc"]
#| }
#|}
),
"deprecated.mbt": (
#|#deprecated("use `@math.cbtrf` instead")
#|#coverage.skip
#|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 {
#| return self + self
#| }
#| if hx < 0x00800000 {
#| 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
#| 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)
#| let r = t * t * t
#| let t = t * (dx + dx + r) / (dx + r + r)
#| t.to_float()
#|}
#|#deprecated("use `@math.hypotf` instead")
#|#coverage.skip
#|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()
#|}
#|#deprecated("use `@math.expf` instead")
#|#coverage.skip
#|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()
#|}
#|#deprecated("use `@math.expm1f` instead")
#|#coverage.skip
#|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
#| if hx >= 0x4195b844 {
#| if hx > 0x7f800000 {
#| 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
#| if hx > 0x3eb17218 {
#| if hx < 0x3F851592 {
#| 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 {
#| return x
#| } else {
#| k = 0
#| }
#| 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 {
#| return x - (x * e - hxs)
#| }
#| e = x * (e - c) - c
#| e -= hxs
#| 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)) {
#| 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
#| }
#|}
#|#deprecated("use `@math.sinh` instead")
#|#coverage.skip
#|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
#| }
#| ix = ix & 0x7fffffff
#| let absx = ix.reinterpret_as_float()
#| let w = ix
#| 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))
#| }
#| h * k_expo2f(absx) * 2.0
#|}
#|#deprecated("use `@math.cosh` instead")
#|#coverage.skip
#|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
#| 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))
#| }
#| if w < 0x42b17217 {
#| let t = x.exp()
#| return (t + (1.0 : Float) / t) * 0.5
#| }
#| k_expo2f(x)
#|}
#|#deprecated("use `@math.tanh` instead")
#|#coverage.skip
#|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 {
#| if w > 0x41200000 {
#| (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 {
#| let t = (x * 2.0).expm1()
#| t / (t + 2.0)
#| } else if w >= 0x00800000 {
#| let t = (x * -2.0).expm1()
#| -t / (t + 2.0)
#| } else {
#| x
#| }
#| if sign {
#| -tt
#| } else {
#| tt
#| }
#|}
#|#deprecated("use `@math.asinh` instead")
#|#coverage.skip
#|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.ln() + ln2
#| } else if i >= 0x3f800000U + (1U << 23) {
#| (x * 2.0 + (1.0 : Float) / ((x * x + 1.0).sqrt() + x)).ln()
#| } else if i >= 0x3f800000U - (12U << 23) {
#| (x + x * x / ((x * x + 1.0).sqrt() + 1.0)).ln_1p()
#| } else {
#| x
#| }
#| if sign {
#| -x
#| } else {
#| x
#| }
#|}
#|#deprecated("use `@math.acosh` instead")
#|#coverage.skip
#|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) {
#| return (x - 1.0 + ((x - 1.0) * (x - 1.0) + (2.0 : Float) * (x - 1.0)).sqrt()).ln_1p()
#| }
#| if a < 0x3f800000U + (12U << 23) {
#| return (x * 2.0 - (1.0 : Float) / (x + (x * x - 1.0).sqrt())).ln()
#| }
#| return x.ln() + ln2
#|}
#|#deprecated("use `@math.atanh` instead")
#|#coverage.skip
#|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 * 2.0 + x * 2.0 * x / ((1.0 : Float) - x)).ln_1p() * 0.5
#| }
#| } else {
#| (x / ((1.0 : Float) - x) * 2.0).ln_1p() * 0.5
#| }
#| if sign {
#| -x
#| } else {
#| x
#| }
#|}
#|#deprecated("use `@math.lnf` instead")
#|#coverage.skip
#|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()
#|}
#|#deprecated("use `@math.ln_1pf` instead")
#|#coverage.skip
#|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
#|}
#|#deprecated("use `@math.sinf` instead")
#|#coverage.skip
#|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)
#|}
#|#deprecated("use `@math.cosf` instead")
#|#coverage.skip
#|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)
#|}
#|#deprecated("use `@math.tanf` instead")
#|#coverage.skip
#|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)
#|}
#|#deprecated("use `@math.asinf` instead")
#|#coverage.skip
#|pub fn Float::asin(self : Float) -> Float {
#| let x = self
#| let x1p120 = 0x3870000000000000UL.reinterpret_as_double()
#| let pio2 : Double = 1.570796326794896558e+00
#| 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
#| }
#|}
#|#deprecated("use `@math.acosf` instead")
#|#coverage.skip
#|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)
#|}
#|#deprecated("use `@math.atanf` instead")
#|#coverage.skip
#|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
#| }
#|}
#|#deprecated("use `@math.atan2f` instead")
#|#coverage.skip
#|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
#| }
#|}
),
"exp.mbt": (
#|fn top12(x : Float) -> UInt {
#| x.reinterpret_as_uint() >> 20
#|}
#|fn __math_xflowf(sign : UInt, y : Float) -> Float {
#| return (if sign != 0 { -y } else { y }) * y
#|}
#|fn __math_oflowf(sign : UInt) -> Float {
#| return __math_xflowf(sign, 0x1.0p97)
#|}
#|fn __math_uflowf(sign : UInt) -> Float {
#| return __math_xflowf(sign, 0x1.0p-95)
#|}
#|let exp2f_table_bits = 5
#|priv struct Exp2fData {
#| tab : FixedArray[UInt64]
#| shift : Double
#| invln2_scaled : Double
#| poly_scaled : FixedArray[Double]
#|}
#|let expf_n : UInt64 = (1 << exp2f_table_bits).to_uint64()
#|let exp2f_data_n : Double = (1 << exp2f_table_bits).to_double()
#|let exp2f_data : Exp2fData = {
#| tab: [
#| 0x3ff0000000000000, 0x3fefd9b0d3158574, 0x3fefb5586cf9890f, 0x3fef9301d0125b51,
#| 0x3fef72b83c7d517b, 0x3fef54873168b9aa, 0x3fef387a6e756238, 0x3fef1e9df51fdee1,
#| 0x3fef06fe0a31b715, 0x3feef1a7373aa9cb, 0x3feedea64c123422, 0x3feece086061892d,
#| 0x3feebfdad5362a27, 0x3feeb42b569d4f82, 0x3feeab07dd485429, 0x3feea47eb03a5585,
#| 0x3feea09e667f3bcd, 0x3fee9f75e8ec5f74, 0x3feea11473eb0187, 0x3feea589994cce13,
#| 0x3feeace5422aa0db, 0x3feeb737b0cdc5e5, 0x3feec49182a3f090, 0x3feed503b23e255d,
#| 0x3feee89f995ad3ad, 0x3feeff76f2fb5e47, 0x3fef199bdd85529c, 0x3fef3720dcef9069,
#| 0x3fef5818dcfba487, 0x3fef7c97337b9b5f, 0x3fefa4afa2a490da, 0x3fefd0765b6e4540,
#| ],
#| shift: 0x1.8p+52,
#| invln2_scaled: 0x1.71547652b82fep+0 * exp2f_data_n,
#| poly_scaled: [
#| 0x1.c6af84b912394p-5 / exp2f_data_n / exp2f_data_n / exp2f_data_n,
#| 0x1.ebfce50fac4f3p-3 / exp2f_data_n / exp2f_data_n,
#| 0x1.62e42ff0c52d6p-1 / exp2f_data_n,
#| ],
#|}
),
"float.mbt": (
#|pub let not_a_number : Float = (0x7FC00000).reinterpret_as_float()
#|pub let infinity : Float = (0x7F800000).reinterpret_as_float()
#|pub let neg_infinity : Float = (0xFF800000).reinterpret_as_float()
#|pub let max_value : Float = (0x7F7FFFFF).reinterpret_as_float()
#|pub let min_value : Float = (0xFF7FFFFF).reinterpret_as_float()
#|pub let min_positive : Float = (0x00800000).reinterpret_as_float()
#|pub fn Float::abs(self : Float) -> Float = "%f32.abs"
#|pub impl Show for Float with output(self, logger) {
#| logger.write_string(self.to_double().to_string())
#|}
#|pub impl Default for Float with default() {
#| 0.0
#|}
#|pub fn default() -> Float {
#| 0.0
#|}
#|pub impl Hash for Float with hash(self) {
#| self.reinterpret_as_int() |> Hash::hash()
#|}
#|pub impl Hash for Float with hash_combine(self, hasher) {
#| hasher.combine_float(self)
#|}
#|pub fn to_be_bytes(self : Float) -> Bytes {
#| self.reinterpret_as_uint().to_be_bytes()
#|}
#|pub fn to_le_bytes(self : Float) -> Bytes {
#| self.reinterpret_as_uint().to_le_bytes()
#|}
#|pub fn is_inf(self : Float) -> Bool {
#| self.is_pos_inf() || self.is_neg_inf()
#|}
#|pub fn is_pos_inf(self : Float) -> Bool {
#| self > max_value
#|}
#|pub fn is_neg_inf(self : Float) -> Bool {
#| self < min_value
#|}
#|pub fn is_nan(self : Float) -> Bool {
#| self != self
#|}
#|pub fn Float::is_close(
#| self : Self,
#| other : Self,
#| relative_tolerance? : Self = 1.0e-09,
#| absolute_tolerance? : Self = 0.0,
#|) -> Bool {
#| if relative_tolerance < 0.0 || absolute_tolerance < 0.0 {
#| abort("Tolerances must be non-negative")
#| }
#| if self == other {
#| return true
#| }
#| if self.is_inf() || other.is_inf() {
#| return false
#| }
#| let diff = (other - self).abs()
#| return (
#| diff <= (relative_tolerance * other).abs() ||
#| diff <= (relative_tolerance * self).abs()
#| ) ||
#| diff <= absolute_tolerance
#|}
),
"hyperbolic.mbt": (
#|fn k_expo2f(x : Float) -> Float {
#| let k = 235
#| let k_ln2 = (0x4322e3bc).reinterpret_as_float()
#| let scale = ((0x7f + k / 2) << 23).reinterpret_as_float()
#| (x - k_ln2).exp() * scale * scale
#|}
),
"log.mbt": (
#|let logf_off = 0x3f330000U
#|let logf_table_bits = 4
#|let logf_n : UInt = 1U << logf_table_bits
#|priv struct LogfData {
#| invc : FixedArray[Double]
#| logc : FixedArray[Double]
#| ln2 : Double
#| poly : FixedArray[Double]
#|}
#|let logf_data : LogfData = {
#| invc: [
#| 0x1.661ec79f8f3bep+0, 0x1.571ed4aaf883dp+0, 0x1.49539f0f010bp+0, 0x1.3c995b0b80385p+0,
#| 0x1.30d190c8864a5p+0, 0x1.25e227b0b8eap+0, 0x1.1bb4a4a1a343fp+0, 0x1.12358f08ae5bap+0,
#| 0x1.0953f419900a7p+0, 0x1.0p+0, 0x1.e608cfd9a47acp-1, 0x1.ca4b31f026aap-1, 0x1.b2036576afce6p-1,
#| 0x1.9c2d163a1aa2dp-1, 0x1.886e6037841edp-1, 0x1.767dcf5534862p-1,
#| ],
#| logc: [
#| -0x1.57bf7808caadep-2, -0x1.2bef0a7c06ddbp-2, -0x1.01eae7f513a67p-2, -0x1.b31d8a68224e9p-3,
#| -0x1.6574f0ac07758p-3, -0x1.1aa2bc79c81p-3, -0x1.a4e76ce8c0e5ep-4, -0x1.1973c5a611cccp-4,
#| -0x1.252f438e10c1ep-5, 0x0.0p+0, 0x1.aa5aa5df25984p-5, 0x1.c5e53aa362eb4p-4,
#| 0x1.526e57720db08p-3, 0x1.bc2860d22477p-3, 0x1.1058bc8a07ee1p-2, 0x1.4043057b6ee09p-2,
#| ],
#| ln2: 0x1.62e42fefa39efp-1,
#| poly: [-0x1.00ea348b88334p-2, 0x1.5575b0be00b6ap-2, -0x1.ffffef20a4123p-2],
#|}
),
"math_functions.mbt": (
#|pub fnalias Float::(
#| sin,
#| cos,
#| tan,
#| asin,
#| acos,
#| atan,
#| atan2,
#| exp,
#| expm1,
#| pow,
#| ln,
#| ln_1p,
#| sinh,
#| cosh,
#| tanh,
#| asinh,
#| acosh,
#| atanh,
#| hypot,
#| cbrt,
#| trunc,
#| ceil,
#| floor,
#| round,
#| abs
#|)
),
"mod.mbt": (
#|pub impl Mod for Float with mod(self : Float, other : Float) -> Float {
#| (self.to_double() % other.to_double()).to_float()
#|}
),
"pow.mbt": (
#|pub fn Float::pow(self : Float, other : Float) -> Float {
#| self.to_double().pow(other.to_double()).to_float()
#|}
),
"round.mbt": (
#|let sign_mask : UInt = 0x8000_0000
#|let exp_bias = 127
#|let exp_bits = 8
#|let frac_bits = 23
#|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()
#|}
#|pub fn Float::ceil(self : Float) -> Float {
#| let trunced = self.trunc()
#| if self > trunced {
#| return trunced + 1.0
#| } else {
#| return trunced
#| }
#|}
#|pub fn Float::floor(self : Float) -> Float {
#| let trunced = self.trunc()
#| if self < trunced {
#| return trunced - 1.0
#| } else {
#| return trunced
#| }
#|}
#|pub fn Float::round(self : Float) -> Float {
#| floor(self + 0.5)
#|}
),
"round_js.mbt": (
#|pub fn Float::trunc(self : Float) -> Float = "Math" "trunc"
#|pub fn Float::ceil(self : Float) -> Float = "Math" "ceil"
#|pub fn Float::floor(self : Float) -> Float = "Math" "floor"
#|pub fn Float::round(self : Float) -> Float = "Math" "round"
),
"round_wasm.mbt": (
#|pub fn Float::trunc(self : Float) -> Float = "(func (param $f f32) (result f32) (f32.trunc (local.get $f)))"
#|pub fn Float::ceil(self : Float) -> Float = "(func (param $f f32) (result f32) (f32.ceil (local.get $f)))"
#|pub fn Float::floor(self : Float) -> Float = "(func (param $f f32) (result f32) (f32.floor (local.get $f)))"
#|pub fn Float::round(self : Float) -> Float {
#| floor(self + 0.5)
#|}
),
"to_int.mbt": (
#|fn Float::to_unchecked_int(self : Float) -> Int = "%f32.to_i32"
#|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()
#| }
#|}
),
"to_int_wasm.mbt": (
#|pub fn to_int(self : Float) -> Int = "%f32.to_i32_saturate"
),
"trig.mbt": (
#|const SIN_SWITCHOVER : Float = 201.15625
#|const COS_SWITCHOVER : Float = 142.90625
#|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()
#|}
#|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())
#|}
#|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 += 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)
#|}
#|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
#|}
#|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
#|}
#|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
#|}
#|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()
#|}
),
},
)
///|
let moonbitlang_core_hashmap_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/test",
#| "moonbitlang/core/array",
#| "moonbitlang/core/tuple",
#| "moonbitlang/core/quickcheck",
#| "moonbitlang/core/int"
#| ],
#| "test-import": ["moonbitlang/core/string", "moonbitlang/core/json"]
#|}
),
"deprecated.mbt": "",
"hashmap.mbt": (
#|pub fn[K, V] new(capacity? : Int = 8) -> HashMap[K, V] {
#| let capacity = capacity.next_power_of_two()
#| {
#| size: 0,
#| capacity,
#| entries: FixedArray::make(capacity, None),
#| capacity_mask: capacity - 1,
#| }
#|}
#|pub fn[K : Hash + Eq, V] from_array(arr : Array[(K, V)]) -> HashMap[K, V] {
#| let m = new(capacity=arr.length())
#| arr.each(e => m.set(e.0, e.1))
#| m
#|}
#|pub fn[K : Hash + Eq, V] set(self : HashMap[K, V], key : K, value : V) -> Unit {
#| self.set_with_hash(key, value, key.hash())
#|}
#|fn[K : Eq, V] set_with_hash(
#| self : HashMap[K, V],
#| key : K,
#| value : V,
#| hash : Int,
#|) -> Unit {
#| if self.size >= self.capacity / 2 {
#| self.grow()
#| }
#| 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 = { psl, key, value, hash }
#| self.entries[idx] = Some(entry)
#| self.size += 1
#|}
#|fn[K, V] HashMap::push_away(
#| self : HashMap[K, V],
#| idx : Int,
#| entry : Entry[K, V],
#|) -> Unit {
#| for psl = entry.psl + 1, idx = (idx + 1) & self.capacity_mask, entry = entry {
#| match self.entries[idx] {
#| None => {
#| entry.psl = psl
#| self.entries[idx] = Some(entry)
#| break
#| }
#| Some(curr_entry) =>
#| if psl > curr_entry.psl {
#| entry.psl = psl
#| self.entries[idx] = Some(entry)
#| continue curr_entry.psl + 1,
#| (idx + 1) & self.capacity_mask,
#| curr_entry
#| } else {
#| continue psl + 1, (idx + 1) & self.capacity_mask, entry
#| }
#| }
#| }
#|}
#|pub fn[K : Hash + Eq, V] op_set(
#| self : HashMap[K, V],
#| key : K,
#| value : V,
#|) -> Unit {
#| self.set(key, value)
#|}
#|pub fn[K : Hash + Eq, V] get(self : HashMap[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
#| }
#|}
#|pub fn[K : Hash + Eq, V] op_get(self : HashMap[K, V], key : K) -> V {
#| let hash = key.hash()
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries[idx] is Some(entry)
#| if entry.hash == hash && entry.key == key {
#| break entry.value
#| }
#| guard entry.psl <= i
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#|}
#|pub fn[K : Hash + Eq, V] get_or_init(
#| self : HashMap[K, V],
#| key : K,
#| init : () -> V,
#|) -> V {
#| let hash = key.hash()
#| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash &
#| self.capacity_mask {
#| match self.entries[idx] {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| return entry.value
#| }
#| if psl > entry.psl {
#| let new_value = init()
#| break (idx, psl, new_value, Some(entry))
#| }
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| None => {
#| let new_value = init()
#| break (idx, psl, new_value, None)
#| }
#| }
#| }
#| if self.size >= self.capacity / 2 {
#| self.grow()
#| self.set_with_hash(key, new_value, hash)
#| } else {
#| if push_away is Some(entry) {
#| self.push_away(idx, entry)
#| }
#| let entry = { psl, hash, key, value: new_value }
#| self.entries[idx] = Some(entry)
#| self.size += 1
#| }
#| new_value
#|}
#|pub fn[K : Hash + Eq, V] get_or_default(
#| self : HashMap[K, V],
#| key : K,
#| default : V,
#|) -> V {
#| let hash = key.hash()
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries[idx] is Some(entry) else { break default }
#| if entry.hash == hash && entry.key == key {
#| break entry.value
#| }
#| if i > entry.psl {
#| break default
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#|}
#|pub fn[K : Hash + Eq, V] contains(self : HashMap[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
#| }
#|}
#|pub fn[K : Hash + Eq, V : Eq] contains_kv(
#| self : HashMap[K, V],
#| key : K,
#| value : V,
#|) -> 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 && entry.value == value {
#| return true
#| }
#| if i > entry.psl {
#| return false
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#|}
#|pub fn[K : Hash + Eq, V] remove(self : HashMap[K, V], key : K) -> Unit {
#| self.remove_with_hash(key, key.hash())
#|}
#|fn[K : Eq, V] remove_with_hash(
#| self : HashMap[K, V],
#| key : K,
#| hash : Int,
#|) -> Unit {
#| for i = 0, idx = hash & self.capacity_mask {
#| match self.entries[idx] {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| self.shift_back(idx)
#| self.size -= 1
#| break
#| }
#| if i > entry.psl {
#| break
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#| None => break
#| }
#| }
#|}
#|fn[K, V] shift_back(self : HashMap[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.entries[idx] = Some(entry)
#| self.shift_back(next)
#| }
#| }
#|}
#|fn[K : Eq, V] grow(self : HashMap[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.. HashMap[K, V] {
#| let m = new(capacity=arr.length())
#| arr.each(e => m.set(e.0, e.1))
#| m
#|}
#|test "of" {
#| let m = of([(1, 2), (3, 4)])
#| inspect(m.get(1), content="Some(2)")
#| inspect(m.get(3), content="Some(4)")
#|}
#|pub impl[K : @quickcheck.Arbitrary + Hash + Eq, V : @quickcheck.Arbitrary] @quickcheck.Arbitrary for HashMap[
#| K,
#| V,
#|] with arbitrary(size, rs) {
#| let m = new()
#| (@quickcheck.Arbitrary::arbitrary(size, rs) : Iter[(K, V)]).each(kv => m.set(
#| kv.0,
#| kv.1,
#| ))
#| m
#|}
#|pub impl[K, V] Default for HashMap[K, V] with default() {
#| new()
#|}
#|pub fn[K, V, V2] HashMap::map(
#| self : HashMap[K, V],
#| f : (K, V) -> V2,
#|) -> HashMap[K, V2] {
#| let other = {
#| capacity: self.capacity,
#| entries: FixedArray::make(self.capacity, None),
#| size: self.size,
#| capacity_mask: self.capacity_mask,
#| }
#| if self.size == 0 {
#| return other
#| }
#| for i in 0.. HashMap[K, V] {
#| let other = {
#| capacity: self.capacity,
#| entries: FixedArray::make(self.capacity, None),
#| size: self.size,
#| capacity_mask: self.capacity_mask,
#| }
#| if self.size == 0 {
#| return other
#| }
#| for i in 0.. 1), content="1")
#| inspect(m.get("a"), content="Some(1)")
#| inspect(m.get_or_init("a", () => 2), content="1")
#| inspect(m.get("a"), content="Some(1)")
#|}
),
"json.mbt": (
#|pub impl[K : Show, V : ToJson] ToJson for HashMap[K, V] with to_json(self) {
#| let object = Map::new(capacity=self.capacity)
#| for k, v in self {
#| object[k.to_string()] = v.to_json()
#| }
#| Json::object(object)
#|}
),
"types.mbt": (
#|priv struct Entry[K, V] {
#| mut psl : Int
#| hash : Int
#| key : K
#| mut value : V
#|} derive(Show)
#|struct HashMap[K, V] {
#| mut entries : FixedArray[Entry[K, V]?]
#| mut capacity : Int
#| mut capacity_mask : Int // capacity_mask = capacity - 1, used to find idx
#| mut size : Int // active key-value pairs count
#|}
#|pub impl[K : Hash + Eq, V : Eq] Eq for HashMap[K, V] with equal(
#| self : HashMap[K, V],
#| that : HashMap[K, V],
#|) -> Bool {
#| guard self.size == that.size else { return false }
#| for k, v in self {
#| guard that.contains_kv(k, v) else { return false }
#| } else {
#| true
#| }
#|}
#|#deprecated("Use `HashMap` instead of `T`")
#|pub typealias HashMap as T
),
"utils.mbt": (
#|fn[K : Show, V : Show] debug_entries(self : HashMap[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
#| }
#|}
#|pub fn[K, V] clear(self : HashMap[K, V]) -> Unit {
#| self.entries.fill(None)
#| self.size = 0
#|}
#|pub fn[K, V] iter(self : HashMap[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
#| })
#|}
#|pub fn[K, V] iter2(self : HashMap[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
#| })
#|}
#|pub fn[K : Hash + Eq, V] from_iter(iter : Iter[(K, V)]) -> HashMap[K, V] {
#| let m = new()
#| iter.each(e => m[e.0] = e.1)
#| m
#|}
#|pub fn[K, V] to_array(self : HashMap[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
#|}
#|pub fn[K, V] size(self : HashMap[K, V]) -> Int {
#| self.size
#|}
#|pub fn[K, V] capacity(self : HashMap[K, V]) -> Int {
#| self.capacity
#|}
#|pub fn[K, V] is_empty(self : HashMap[K, V]) -> Bool {
#| self.size == 0
#|}
#|#locals(f)
#|pub fn[K, V] each(
#| self : HashMap[K, V],
#| f : (K, V) -> Unit raise?,
#|) -> Unit raise? {
#| for i in 0.. Unit raise?,
#|) -> Unit raise? {
#| 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
#| }
#| }
#|}
#|pub impl[K : Show, V : Show] Show for HashMap[K, V] with output(self, logger) {
#| logger.write_string("HashMap::of([")
#| self.eachi((i, k, v) => {
#| if i > 0 {
#| logger.write_string(", ")
#| }
#| logger
#| ..write_string("(")
#| ..write_object(k)
#| ..write_string(", ")
#| ..write_object(v)
#| ..write_string(")")
#| })
#| logger.write_string("])")
#|}
#|pub fn[K, V] HashMap::keys(self : HashMap[K, V]) -> 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
#| })
#|}
#|pub fn[K, V] HashMap::values(self : HashMap[K, V]) -> Iter[V] {
#| Iter::new(yield_ => for entry in self.entries {
#| if entry is Some({ value, .. }) {
#| guard yield_(value) is IterContinue else { break IterEnd }
#| }
#| } else {
#| IterContinue
#| })
#|}
#|#locals(f)
#|pub fn[K, V] retain(self : HashMap[K, V], f : (K, V) -> Bool) -> Unit {
#| let last = self.capacity - 1
#| while self.entries[last] is Some(entry) && !f(entry.key, entry.value) {
#| self.shift_back(last)
#| self.size -= 1
#| }
#| for i = last - 1; i >= 0; i = i - 1 {
#| if self.entries[i] is Some(entry) {
#| if !f(entry.key, entry.value) {
#| self.shift_back(i)
#| self.size -= 1
#| }
#| }
#| }
#|}
),
},
)
///|
let moonbitlang_core_hashset_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/test",
#| "moonbitlang/core/array",
#| "moonbitlang/core/quickcheck"
#| ],
#| "test-import": [
#| "moonbitlang/core/string",
#| "moonbitlang/core/int",
#| "moonbitlang/core/json"
#| ]
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `add` instead.")
#|#coverage.skip
#|pub fn[K : Hash + Eq] insert(self : HashSet[K], key : K) -> Unit {
#| self.add(key)
#|}
),
"hashset.mbt": (
#|let default_init_capacity = 8
#|pub fn[K] HashSet::new(capacity? : Int = default_init_capacity) -> HashSet[K] {
#| {
#| size: 0,
#| capacity,
#| capacity_mask: capacity - 1,
#| grow_at: calc_grow_threshold(capacity),
#| entries: FixedArray::make(capacity, None),
#| }
#|}
#|pub fn[K : Hash + Eq] HashSet::from_array(arr : Array[K]) -> HashSet[K] {
#| let m = new()
#| arr.each(e => m.add(e))
#| m
#|}
#|pub fn[K : Hash + Eq] HashSet::of(arr : FixedArray[K]) -> HashSet[K] {
#| let m = new()
#| arr.each(e => m.add(e))
#| m
#|}
#|pub fn[K : Hash + Eq] add(self : HashSet[K], key : K) -> Unit {
#| self.add_with_hash(key, key.hash())
#|}
#|fn[K : Eq] add_with_hash(self : HashSet[K], key : K, hash : Int) -> Unit {
#| if self.size >= self.grow_at {
#| self.grow()
#| }
#| let (idx, psl) = for psl = 0, idx = abs(hash) & self.capacity_mask {
#| match self.entries[idx] {
#| None => break (idx, psl)
#| Some(curr_entry) => {
#| if curr_entry.hash == hash && curr_entry.key == key {
#| 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 = { psl, key, hash }
#| self.set_entry(entry, idx)
#| self.size += 1
#|}
#|fn[K] push_away(self : HashSet[K], idx : Int, entry : Entry[K]) -> Unit {
#| for psl = entry.psl + 1, idx = (idx + 1) & self.capacity_mask, entry = entry {
#| match self.entries[idx] {
#| None => {
#| entry.psl = psl
#| self.set_entry(entry, idx)
#| break
#| }
#| Some(curr_entry) =>
#| if psl > curr_entry.psl {
#| entry.psl = psl
#| self.set_entry(entry, idx)
#| continue curr_entry.psl + 1,
#| (idx + 1) & self.capacity_mask,
#| curr_entry
#| } else {
#| continue psl + 1, (idx + 1) & self.capacity_mask, entry
#| }
#| }
#| }
#|}
#|#inline
#|fn[K] set_entry(self : HashSet[K], entry : Entry[K], new_idx : Int) -> Unit {
#| self.entries[new_idx] = Some(entry)
#|}
#|pub fn[K : Hash + Eq] contains(self : HashSet[K], key : K) -> Bool {
#| let hash = key.hash()
#| for i = 0, idx = abs(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
#| }
#|}
#|pub fn[K : Hash + Eq] remove(self : HashSet[K], key : K) -> Unit {
#| let hash = key.hash()
#| for i = 0, idx = abs(hash) & self.capacity_mask {
#| guard self.entries[idx] is Some(entry) else { break }
#| if entry.hash == hash && entry.key == key {
#| self.shift_back(idx)
#| self.size -= 1
#| break
#| }
#| if i > entry.psl {
#| break
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#|}
#|fn[K] shift_back(self : HashSet[K], 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)
#| }
#| }
#|}
#|fn[K : Eq] grow(self : HashSet[K]) -> Unit {
#| if self.capacity == 0 {
#| self.capacity = default_init_capacity
#| self.capacity_mask = self.capacity - 1
#| 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.capacity_mask = self.capacity - 1
#| self.grow_at = calc_grow_threshold(self.capacity)
#| self.size = 0
#| for i in 0.. Int {
#| self.size
#|}
#|pub fn[K] capacity(self : HashSet[K]) -> Int {
#| self.capacity
#|}
#|pub fn[K] is_empty(self : HashSet[K]) -> Bool {
#| self.size == 0
#|}
#|#locals(f)
#|pub fn[K] each(self : HashSet[K], f : (K) -> Unit raise?) -> Unit raise? {
#| for entry in self.entries {
#| if entry is Some({ key, .. }) {
#| f(key)
#| }
#| }
#|}
#|#locals(f)
#|pub fn[K] eachi(self : HashSet[K], f : (Int, K) -> Unit raise?) -> Unit raise? {
#| let mut idx = 0
#| for i in 0.. Unit {
#| self.entries.fill(None)
#| self.size = 0
#|}
#|pub fn[K] iter(self : HashSet[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
#| })
#|}
#|pub fn[K] to_array(self : HashSet[K]) -> Array[K] {
#| let arr = Array::new(capacity=self.size)
#| for entry in self.entries {
#| if entry is Some({ key, .. }) {
#| arr.push(key)
#| }
#| }
#| arr
#|}
#|pub fn[K : Hash + Eq] HashSet::from_iter(iter : Iter[K]) -> HashSet[K] {
#| let s = new()
#| iter.each(e => s.add(e))
#| s
#|}
#|pub fn[K : Hash + Eq] union(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> HashSet[K] {
#| let m = new()
#| self.each(k => m.add(k))
#| other.each(k => m.add(k))
#| m
#|}
#|pub fn[K : Hash + Eq] intersection(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> HashSet[K] {
#| let m = new()
#| self.each(k => if other.contains(k) { m.add(k) })
#| m
#|}
#|pub fn[K : Hash + Eq] difference(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> HashSet[K] {
#| let m = new()
#| self.each(k => if !other.contains(k) { m.add(k) })
#| m
#|}
#|pub fn[K : Hash + Eq] symmetric_difference(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> HashSet[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
#|}
#|pub fn[K : Hash + Eq] is_disjoint(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> Bool {
#| if self.size() <= other.size() {
#| self.iter().all(k => !other.contains(k))
#| } else {
#| other.iter().all(k => !self.contains(k))
#| }
#|}
#|pub fn[K : Hash + Eq] is_subset(self : HashSet[K], other : HashSet[K]) -> Bool {
#| if self.size() <= other.size() {
#| self.iter().all(k => other.contains(k))
#| } else {
#| false
#| }
#|}
#|pub fn[K : Hash + Eq] is_superset(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> Bool {
#| other.is_subset(self)
#|}
#|pub impl[K : Hash + Eq] BitAnd for HashSet[K] with land(self, other) {
#| self.intersection(other)
#|}
#|pub impl[K : Hash + Eq] BitOr for HashSet[K] with lor(self, other) {
#| self.union(other)
#|}
#|pub impl[K : Hash + Eq] BitXOr for HashSet[K] with lxor(self, other) {
#| self.symmetric_difference(other)
#|}
#|pub impl[K : Hash + Eq] Sub for HashSet[K] with sub(self, other) {
#| self.difference(other)
#|}
#|pub impl[X : @quickcheck.Arbitrary + Eq + Hash] @quickcheck.Arbitrary for HashSet[
#| X,
#|] with arbitrary(size, rs) {
#| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_iter
#|}
#|fn abs(n : Int) -> Int {
#| if n < 0 {
#| -n
#| } else {
#| n
#| }
#|}
#|fn calc_grow_threshold(capacity : Int) -> Int {
#| capacity * 13 / 16
#|}
#|fn[K : Show] debug_entries(self : HashSet[K]) -> String {
#| let mut s = ""
#| for i in 0.. 0 {
#| s += ","
#| }
#| match self.entries[i] {
#| None => s += "_"
#| Some({ psl, key, .. }) => s += "(\{psl},\{key})"
#| }
#| }
#| s
#|}
#|priv struct MyString(String) derive(Eq)
#|impl Hash for MyString with hash(self) {
#| let MyString(self) = self
#| self.length()
#|}
#|impl Hash for MyString with hash_combine(self, hasher) {
#| let MyString(self) = self
#| hasher.combine_string(self)
#|}
#|impl Show for MyString with output(self, logger) {
#| let MyString(self) = self
#| logger.write_string(self)
#|}
#|test "set" {
#| let m : HashSet[MyString] = new()
#| m.add("a")
#| m.add("b")
#| m.add("bc")
#| m.add("abc")
#| m.add("cd")
#| m.add("c")
#| m.add("d")
#| inspect(m.size, content="7")
#| assert_eq(
#| m.debug_entries(),
#| "_,(0,a),(1,b),(2,c),(3,d),(3,bc),(4,cd),(4,abc),_,_,_,_,_,_,_,_",
#| )
#|}
#|test "remove" {
#| let m : HashSet[MyString] = new()
#| fn i(s) {
#| MyString::MyString(s)
#| }
#| m.add("a" |> i)
#| m.add("ab" |> i)
#| m.add("bc" |> i)
#| m.add("cd" |> i)
#| m.add("abc" |> i)
#| m.add("abcdef" |> i)
#| m.remove("ab" |> i)
#| inspect(m.size(), content="5")
#| inspect(
#| m.debug_entries(),
#| content="_,(0,a),(0,bc),(1,cd),(1,abc),_,(0,abcdef),_",
#| )
#|}
#|test "remove_unexist_key" {
#| let m : HashSet[MyString] = new()
#| fn i(s) {
#| MyString::MyString(s)
#| }
#| m.add("a" |> i)
#| m.add("ab" |> i)
#| m.add("abc" |> i)
#| m.remove("d" |> i)
#| inspect(m.size(), content="3")
#| inspect(m.debug_entries(), content="_,(0,a),(0,ab),(0,abc),_,_,_,_")
#|}
#|test "grow" {
#| let m : HashSet[MyString] = new()
#| fn i(s) {
#| MyString::MyString(s)
#| }
#| m.add("C" |> i)
#| m.add("Go" |> i)
#| m.add("C++" |> i)
#| m.add("Java" |> i)
#| m.add("Scala" |> i)
#| m.add("Julia" |> i)
#| inspect(m.size, content="6")
#| inspect(m.capacity, content="8")
#| m.add("Cobol" |> i)
#| inspect(m.size, content="7")
#| inspect(m.capacity, content="16")
#| m.add("Python" |> i)
#| m.add("Haskell" |> i)
#| m.add("Rescript" |> i)
#| inspect(m.size, content="10")
#| inspect(m.capacity, content="16")
#| assert_eq(
#| m.debug_entries(),
#| "_,(0,C),(0,Go),(0,C++),(0,Java),(0,Scala),(1,Julia),(2,Cobol),(2,Python),(2,Haskell),(2,Rescript),_,_,_,_,_",
#| )
#|}
#|test "clear" {
#| let m : HashSet[MyString] = new()
#| m.clear()
#| inspect(m.size(), content="0")
#| inspect(m.capacity(), content="8")
#| for i in 0.. Bool {
#| let old_size = self.size
#| self.add(key)
#| self.size > old_size
#|}
#|pub fn[K : Hash + Eq] remove_and_check(self : HashSet[K], key : K) -> Bool {
#| let old_size = self.size
#| self.remove(key)
#| self.size < old_size
#|}
#|pub fn[K] copy(self : HashSet[K]) -> HashSet[K] {
#| let other = {
#| capacity: self.capacity,
#| entries: FixedArray::make(self.capacity, None),
#| size: self.size,
#| capacity_mask: self.capacity_mask,
#| grow_at: self.grow_at,
#| }
#| for i in 0.. T[A] {
#| { tree: Tree::empty(), size: 0, shift: 0 }
#|}
#|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 }
#|}
#|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 }
#|}
#|pub fn[A] of(arr : FixedArray[A]) -> T[A] {
#| makei(arr.length(), i => arr[i])
#|}
#|#deprecated("We don't copy immutable array")
#|#coverage.skip
#|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 }
#|}
#|pub fn[A] from_array(arr : Array[A]) -> T[A] {
#| makei(arr.length(), i => arr[i])
#|}
#|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 }
#|}
#|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
#| }
#|}
#|pub fn[A] is_empty(self : T[A]) -> Bool {
#| self.size == 0
#|}
#|pub fn[A] length(self : T[A]) -> Int {
#| self.size
#|}
#|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)
#| }
#|}
#|pub fn[A] get(self : T[A], index : Int) -> A? {
#| guard 0 <= index && index < self.size else { None }
#| Some(self[index])
#|}
#|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,
#| }
#|}
#|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 }
#|}
#|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 }
#|}
#|pub impl[A] Add for T[A] with add(self, other) {
#| self.concat(other)
#|}
#|pub fn[A] iter(self : T[A]) -> Iter[A] {
#| self.tree.iter()
#|}
#|pub fn[A] each(self : T[A], f : (A) -> Unit raise?) -> Unit raise? {
#| self.tree.each(f)
#|}
#|pub fn[A] eachi(self : T[A], f : (Int, A) -> Unit raise?) -> Unit raise? {
#| self.tree.eachi(f, self.shift, 0)
#|}
#|pub fn[A, B] fold(self : T[A], init~ : B, f : (B, A) -> B raise?) -> B raise? {
#| self.tree.fold(init, f)
#|}
#|pub fn[A, B] rev_fold(
#| self : T[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| self.tree.rev_fold(init, f)
#|}
#|#deprecated("Use `fold` instead")
#|#coverage.skip
#|pub fn[A] fold_left(self : T[A], f : (A, A) -> A raise?, init~ : A) -> A raise? {
#| self.fold(init~, f)
#|}
#|#deprecated("Use `rev_fold` instead")
#|#coverage.skip
#|pub fn[A] fold_right(
#| self : T[A],
#| f : (A, A) -> A raise?,
#| init~ : A,
#|) -> A raise? {
#| self.rev_fold(init~, f)
#|}
#|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 }
#|}
#|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for T[X] with arbitrary(
#| size,
#| rs,
#|) {
#| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array
#|}
#|pub impl[A : Hash] Hash for T[A] with hash_combine(self, hasher) {
#| for e in self {
#| hasher.combine(e)
#| }
#|}
#|pub impl[A : Eq] Eq for T[A] with equal(self, other) {
#| self.size == other.size && self.tree == other.tree
#|}
#|pub impl[A : Show] Show for T[A] with output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@immut/array.of([", suffix="])")
#|}
#|pub impl[A : Compare] Compare for T[A] with compare(self, other) {
#| let len_self = self.length()
#| let len_other = other.length()
#| let cmp = len_self.compare(len_other)
#| guard cmp is 0 else { return cmp }
#| for i in 0.. Tree[A] {
#| if cap == branching_factor {
#| Leaf(leaves[0])
#| } else if leaves.length() <= branching_factor {
#| let arr = FixedArray::make(leaves.length(), Empty)
#| for i in 0.. from_leaves(
#| leaves[i * times:(i + 1) * times],
#| child_cap,
#| ))
#| } else {
#| let arr = FixedArray::make(quot + 1, Tree::Empty)
#| for i in 0.. (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)
#|}
),
"deprecated.mbt": (
#|#deprecated("use `@immut/array.new` instead")
#|#coverage.skip
#|pub fn[A] T::new() -> T[A] {
#| new()
#|}
#|#deprecated("use `@immut/array.from_iter` instead")
#|#coverage.skip
#|pub fn[A] T::from_iter(iter : Iter[A]) -> T[A] {
#| from_iter(iter)
#|}
#|#deprecated("use `@immut/array.from_array` instead")
#|#coverage.skip
#|pub fn[A] T::from_array(arr : Array[A]) -> T[A] {
#| from_array(arr)
#|}
#|#deprecated("use `@immut/array.make` instead")
#|#coverage.skip
#|pub fn[A] T::make(len : Int, value : A) -> T[A] {
#| make(len, value)
#|}
#|#deprecated("use `@immut/array.makei` instead")
#|#coverage.skip
#|pub fn[A] T::makei(len : Int, f : (Int) -> A) -> T[A] {
#| makei(len, f)
#|}
#|#deprecated("use `@immut/array.of` instead")
#|#coverage.skip
#|pub fn[A] T::of(arr : FixedArray[A]) -> T[A] {
#| of(arr)
#|}
),
"tree.mbt": (
#|let num_bits = 5
#|let branching_factor : Int = 1 << num_bits
#|let bitmask : Int = branching_factor - 1
#|const LINEAR_THRESHOLD : Int = 4
#|const E_MAX : Int = 2
#|let e_max_2 : Int = E_MAX / 2
#|fn[T] Tree::empty() -> Tree[T] {
#| Tree::Empty
#|}
#|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
#| }
#|}
#|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")
#| }
#|}
#|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")
#| }
#|}
#|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")
#| }
#|}
#|fn[T] Tree::set(self : Tree[T], index : Int, shift : Int, value : T) -> Tree[T] {
#| 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")
#| }
#|}
#|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) {
#| 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))
#| }
#| 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,
#| )
#| }
#| }
#|}
#|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))
#| }
#|}
#|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
#| }
#| })
#|}
#|fn[A] Tree::eachi(
#| self : Tree[A],
#| f : (Int, A) -> Unit raise?,
#| shift : Int,
#| start : Int,
#|) -> Unit raise? {
#| match self {
#| Empty => ()
#| Leaf(l) =>
#| for i in 0.. {
#| let child_shift = shift - num_bits
#| let mut start = start
#| for i in 0.. {
#| let child_shift = shift - num_bits
#| let mut start = start
#| for i in 0.. B raise?,
#|) -> B raise? {
#| match self {
#| Empty => acc
#| Leaf(l) => l.fold(f, init=acc)
#| Node(n, _) => n.fold((acc, t) => t.fold(acc, f), init=acc)
#| }
#|}
#|fn[A, B] Tree::rev_fold(
#| self : Tree[A],
#| acc : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| match self {
#| Empty => acc
#| Leaf(l) => l.rev_fold(f, init=acc)
#| Node(n, _) => n.rev_fold((acc, t) => t.rev_fold(acc, f), init=acc)
#| }
#|}
#|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))
#| }
#|}
#|fn[A] Tree::concat(
#| left : Tree[A],
#| left_shift : Int,
#| right : Tree[A],
#| right_shift : Int,
#| top : Bool,
#|) -> (Tree[A], Int) {
#| if left_shift > right_shift {
#| let (c, c_shift) = Tree::concat(
#| left.right_child(),
#| left_shift - num_bits,
#| right,
#| right_shift,
#| false,
#| )
#| guard c_shift == left_shift
#| return rebalance(left, c, Empty, left_shift, top)
#| } else if right_shift > left_shift {
#| let (c, c_shift) = Tree::concat(
#| left,
#| left_shift,
#| right.left_child(),
#| right_shift - num_bits,
#| false,
#| )
#| guard c_shift == right_shift
#| return rebalance(Empty, c, right, right_shift, top)
#| } else if left_shift == 0 {
#| let left_elems = left.leaf_elements()
#| let right_elems = right.leaf_elements()
#| let left_len = left_elems.length()
#| let right_len = right_elems.length()
#| let len = left_len + right_len
#| if top && len <= branching_factor {
#| return (
#| Leaf(
#| FixedArray::makei(len, (i : Int) => if i < left_len {
#| left_elems[i]
#| } else {
#| right_elems[i - left_len]
#| }),
#| ),
#| 0,
#| )
#| } else {
#| return (
#| Node(
#| FixedArray::from_array([left, right]),
#| Some(FixedArray::from_array([left_len, len])),
#| ),
#| num_bits,
#| )
#| }
#| } else {
#| let (c, c_shift) = Tree::concat(
#| left.right_child(),
#| left_shift - num_bits,
#| right.left_child(),
#| right_shift - num_bits,
#| false,
#| )
#| guard c_shift == left_shift
#| guard c_shift == right_shift
#| return rebalance(left, c, right, left_shift, top)
#| }
#|}
#|fn[A] rebalance(
#| left : Tree[A],
#| center : Tree[A],
#| right : Tree[A],
#| shift : Int,
#| top : Bool,
#|) -> (Tree[A], Int) {
#| let t = tri_merge(left, center, right) // t is a list of trees of (H-1) height
#| let (nc, nc_len) = redis_plan(t)
#| let new_t = redis(t, nc, nc_len, shift - num_bits) // new_t is a list of trees of (H-1) height
#| guard new_t.length() == nc_len
#| if nc_len <= branching_factor {
#| let node = Node(new_t, compute_sizes(new_t, shift - num_bits)) // node of H height
#| if !top {
#| return (Node(FixedArray::from_array([node]), None), shift + num_bits)
#| } else {
#| return (node, shift)
#| }
#| } else {
#| let new_child_1 = FixedArray::makei(branching_factor, i => new_t[i])
#| let new_child_2 = FixedArray::makei(new_t.length() - branching_factor, i => new_t[i +
#| branching_factor])
#| let new_node_1 = Node(
#| new_child_1,
#| compute_sizes(new_child_1, shift - num_bits),
#| ) // height H
#| let new_node_2 = Node(
#| new_child_2,
#| compute_sizes(new_child_2, shift - num_bits),
#| ) // height H
#| let new_children = FixedArray::from_array([new_node_1, new_node_2])
#| return (
#| Node(new_children, compute_sizes(new_children, shift)),
#| shift + num_bits,
#| ) // return (H+1) height node
#| }
#|}
#|fn[A] tri_merge(
#| left : Tree[A],
#| center : Tree[A],
#| right : Tree[A],
#|) -> FixedArray[Tree[A]] {
#| if left.is_leaf() || !center.is_node() || right.is_leaf() {
#| abort("Unreachable: input to merge is invalid")
#| }
#| fn get_children(self : Tree[A]) -> FixedArray[Tree[A]] {
#| match self {
#| Node(children, _) => children
#| Empty => []
#| Leaf(_) => abort("Unreachable")
#| }
#| }
#| let left_children = get_children(left)
#| let center_children = get_children(center)
#| let right_children = get_children(right)
#| let left_len = left_children.length()
#| let left_len = if left_len == 0 { 0 } else { left_len - 1 }
#| let center_len = center_children.length()
#| let right_len = right_children.length()
#| let right_len = if right_len == 0 { 0 } else { right_len - 1 }
#| FixedArray::makei(left_len + center_len + right_len, i => if i < left_len {
#| left_children[i]
#| } else if i < left_len + center_len {
#| center_children[i - left_len]
#| } else if right_len > 0 {
#| right_children[1 + i - left_len - center_len]
#| } else {
#| abort("Unreachable")
#| })
#|}
#|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)
#| 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 {
#| while node_counts[i] > branching_factor - e_max_2 {
#| i += 1
#| }
#| 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)
#|}
#|fn[A] redis(
#| old_t : FixedArray[Tree[A]],
#| node_counts : FixedArray[Int],
#| node_nums : Int,
#| shift : Int,
#|) -> FixedArray[Tree[A]] {
#| let old_len = old_t.length()
#| let new_t = FixedArray::make(node_nums, Empty)
#| let mut old_offset = 0
#| let mut j = 0 // the index of in the old tree
#| if shift == 0 {
#| let mut old_leaf_elems = FixedArray::default()
#| let mut old_leaf_len = 0
#| for i in 0.. FixedArray[Int]? {
#| let len = children.length()
#| let sizes = FixedArray::make(len, 0)
#| let mut sum = 0
#| let mut flag = true
#| let full_subtree_size = branching_factor << shift
#| for i in 0.. String {
#| String::make(indent, ' ') + s
#| }
#| fn aux(t : Tree[A], ident : Int) {
#| match t {
#| Empty => indent_str("Empty", ident)
#| Leaf(l) => {
#| let mut s = "Leaf("
#| for i in 0.. {
#| let mut s = indent_str("Node(", ident) + "\n"
#| for i in 0.. Bool {
#| self is Node(_, _)
#|}
#|fn[A] Tree::is_leaf(self : Tree[A]) -> Bool {
#| self is Leaf(_)
#|}
#|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")
#| }
#|}
#|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")
#| }
#|}
#|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
#|}
#|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
#|}
#|fn[A] Tree::local_size(self : Tree[A]) -> Int {
#| match self {
#| Empty => 0
#| Leaf(l) => l.length()
#| Node(children, _) => children.length()
#| }
#|}
#|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)
#| }
#| }
#|}
),
"types.mbt": (
#|struct T[A] {
#| tree : Tree[A]
#| size : Int
#| shift : Int
#|}
#|priv enum Tree[A] {
#| Empty
#| Node(FixedArray[Tree[A]], FixedArray[Int]?) // (Subtrees, Sizes of subtrees)
#| Leaf(FixedArray[A])
#|} derive(Eq)
),
"utils.mbt": (
#|fn[T] immutable_set(arr : FixedArray[T], i : Int, v : T) -> FixedArray[T] {
#| let arr = arr.copy()
#| arr[i] = v
#| arr
#|}
#|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
#|}
#|fn shr_as_uint(x : Int, y : Int) -> Int {
#| (x.reinterpret_as_uint() >> y).reinterpret_as_int()
#|}
#|fn radix_indexing(index : Int, shift : Int) -> Int {
#| shr_as_uint(index, shift) & bitmask
#|}
#|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
#|}
#|fn copy_sizes(sizes : FixedArray[Int]?) -> FixedArray[Int]? {
#| match sizes {
#| Some(sizes) => Some(sizes.copy())
#| None => None
#| }
#|}
#|fn min(a : Int, b : Int) -> Int {
#| if a < b {
#| a
#| } else {
#| b
#| }
#|}
),
"utils_wbtest2.mbt": (
#|test "immutable_set" {
#| let arr = FixedArray::from_array([1, 2, 3, 4, 5])
#| let new_arr = immutable_set(arr, 2, 10)
#| inspect(new_arr[2], content="10")
#| inspect(arr[2], content="3") // Original array unchanged
#| inspect(new_arr.length(), content="5")
#|}
#|test "immutable_push" {
#| let arr = FixedArray::from_array([1, 2, 3])
#| let new_arr = immutable_push(arr, 4)
#| inspect(new_arr.length(), content="4")
#| inspect(new_arr[3], content="4")
#| inspect(arr.length(), content="3") // Original array unchanged
#|}
#|test "shr_as_uint" {
#| inspect(shr_as_uint(16, 2), content="4")
#| inspect(shr_as_uint(8, 1), content="4")
#| inspect(shr_as_uint(-1, 1), content="2147483647") // Handle negative numbers as unsigned
#|}
#|test "radix_indexing" {
#| inspect(radix_indexing(35, 5), content="1") // 35 >> 5 = 1, 1 & 31 = 1
#| inspect(radix_indexing(100, 5), content="3") // 100 >> 5 = 3, 3 & 31 = 3
#| inspect(radix_indexing(7, 5), content="0") // 7 >> 5 = 0, 0 & 31 = 0
#|}
#|test "get_branch_index" {
#| let sizes = FixedArray::from_array([3, 6, 10, 15])
#| inspect(get_branch_index(sizes, 2), content="0") // Index 2 is in first branch (contains indexes 0-2)
#| inspect(get_branch_index(sizes, 5), content="1") // Index 5 is in second branch (contains indexes 3-5)
#| inspect(get_branch_index(sizes, 8), content="2") // Index 8 is in third branch (contains indexes 6-9)
#|}
#|test "copy_sizes with Some" {
#| let original = FixedArray::from_array([1, 2, 3])
#| let sizes = Some(original)
#| let copied = copy_sizes(sizes)
#| match copied {
#| Some(copied_arr) => {
#| inspect(copied_arr.length(), content="3")
#| inspect(copied_arr[0], content="1")
#| inspect(copied_arr[1], content="2")
#| inspect(copied_arr[2], content="3")
#| original[0] = 100
#| inspect(copied_arr[0], content="1") // Should still be 1
#| }
#| None => inspect("Should not be None", content="error")
#| }
#|}
#|test "copy_sizes with None" {
#| let sizes : FixedArray[Int]? = None
#| let copied = copy_sizes(sizes)
#| match copied {
#| None => inspect("None copied correctly", content="None copied correctly")
#| Some(_) => inspect("Should be None", content="error")
#| }
#|}
#|test "min function" {
#| inspect(min(5, 3), content="3")
#| inspect(min(1, 10), content="1")
#| inspect(min(-5, 0), content="-5")
#| inspect(min(42, 42), content="42")
#|}
),
},
)
///|
let moonbitlang_core_immut_hashmap_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/array",
#| "moonbitlang/core/tuple",
#| "moonbitlang/core/quickcheck",
#| "moonbitlang/core/immut/internal/sparse_array",
#| "moonbitlang/core/immut/internal/path",
#| "moonbitlang/core/list"
#| ],
#| "test-import": [
#| "moonbitlang/core/int",
#| "moonbitlang/core/string",
#| "moonbitlang/core/option"
#| ]
#|}
),
"HAMT.mbt": (
#|pub fn[K, V] new() -> HashMap[K, V] {
#| None
#|}
#|pub fn[K : Hash, V] singleton(key : K, value : V) -> HashMap[K, V] {
#| Some(Flat(key, value, @path.of(key)))
#|}
#|pub fn[K : Eq + Hash, V] contains(self : HashMap[K, V], key : K) -> Bool {
#| self.get(key) is Some(_)
#|}
#|#alias(find, deprecated)
#|pub fn[K : Eq + Hash, V] get(self : HashMap[K, V], key : K) -> V? {
#| match self.0 {
#| None => None
#| Some(node) => node.get_with_path(key, @path.of(key))
#| }
#|}
#|fn[K : Eq, V] Node::get_with_path(
#| self : Node[K, V],
#| key : K,
#| path : Path,
#|) -> V? {
#| loop (self, path) {
#| (Leaf(key1, value1, bucket), _) =>
#| if key == key1 {
#| Some(value1)
#| } else {
#| bucket.lookup(key)
#| }
#| (Flat(key1, value1, path1), path) =>
#| if path == path1 && key == key1 {
#| Some(value1)
#| } else {
#| None
#| }
#| (Branch(children), path) => {
#| let idx = path.idx()
#| if children[idx] is Some(child) {
#| continue (child, path.next())
#| }
#| None
#| }
#| }
#|}
#|#deprecated("Use `get` instead. `op_get` will return `V` instead of `Option[V]` in the future.")
#|pub fn[K : Eq + Hash, V] op_get(self : HashMap[K, V], key : K) -> V? {
#| self.get(key)
#|}
#|fn[K, V] join_2(
#| key1 : K,
#| value1 : V,
#| path1 : Path,
#| key2 : K,
#| value2 : V,
#| path2 : Path,
#|) -> Node[K, V] {
#| let idx1 = path1.idx()
#| let idx2 = path2.idx()
#| if idx1 == idx2 {
#| let node = if path1.is_last() {
#| Leaf(key2, value2, @list.singleton((key1, value1)))
#| } else {
#| join_2(key1, value1, path1.next(), key2, value2, path2.next())
#| }
#| Branch(@sparse_array.singleton(idx1, node))
#| } else {
#| let (node1, node2) = if path1.is_last() {
#| (Leaf(key1, value1, @list.empty()), Leaf(key2, value2, @list.empty()))
#| } else {
#| (Flat(key1, value1, path1.next()), Flat(key2, value2, path2.next()))
#| }
#| Branch(@sparse_array.doubleton(idx1, node1, idx2, node2))
#| }
#|}
#|fn[K : Eq, V] add_with_path(
#| self : Node[K, V],
#| key : K,
#| value : V,
#| path : Path,
#|) -> Node[K, V] {
#| match self {
#| Leaf(key1, value1, bucket) =>
#| if key == key1 {
#| Leaf(key, value, bucket)
#| } else {
#| let new_bucket = match bucket.find_index(kv => kv.0 == key) {
#| None => bucket
#| Some(index) => bucket.remove_at(index)
#| }
#| Leaf(key, value, new_bucket.add((key1, value1)))
#| }
#| Flat(key1, value1, path1) =>
#| if path == path1 && key == key1 {
#| Flat(key1, value, path1)
#| } else {
#| join_2(key1, value1, path1, key, value, path)
#| }
#| Branch(children) => {
#| let idx = path.idx()
#| match children[idx] {
#| Some(child) => {
#| let child = child.add_with_path(key, value, path.next())
#| Branch(children.replace(idx, child))
#| }
#| None => {
#| let child = Flat(key, value, path.next())
#| Branch(children.add(idx, child))
#| }
#| }
#| }
#| }
#|}
#|#deprecated("Use `filter_with_key` instead. `filter` will accept `(K, V) -> Bool` in the future.")
#|#coverage.skip
#|pub fn[K, V] filter(
#| self : HashMap[K, V],
#| pred : (V) -> Bool raise?,
#|) -> HashMap[K, V] raise? {
#| self.filter_with_key((_, v) => pred(v))
#|}
#|pub fn[K, V] filter_with_key(
#| self : HashMap[K, V],
#| pred : (K, V) -> Bool raise?,
#|) -> HashMap[K, V] raise? {
#| fn go(node) raise? {
#| match node {
#| Leaf(key1, value1, bucket) => {
#| let new_bucket = bucket.filter(kv => pred(kv.0, kv.1))
#| if pred(key1, value1) {
#| Some(Leaf(key1, value1, new_bucket))
#| } else {
#| match new_bucket {
#| Empty => None
#| More((k1, v1), tail~) => Some(Leaf(k1, v1, tail))
#| }
#| }
#| }
#| Flat(key1, value1, _) =>
#| if pred(key1, value1) {
#| Some(node)
#| } else {
#| None
#| }
#| Branch(children) =>
#| match children.filter(go) {
#| None => None
#| Some(new_children) => Some(Branch(new_children))
#| }
#| }
#| }
#| match self.0 {
#| None => None
#| Some(node) => go(node)
#| }
#|}
#|#deprecated("Use `fold_with_key` instead. `fold` will accept `(A, K, V) -> A` in the future.")
#|pub fn[K, V, A] fold(
#| self : HashMap[K, V],
#| init~ : A,
#| f : (A, V) -> A raise?,
#|) -> A raise? {
#| self.fold_with_key((acc, _k, v) => f(acc, v), init~)
#|}
#|pub fn[K, V, A] fold_with_key(
#| self : HashMap[K, V],
#| init~ : A,
#| f : (A, K, V) -> A raise?,
#|) -> A raise? {
#| fn go(acc, node) raise? {
#| match node {
#| Leaf(k, v, bucket) =>
#| bucket.fold(init=f(acc, k, v), (acc, kv) => f(acc, kv.0, kv.1))
#| Flat(k, v, _) => f(acc, k, v)
#| Branch(children) => children.data.fold(init=acc, go)
#| }
#| }
#| match self.0 {
#| None => init
#| Some(node) => go(init, node)
#| }
#|}
#|#deprecated("Use `map_with_key` instead. `map` will accept `(K, V) -> A` in the future.")
#|#coverage.skip
#|pub fn[K, V, A] map(
#| self : HashMap[K, V],
#| f : (V) -> A raise?,
#|) -> HashMap[K, A] raise? {
#| self.map_with_key((_k, v) => f(v))
#|}
#|pub fn[K, V, A] map_with_key(
#| self : HashMap[K, V],
#| f : (K, V) -> A raise?,
#|) -> HashMap[K, A] raise? {
#| fn go(m : Node[K, V]) -> Node[K, A] raise? {
#| match m {
#| Leaf(k, v, bucket) =>
#| Leaf(k, f(k, v), bucket.map(kv => (kv.0, f(kv.0, kv.1))))
#| Flat(k, v, path) => Flat(k, f(k, v), path)
#| Branch(children) => Branch(children.map(go))
#| }
#| }
#| match self.0 {
#| None => None
#| Some(node) => Some(go(node))
#| }
#|}
#|pub fn[K : Eq + Hash, V] add(
#| self : HashMap[K, V],
#| key : K,
#| value : V,
#|) -> HashMap[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)))
#| }
#|}
#|pub fn[K : Eq + Hash, V] remove(self : HashMap[K, V], key : K) -> HashMap[K, V] {
#| match self.0 {
#| None => None
#| Some(node) => node.remove_with_path(key, @path.of(key))
#| }
#|}
#|fn[K : Eq, V] remove_with_path(
#| self : Node[K, V],
#| key : K,
#| path : Path,
#|) -> Node[K, V]? {
#| match self {
#| Leaf(key1, value1, bucket) =>
#| if key1 == key {
#| match bucket {
#| @list.Empty => None
#| More((key2, value2), tail~) => Some(Leaf(key2, value2, tail))
#| }
#| } else if bucket.find_index(kv => kv.0 == key) is Some(index) {
#| Some(Leaf(key1, value1, 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, value1, path1)] =>
#| Some(
#| Flat(
#| key1,
#| value1,
#| path1.push(new_children.elem_info.first_idx()),
#| ),
#| )
#| _ => Some(Branch(new_children))
#| }
#| }
#| }
#| }
#| }
#|}
#|pub fn[K, V] size(self : HashMap[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)
#| }
#|}
#|pub fn[K : Eq, V] HashMap::union(
#| self : HashMap[K, V],
#| other : HashMap[K, V],
#|) -> HashMap[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))
#| }
#|}
#|pub fn[K : Eq, V] HashMap::union_with(
#| self : HashMap[K, V],
#| other : HashMap[K, V],
#| f : (K, V, V) -> V raise?,
#|) -> HashMap[K, V] raise? {
#| fn go(node1 : Node[_], node2) raise? {
#| match (node1, node2) {
#| (_, Flat(key2, value2, path2)) => {
#| let new_value = match node1.get_with_path(key2, path2) {
#| Some(value1) => f(key2, value1, value2)
#| None => value2
#| }
#| node1.add_with_path(key2, new_value, path2)
#| }
#| (Flat(key1, value1, path1), _) => {
#| let new_value = match node2.get_with_path(key1, path1) {
#| Some(value2) => f(key1, value1, value2)
#| None => value1
#| }
#| node2.add_with_path(key1, new_value, 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))
#| kvs1.union_with(kvs2, f)
#| }
#| _ => abort("Unreachable")
#| }
#| }
#| match (self.0, other.0) {
#| (None, x) | (x, None) => x
#| (Some(a), Some(b)) => Some(go(a, b))
#| }
#|}
#|fn[K : Eq, V] @list.List::union_with(
#| self : Self[(K, V)],
#| other : Self[(K, V)],
#| f : (K, V, V) -> V raise?,
#|) -> Node[K, V] raise? {
#| let res = self.to_array()
#| for kv2 in other {
#| for i, kv1 in res {
#| if kv1.0 == kv2.0 {
#| res[i] = (kv1.0, f(kv1.0, kv1.1, kv2.1))
#| break
#| }
#| } else {
#| res.push(kv2)
#| }
#| }
#| guard @list.from_array(res) is More((k, v), tail~)
#| Leaf(k, v, tail)
#|}
#|pub fn[K : Eq, V] HashMap::intersection(
#| self : HashMap[K, V],
#| other : HashMap[K, V],
#|) -> HashMap[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)
#| }
#|}
#|pub fn[K : Eq, V] HashMap::intersection_with(
#| self : HashMap[K, V],
#| other : HashMap[K, V],
#| f : (K, V, V) -> V raise?,
#|) -> HashMap[K, V] raise? {
#| fn go(node1 : Node[_], node2) raise? {
#| match (node1, node2) {
#| (_, Flat(key2, value2, path2)) =>
#| match node1.get_with_path(key2, path2) {
#| Some(value1) => Some(Flat(key2, f(key2, value1, value2), path2))
#| None => None
#| }
#| (Flat(key1, value1, path1), _) =>
#| match node2.get_with_path(key1, path1) {
#| Some(value2) => Some(Flat(key1, f(key1, value1, 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))
#| kvs1.intersection_with(kvs2, f)
#| }
#| _ => abort("Unreachable")
#| }
#| }
#| match (self.0, other.0) {
#| (None, _) | (_, None) => None
#| (Some(a), Some(b)) => go(a, b)
#| }
#|}
#|fn[K : Eq, V] @list.List::intersection_with(
#| self : Self[(K, V)],
#| other : Self[(K, V)],
#| f : (K, V, V) -> V raise?,
#|) -> Node[K, V]? raise? {
#| let res = []
#| for kv1 in self {
#| for kv2 in other {
#| if kv1.0 == kv2.0 {
#| res.push((kv1.0, f(kv1.0, kv1.1, kv2.1)))
#| break
#| }
#| }
#| }
#| match @list.from_array(res) {
#| Empty => None
#| More((k, v), tail~) => Some(Leaf(k, v, tail))
#| }
#|}
#|pub fn[K : Eq, V] HashMap::difference(
#| self : HashMap[K, V],
#| other : HashMap[K, V],
#|) -> HashMap[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)
#| }
#|}
#|pub fn[K, V] each(
#| self : HashMap[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)
#| }
#|}
#|pub fn[K, V] keys(self : HashMap[K, V]) -> Iter[K] {
#| self.iter().map(p => p.0)
#|}
#|#alias(elems, deprecated="Use `values` instead")
#|pub fn[K, V] values(self : HashMap[K, V]) -> Iter[V] {
#| self.iter().map(p => p.1)
#|}
#|pub fn[K, V] iter(self : HashMap[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)
#| }
#|}
#|pub fn[K, V] iter2(self : HashMap[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
#| })
#|}
#|pub fn[K : Eq + Hash, V] from_iter(iter : Iter[(K, V)]) -> HashMap[K, V] {
#| iter.fold(init=new(), (m, e) => m.add(e.0, e.1))
#|}
#|pub impl[K : Show, V : Show] Show for HashMap[K, V] with output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@immut/hashmap.of([", suffix="])")
#|}
#|pub fn[K : Eq + Hash, V] from_array(arr : Array[(K, V)]) -> HashMap[K, V] {
#| loop (arr.length(), new()) {
#| (0, map) => map
#| (n, map) => {
#| let (k, v) = arr[n - 1]
#| continue (n - 1, map.add(k, v))
#| }
#| }
#|}
#|pub fn[K, V] to_array(self : HashMap[K, V]) -> Array[(K, V)] {
#| let arr = Array::new(capacity=self.size())
#| self.each((k, v) => arr.push((k, v)))
#| arr
#|}
#|pub impl[K : Eq + Hash + @quickcheck.Arbitrary, V : @quickcheck.Arbitrary] @quickcheck.Arbitrary for HashMap[
#| K,
#| V,
#|] with arbitrary(size, rs) {
#| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array
#|}
#|pub fn[K : Eq + Hash, V] of(arr : FixedArray[(K, V)]) -> HashMap[K, V] {
#| loop (arr.length(), new()) {
#| (0, map) => map
#| (n, map) => {
#| let (k, v) = arr[n - 1]
#| continue (n - 1, map.add(k, v))
#| }
#| }
#|}
#|impl[K : Eq, V : Eq] Eq for Node[K, V] with equal(self, other) {
#| match (self, other) {
#| (Flat(key1, value1, path1), Flat(key2, value2, path2)) =>
#| path1 == path2 && key1 == key2 && value1 == value2
#| (Branch(children1), Branch(children2)) => children1 == children2
#| (Leaf(key1, value1, bucket1), Leaf(key2, value2, bucket2)) => {
#| guard bucket1.length() == bucket2.length() else { return false }
#| let kvs1 = bucket1.add((key1, value1))
#| let kvs2 = bucket2.add((key2, value2))
#| kvs1.all(kv => kvs2.lookup(kv.0) is Some(v) && kv.1 == v)
#| }
#| _ => false
#| }
#|}
#|pub impl[K : Hash, V : Hash] Hash for HashMap[K, V] with hash_combine(
#| self,
#| hasher,
#|) {
#| hasher.combine(self.fold_with_key(init=0, (acc, k, v) => acc ^ (k, v).hash()))
#|}
),
"deprecated.mbt": "",
"types.mbt": (
#|typealias @path.Path
#|priv enum Node[K, V] {
#| Flat(K, V, Path)
#| Leaf(K, V, @list.List[(K, V)]) // use a list of buckets to resolve collision
#| Branch(@sparse_array.SparseArray[Node[K, V]])
#|}
#|struct HashMap[K, V](Node[K, V]?) derive(Eq)
#|#deprecated("Use `HashMap` instead of `T`")
#|pub typealias HashMap as T
),
},
)
///|
let moonbitlang_core_immut_hashset_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/array",
#| "moonbitlang/core/immut/internal/sparse_array",
#| "moonbitlang/core/quickcheck",
#| "moonbitlang/core/immut/internal/path",
#| "moonbitlang/core/list"
#| ],
#| "test-import": ["moonbitlang/core/string", "moonbitlang/core/int"]
#|}
),
"HAMT.mbt": (
#|pub fn[A] new() -> HashSet[A] {
#| None
#|}
#|pub fn[A : Eq + Hash] contains(self : HashSet[A], key : A) -> Bool {
#| self.0 is Some(node) && node.contains(key, @path.of(key))
#|}
#|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
#| }
#| }
#|}
#|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))
#| }
#|}
#|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))
#| }
#| }
#| }
#| }
#|}
#|pub fn[A : Eq + Hash] add(self : HashSet[A], key : A) -> HashSet[A] {
#| match self.0 {
#| None => Some(Flat(key, @path.of(key)))
#| Some(node) => Some(node.add_with_path(key, @path.of(key)))
#| }
#|}
#|pub fn[A : Eq + Hash] remove(self : HashSet[A], key : A) -> HashSet[A] {
#| match self.0 {
#| None => None
#| Some(node) => node.remove_with_path(key, @path.of(key))
#| }
#|}
#|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))
#| }
#| }
#| }
#| }
#| }
#|}
#|pub fn[A] size(self : HashSet[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)
#| }
#|}
#|pub fn[K : Eq] HashSet::union(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> HashSet[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))
#| }
#|}
#|pub fn[K : Eq] HashSet::intersection(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> HashSet[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)
#| }
#|}
#|pub fn[K : Eq] HashSet::difference(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> HashSet[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)
#| }
#|}
#|pub fn[A] is_empty(self : HashSet[A]) -> Bool {
#| self.0 is None
#|}
#|pub fn[A] each(self : HashSet[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)
#| }
#|}
#|pub fn[A] iter(self : HashSet[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)
#| }
#|}
#|pub fn[A : Eq + Hash] from_iter(iter : Iter[A]) -> HashSet[A] {
#| iter.fold(init=new(), (s, e) => s.add(e))
#|}
#|pub impl[A : Show] Show for HashSet[A] with output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@immut/hashset.of([", suffix="])")
#|}
#|pub fn[A : Eq + Hash] from_array(arr : Array[A]) -> HashSet[A] {
#| loop (arr.length(), new()) {
#| (0, set) => set
#| (n, set) => {
#| let k = arr[n - 1]
#| continue (n - 1, set.add(k))
#| }
#| }
#|}
#|pub fn[A : Eq + Hash] of(arr : FixedArray[A]) -> HashSet[A] {
#| loop (arr.length(), new()) {
#| (0, set) => set
#| (n, set) => {
#| let k = arr[n - 1]
#| continue (n - 1, set.add(k))
#| }
#| }
#|}
#|pub impl[A : Hash] Hash for HashSet[A] with hash_combine(self, hasher) {
#| hasher.combine(self.iter().fold(init=0, (x, y) => x ^ y.hash()))
#|}
#|impl[A : Eq] Eq for Node[A] with equal(self, other) {
#| match (self, other) {
#| (Leaf(x, xs), Leaf(y, ys)) =>
#| xs.length() == ys.length() &&
#| {
#| let keys1 = xs.add(x)
#| let keys2 = ys.add(y)
#| keys1.iter().all(keys2.contains(_))
#| }
#| (Flat(x, pathx), Flat(y, pathy)) => pathx == pathy && x == y
#| (Branch(xs), Branch(ys)) => xs == ys
#| _ => false
#| }
#|}
#|pub impl[K : Eq + Hash + @quickcheck.Arbitrary] @quickcheck.Arbitrary for HashSet[
#| K,
#|] with arbitrary(size, rs) {
#| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array
#|}
#|test "hash" {
#| assert_eq(Hash::hash(of([1, 2, 3, 4])), Hash::hash(of([3, 2]).add(1).add(4)))
#| assert_not_eq(Hash::hash(of([1, 2, 3])), Hash::hash(of([1, 2, 4])))
#|}
#|test "eq" {
#| assert_eq(of([1, 2, 3, 4]), of([3, 2]).add(1).add(4))
#| assert_not_eq(of([1, 2, 3]), of([1, 2, 4]))
#|}
),
"types.mbt": (
#|typealias @path.Path
#|priv enum Node[A] {
#| Flat(A, Path)
#| Leaf(A, @list.List[A]) // use a list of buckets to resolve collision
#| Branch(@sparse_array.SparseArray[Node[A]])
#|}
#|struct HashSet[A](Node[A]?) derive(Eq)
#|#deprecated("Use `Set` instead of `T`")
#|pub typealias HashSet as T
),
},
)
///|
let moonbitlang_core_immut_internal_path_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/internal/path",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin"]
#|}
),
"path.mbt": (
#|pub(all) struct Path(UInt) derive(Eq)
#|const SEGMENT_LENGTH : Int = 5
#|const INDEX_MASK : UInt = (1 << SEGMENT_LENGTH) - 1
#|const SEGMENT_NUM : Int = 32 / SEGMENT_LENGTH
#|const HEAD_TAG : UInt = 0xffffffffU << (SEGMENT_LENGTH * SEGMENT_NUM)
#|pub fn[A : Hash] of(key : A) -> Path {
#| key.hash().reinterpret_as_uint() | HEAD_TAG
#|}
#|const MAX_TAIL : UInt = 0xffffffffU >> (SEGMENT_LENGTH * (SEGMENT_NUM - 1))
#|pub fn Path::is_last(self : Path) -> Bool {
#| let Path(self) = self
#| self <= MAX_TAIL
#|}
#|pub fn Path::push(self : Path, idx : Int) -> Path {
#| let Path(self) = self
#| (self << SEGMENT_LENGTH) | idx.reinterpret_as_uint()
#|}
#|pub fn Path::idx(self : Path) -> Int {
#| let Path(self) = self
#| (self & INDEX_MASK).reinterpret_as_int()
#|}
#|pub fn Path::next(self : Path) -> Path {
#| let Path(self) = self
#| self >> SEGMENT_LENGTH
#|}
),
},
)
///|
let moonbitlang_core_immut_internal_sparse_array_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/internal/sparse_array",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/array": moonbitlang_core_array_module,
},
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin", "moonbitlang/core/array"]
#|}
),
"bitset.mbt": (
#|pub(all) struct Bitset(UInt) derive(Eq)
#|let empty_bitset : Bitset = Bitset(0)
#|pub fn Bitset::has(self : Bitset, idx : Int) -> Bool {
#| (self.0 & (1U << idx)) != 0
#|}
#|pub fn Bitset::index_of(self : Bitset, idx : Int) -> Int {
#| (self.0 & ((1U << idx) - 1)).popcnt()
#|}
#|pub fn Bitset::first_idx(self : Bitset) -> Int {
#| self.0.ctz()
#|}
#|pub fn Bitset::union(self : Bitset, other : Bitset) -> Bitset {
#| Bitset(self.0 | other.0)
#|}
#|pub fn Bitset::intersection(self : Bitset, other : Bitset) -> Bitset {
#| Bitset(self.0 & other.0)
#|}
#|pub fn Bitset::add(self : Bitset, idx : Int) -> Bitset {
#| Bitset(self.0 | (1U << idx))
#|}
#|pub fn Bitset::remove(self : Bitset, idx : Int) -> Bitset {
#| Bitset(self.0 ^ (1U << idx))
#|}
#|pub fn Bitset::size(self : Bitset) -> Int {
#| let Bitset(self) = self
#| self.popcnt()
#|}
#|test "Bitset::has" {
#| let b = empty_bitset.add(2)
#| inspect(b.has(0), content="false")
#| inspect(b.has(2), content="true")
#| let b = b.add(0)
#| inspect(b.has(0), content="true")
#| inspect(b.has(2), content="true")
#|}
#|test "Bitset::index_of" {
#| let b = empty_bitset.add(2)
#| inspect(b.index_of(2), content="0")
#| let b = b.add(0)
#| inspect(b.index_of(2), content="1")
#| let b = b.add(5)
#| inspect(b.index_of(2), content="1")
#| inspect(b.index_of(3), content="2")
#| inspect(b.index_of(4), content="2")
#| inspect(b.index_of(5), content="2")
#| inspect(b.index_of(6), content="3")
#|}
#|test "Bitset::union" {
#| let b1 = empty_bitset.add(2).add(3)
#| let b2 = empty_bitset.add(0).add(1)
#| let b3 = b1.union(b2)
#| inspect(b3.has(0), content="true")
#| inspect(b3.has(1), content="true")
#| inspect(b3.has(2), content="true")
#| inspect(b3.has(3), content="true")
#|}
#|test "Bitset::intersection" {
#| let b1 = empty_bitset.add(2).add(3)
#| let b2 = empty_bitset.add(0).add(1).add(2)
#| let b3 = b1.intersection(b2)
#| inspect(b3.has(0), content="false")
#| inspect(b3.has(1), content="false")
#| inspect(b3.has(2), content="true")
#| inspect(b3.has(3), content="false")
#|}
#|test "Bitset::remove" {
#| let b = empty_bitset.add(2).add(3)
#| inspect(b.has(2), content="true")
#| inspect(b.has(3), content="true")
#| inspect(b.index_of(2), content="0")
#| inspect(b.index_of(3), content="1")
#| let b = b.remove(2)
#| inspect(b.has(2), content="false")
#| inspect(b.has(3), content="true")
#| inspect(b.index_of(3), content="0")
#|}
#|test "Bitset::remove" {
#| let b = empty_bitset.add(2).add(3)
#| inspect(b.has(2), content="true")
#| inspect(b.has(3), content="true")
#| inspect(b.index_of(2), content="0")
#| inspect(b.index_of(3), content="1")
#| let b = b.remove(2)
#| inspect(b.has(2), content="false")
#| inspect(b.has(3), content="true")
#| inspect(b.index_of(3), content="0")
#|}
#|test "Bitset::size" {
#| let b = empty_bitset
#| inspect(b.size(), content="0")
#| let b = b.add(0)
#| inspect(b.size(), content="1")
#| let b = b.add(1)
#| inspect(b.size(), content="2")
#| let b = b.add(1)
#| inspect(b.size(), content="2")
#|}
#|test "Bitset::ctpop" {
#| inspect(
#| ([0, 0xf0f0f0f0, 0x3c3c0ff0] : Array[_]).map(x => x.popcnt()),
#| content="[0, 16, 16]",
#| )
#|}
),
"sparse_array.mbt": (
#|pub(all) struct SparseArray[X] {
#| elem_info : Bitset
#| data : FixedArray[X]
#|} derive(Eq)
#|pub fn[X] empty() -> SparseArray[X] {
#| { elem_info: empty_bitset, data: [] }
#|}
#|pub fn[X] singleton(idx : Int, value : X) -> SparseArray[X] {
#| { elem_info: empty_bitset.add(idx), data: [value] }
#|}
#|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
#| }
#|}
#|fn[X] unsafe_get(self : SparseArray[X], idx : Int) -> X {
#| self.data[self.elem_info.index_of(idx)]
#|}
#|pub fn[X] doubleton(
#| idx1 : Int,
#| value1 : X,
#| idx2 : Int,
#| value2 : X,
#|) -> SparseArray[X] {
#| {
#| elem_info: empty_bitset.add(idx1).add(idx2),
#| data: if idx1 < idx2 {
#| [value1, value2]
#| } else {
#| [value2, value1]
#| },
#| }
#|}
#|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 }
#|}
#|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 }
#|}
#|pub fn[X] SparseArray::union(
#| self : SparseArray[X],
#| other : SparseArray[X],
#| f : (X, X) -> X raise?,
#|) -> SparseArray[X] raise? {
#| let union_elem_info = self.elem_info.union(other.elem_info)
#| let data = FixedArray::make(union_elem_info.size(), self.data[0])
#| for rest = union_elem_info, index = 0; rest != empty_bitset; {
#| let idx = rest.first_idx()
#| data[index] = match self[idx] {
#| None => other.unsafe_get(idx)
#| Some(value1) =>
#| match other[idx] {
#| None => value1
#| Some(value2) => f(value1, value2)
#| }
#| }
#| continue rest.remove(idx), index + 1
#| }
#| { elem_info: union_elem_info, data }
#|}
#|fn[A] FixedArray::copy_prefix(
#| self : FixedArray[A],
#| len~ : Int,
#|) -> FixedArray[A] {
#| let res = FixedArray::make(len, self[0])
#| FixedArray::unsafe_blit(res, 0, self, 0, len)
#| res
#|}
#|pub fn[X] SparseArray::intersection(
#| self : SparseArray[X],
#| other : SparseArray[X],
#| f : (X, X) -> X? raise?,
#|) -> SparseArray[X]? raise? {
#| let inter_elem_info = self.elem_info.intersection(other.elem_info)
#| guard inter_elem_info != 0 else { return None }
#| let data = FixedArray::make(inter_elem_info.size(), self.data[0])
#| for rest = inter_elem_info, index = 0, elem_info = inter_elem_info; rest != 0; {
#| let idx = rest.first_idx()
#| match f(self.unsafe_get(idx), other.unsafe_get(idx)) {
#| Some(value) => {
#| data[index] = value
#| continue rest.remove(idx), index + 1, elem_info
#| }
#| None => continue rest.remove(idx), index, elem_info.remove(idx)
#| }
#| } else {
#| if elem_info == empty_bitset {
#| None
#| } else if elem_info == inter_elem_info {
#| Some({ elem_info, data })
#| } else {
#| Some({ elem_info, data: data.copy_prefix(len=index) })
#| }
#| }
#|}
#|pub fn[X] SparseArray::difference(
#| self : SparseArray[X],
#| other : SparseArray[X],
#| f : (X, X) -> X?,
#|) -> SparseArray[X]? {
#| let self_elem_info = self.elem_info
#| let data = FixedArray::make(self_elem_info.size(), self.data[0])
#| for rest = self_elem_info, index = 0, elem_info = self_elem_info; rest !=
#| empty_bitset; {
#| let idx = rest.first_idx()
#| match other[idx] {
#| None => {
#| data[index] = self.unsafe_get(idx)
#| continue rest.remove(idx), index + 1, elem_info
#| }
#| Some(value2) =>
#| match f(self.unsafe_get(idx), value2) {
#| None => continue rest.remove(idx), index, elem_info.remove(idx)
#| Some(v) => {
#| data[index] = v
#| continue rest.remove(idx), index + 1, elem_info
#| }
#| }
#| }
#| } else {
#| if elem_info == empty_bitset {
#| None
#| } else if elem_info == self_elem_info {
#| Some({ elem_info, data })
#| } else {
#| Some({ elem_info, data: data.copy_prefix(len=index) })
#| }
#| }
#|}
#|pub fn[X, Y] SparseArray::map(
#| self : SparseArray[X],
#| f : (X) -> Y raise?,
#|) -> SparseArray[Y] raise? {
#| { elem_info: self.elem_info, data: self.data.map(f) }
#|}
#|pub fn[X] SparseArray::filter(
#| self : SparseArray[X],
#| pred : (X) -> X? raise?,
#|) -> SparseArray[X]? raise? {
#| let self_elem_info = self.elem_info
#| let data = FixedArray::make(self_elem_info.size(), self.data[0])
#| for rest = self_elem_info, index = 0, elem_info = self_elem_info; rest !=
#| empty_bitset; {
#| let idx = rest.first_idx()
#| match pred(self.unsafe_get(idx)) {
#| None => continue rest.remove(idx), index, elem_info.remove(idx)
#| Some(v) => {
#| data[index] = v
#| continue rest.remove(idx), index + 1, elem_info
#| }
#| }
#| } else {
#| if elem_info == empty_bitset {
#| None
#| } else if elem_info == self_elem_info {
#| Some({ elem_info, data })
#| } else {
#| Some({ elem_info, data: data.copy_prefix(len=index) })
#| }
#| }
#|}
#|pub fn[X] replace(
#| self : SparseArray[X],
#| idx : Int,
#| value : X,
#|) -> SparseArray[X] {
#| let new_data = self.data.copy()
#| new_data[self.elem_info.index_of(idx)] = value
#| { elem_info: self.elem_info, data: new_data }
#|}
#|pub fn[X] size(self : SparseArray[X]) -> Int {
#| self.data.length()
#|}
#|pub fn[X] each(self : SparseArray[X], f : (X) -> Unit raise?) -> Unit raise? {
#| for i in 0.. T[A] raise @json.JsonDecodeError {
#| @json.from_json(json)
#|}
#|#deprecated
#|#coverage.skip
#|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)
#|}
#|#deprecated("use `==` instead")
#|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
#| }
#|}
#|#deprecated("use `@immut/list.from_array` instead")
#|#coverage.skip
#|pub fn[A] T::from_array(arr : Array[A]) -> T[A] {
#| from_array(arr)
#|}
#|#deprecated("use `@immut/list.default` instead")
#|#coverage.skip
#|pub fn[X] T::default() -> T[X] {
#| Nil
#|}
#|#deprecated("use `@immut/list.from_iter` instead")
#|#coverage.skip
#|pub fn[A] T::from_iter(iter : Iter[A]) -> T[A] {
#| from_iter(iter)
#|}
#|#deprecated("use `@immut/list.of` instead")
#|#coverage.skip
#|pub fn[A] T::of(arr : FixedArray[A]) -> T[A] {
#| of(arr)
#|}
),
"list.mbt": (
#|#deprecated("use `@list` instead")
#|pub fn[A] add(self : T[A], head : A) -> T[A] {
#| Cons(head, self)
#|}
#|pub impl[A : Show] Show for T[A] with output(xs, logger) {
#| logger.write_iter(xs.iter(), prefix="@list.of([", suffix="])")
#|}
#|pub impl[A : ToJson] ToJson for T[A] with to_json(self) {
#| let capacity = self.length()
#| guard capacity != 0 else { return [] }
#| let jsons = Array::new(capacity~)
#| for a in self {
#| jsons.push(a.to_json())
#| }
#| Json::array(jsons)
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A : ToJson] to_json(self : T[A]) -> Json {
#| ToJson::to_json(self)
#|}
#|pub impl[A : @json.FromJson] @json.FromJson for T[A] with from_json(json, path) {
#| guard json is Array(arr) else {
#| raise @json.JsonDecodeError((path, "@immut/list.from_json: expected array"))
#| }
#| for i = arr.length() - 1, list = Nil; i >= 0; {
#| continue i - 1, list.add(A::from_json(arr[i], path.add_index(i)))
#| } else {
#| list
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A : @json.FromJson] from_json(
#| json : Json,
#|) -> T[A] raise @json.JsonDecodeError {
#| @json.from_json(json)
#|}
#|#deprecated("use `@list` instead")
#|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
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] length(self : T[A]) -> Int {
#| loop (self, 0) {
#| (Nil, len) => len
#| (Cons(_, rest), acc) => continue (rest, acc + 1)
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] each(self : T[A], f : (A) -> Unit raise?) -> Unit raise? {
#| loop self {
#| Nil => ()
#| Cons(head, tail) => {
#| f(head)
#| continue tail
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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)
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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))
#| }
#|}
#|#deprecated("use `@list` instead")
#|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)
#|}
#|#deprecated("use `@list` instead")
#|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)
#| }
#|}
#|#deprecated("use `@list` instead")
#|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
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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)
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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 }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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)
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] tail(self : T[A]) -> T[A] {
#| match self {
#| Nil => Nil
#| Cons(_, tail) => tail
#| }
#|}
#|#internal(unsafe, "Panic if the list is empty")
#|#deprecated("use `@list` instead")
#|pub fn[A] unsafe_head(self : T[A]) -> A {
#| match self {
#| Nil => abort("head of empty list")
#| Cons(head, _) => head
#| }
#|}
#|#coverage.skip
#|#deprecated("use `@list` instead")
#|pub fn[A] head_exn(self : T[A]) -> A {
#| self.unsafe_head()
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] head(self : T[A]) -> A? {
#| match self {
#| Nil => None
#| Cons(head, _) => Some(head)
#| }
#|}
#|#internal(unsafe, "Panic if the list is empty")
#|#deprecated("use `@list` instead")
#|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
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] last(self : T[A]) -> A? {
#| loop self {
#| Nil => None
#| Cons(head, Nil) => Some(head)
#| Cons(_, tail) => continue tail
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] concat(self : T[A], other : T[A]) -> T[A] {
#| match self {
#| Nil => other
#| Cons(head, tail) => Cons(head, tail.concat(other))
#| }
#|}
#|#deprecated("use `@list` instead")
#|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))
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] rev(self : T[A]) -> T[A] {
#| self.rev_concat(Nil)
#|}
#|#deprecated("use `@list` instead")
#|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))
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A, B] rev_fold(
#| self : T[A],
#| init~ : B,
#| f : (A, B) -> B raise?,
#|) -> B raise? {
#| let xs = self.to_array()
#| let mut acc = init
#| for x in xs.rev_iter() {
#| acc = f(x, acc)
#| }
#| acc
#|}
#|#coverage.skip
#|#deprecated("use `@list` instead")
#|pub fn[A, B] fold_left(
#| self : T[A],
#| f : (B, A) -> B raise?,
#| init~ : B,
#|) -> B raise? {
#| self.fold(init~, f)
#|}
#|#coverage.skip
#|#deprecated("use `@list.rev_fold` instead")
#|pub fn[A, B] fold_right(
#| self : T[A],
#| f : (A, B) -> B raise?,
#| init~ : B,
#|) -> B raise? {
#| match self {
#| Nil => init
#| Cons(head, tail) => f(head, tail.rev_fold(f, init~))
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A, B] foldi(
#| self : T[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| fn go(xs : T[A], i : Int, f : (Int, B, A) -> B raise?, acc : B) -> B raise? {
#| match xs {
#| Nil => acc
#| Cons(x, xs) => go(xs, i + 1, f, f(i, acc, x))
#| }
#| }
#| go(self, 0, f, init)
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A, B] rev_foldi(
#| self : T[A],
#| init~ : B,
#| f : (Int, A, B) -> B raise?,
#|) -> B raise? {
#| fn go(xs : T[A], i : Int, f : (Int, A, B) -> B raise?, acc : B) -> B raise? {
#| match xs {
#| Nil => acc
#| Cons(x, xs) => f(i, x, go(xs, i + 1, f, acc))
#| }
#| }
#| go(self, 0, f, init)
#|}
#|#deprecated("use `@list.foldi` instead")
#|pub fn[A, B] fold_lefti(
#| self : T[A],
#| f : (Int, B, A) -> B raise?,
#| init~ : B,
#|) -> B raise? {
#| fn go(xs : T[A], i : Int, f : (Int, B, A) -> B raise?, acc : B) -> B raise? {
#| match xs {
#| Nil => acc
#| Cons(x, xs) => go(xs, i + 1, f, f(i, acc, x))
#| }
#| }
#| go(self, 0, f, init)
#|}
#|#deprecated("use `@list.rev_foldi` instead")
#|pub fn[A, B] fold_righti(
#| self : T[A],
#| f : (Int, A, B) -> B raise?,
#| init~ : B,
#|) -> B raise? {
#| fn go(xs : T[A], i : Int, f : (Int, A, B) -> B raise?, acc : B) -> B raise? {
#| match xs {
#| Nil => acc
#| Cons(x, xs) => f(i, x, go(xs, i + 1, f, acc))
#| }
#| }
#| go(self, 0, f, init)
#|}
#|#deprecated("use `@list` instead")
#|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)
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A, B] concat_map(self : T[A], f : (A) -> T[B]) -> T[B] {
#| self.flat_map(f)
#|}
#|#deprecated("use `@list` instead")
#|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))
#| }
#|}
#|#deprecated("use `@list` instead")
#|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)
#| }
#| }
#|}
#|#internal(unsafe, "Panic if the index is out of bounds")
#|#deprecated("use `@list` instead")
#|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)
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] nth_exn(self : T[A], n : Int) -> A {
#| self.unsafe_nth(n)
#|}
#|#deprecated("use `@list` instead")
#|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)
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] repeat(n : Int, x : A) -> T[A] {
#| if n == 0 {
#| Nil
#| } else {
#| Cons(x, repeat(n - 1, x))
#| }
#|}
#|#deprecated("use `@list` instead")
#|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)))
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] is_empty(self : T[A]) -> Bool {
#| self is Nil
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A, B] unzip(self : T[(A, B)]) -> (T[A], T[B]) {
#| let mut xs = Nil
#| let mut ys = Nil
#| loop self.rev() {
#| Nil => break (xs, ys)
#| Cons((x, y), tail) => {
#| xs = Cons(x, xs)
#| ys = Cons(y, ys)
#| continue tail
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] flatten(self : T[T[A]]) -> T[A] {
#| match self {
#| Nil => Nil
#| Cons(head, tail) => head.concat(tail.flatten())
#| }
#|}
#|#internal(unsafe, "Panic if the list is empty")
#|#deprecated("use `@list` instead")
#|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
#| }
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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 })
#| }
#| }
#|}
#|#internal(unsafe, "Panic if the list is empty")
#|#deprecated("use `@list` instead")
#|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
#| }
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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 })
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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()))
#| }
#| }
#|}
#|pub impl[A] Add for T[A] with add(self, other) {
#| self.concat(other)
#|}
#|#deprecated("use `@list` instead")
#|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 }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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
#| }
#|}
#|#deprecated("use `@list` instead")
#|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)
#| }
#|}
#|#deprecated("use `@list` instead")
#|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)
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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 }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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) }
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A, E] scan_left(
#| self : T[A],
#| f : (E, A) -> E raise?,
#| init~ : E,
#|) -> T[E] raise? {
#| Cons(
#| init,
#| match self {
#| Nil => Nil
#| Cons(x, xs) => xs.scan_left(f, init=f(init, x))
#| },
#| )
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A, B] scan_right(
#| self : T[A],
#| f : (A, B) -> B raise?,
#| init~ : B,
#|) -> T[B] raise? {
#| match self {
#| Nil => Cons(init, Nil)
#| Cons(x, xs) => {
#| let qs = xs.scan_right(f, init~)
#| Cons(f(x, qs.unsafe_head()), qs)
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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 }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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)
#| }
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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
#| }
#|}
#|#deprecated("use `@list` instead")
#|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))
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|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
#| }
#| }
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A : Eq] is_suffix(self : T[A], suffix : T[A]) -> Bool {
#| self.rev().is_prefix(suffix.rev())
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] intercalate(self : T[T[A]], sep : T[A]) -> T[A] {
#| self.intersperse(sep).flatten()
#|}
#|pub impl[X] Default for T[X] with default() {
#| Nil
#|}
#|#deprecated("use `@list` instead")
#|pub fn[X] default() -> T[X] {
#| Nil
#|}
#|#deprecated("use `@list` instead")
#|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
#| }
#| })
#|}
#|#deprecated("use `@list` instead")
#|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)
#| }
#| })
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] from_iter(iter : Iter[A]) -> T[A] {
#| iter.fold(init=Nil, (acc, e) => Cons(e, acc)).rev()
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] from_iter_rev(iter : Iter[A]) -> T[A] {
#| iter.fold(init=Nil, (acc, e) => Cons(e, acc))
#|}
#|#deprecated("use `@list` instead")
#|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
#| }
#|}
#|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for T[X] with arbitrary(
#| size,
#| rs,
#|) {
#| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array
#|}
#|#deprecated("use `@list` instead")
#|pub fn[A] singleton(x : A) -> T[A] {
#| Cons(x, Nil)
#|}
#|pub impl[A : Hash] Hash for T[A] with hash_combine(self, hasher) {
#| for e in self {
#| hasher.combine(e)
#| }
#|}
#|pub impl[A : Compare] Compare for T[A] with compare(self, other) {
#| loop (self, other) {
#| (Nil, Nil) => 0
#| (Nil, Cons(_, _)) => -1
#| (Cons(_, _), Nil) => 1
#| (Cons(x, xs), Cons(y, ys)) => {
#| let cmp = x.compare(y)
#| if cmp != 0 {
#| break cmp
#| } else {
#| continue (xs, ys)
#| }
#| }
#| }
#|}
),
"types.mbt": (
#|#deprecated("use `@list` instead")
#|pub(all) enum T[A] {
#| Nil
#| Cons(A, T[A])
#|} derive(Eq)
),
},
)
///|
let moonbitlang_core_immut_priority_queue_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/array",
#| "moonbitlang/core/quickcheck"
#| ],
#| "test-import": ["moonbitlang/core/random", "moonbitlang/core/json"],
#| "targets": {
#| "panic_test.mbt": ["not", "native", "llvm"]
#| }
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `unsafe_pop` instead")
#|#coverage.skip
#|pub fn[A : Compare] pop_exn(self : PriorityQueue[A]) -> PriorityQueue[A] {
#| self.unsafe_pop()
#|}
),
"priority_queue.mbt": (
#|pub fn[A] new() -> PriorityQueue[A] {
#| { node: Empty, size: 0 }
#|}
#|pub fn[A : Compare] from_array(array : Array[A]) -> PriorityQueue[A] {
#| let mut pq = new()
#| for i in 0.. Array[A] {
#| let arr : Array[A] = []
#| let stack : Array[Node[A]] = [self.node]
#| while stack.pop() is Some(node) {
#| match node {
#| Empty => ()
#| Leaf(a) => arr.push(a)
#| Branch(a, left=l, right=r) => {
#| arr.push(a)
#| stack.push(l)
#| stack.push(r)
#| }
#| }
#| }
#| arr.sort()
#| arr.rev_inplace()
#| arr
#|}
#|pub fn[A : Compare] iter(self : PriorityQueue[A]) -> Iter[A] {
#| Iter::new(yield_ => {
#| let arr = self.to_array()
#| for i in 0.. PriorityQueue[A] {
#| iter.fold(init=new(), (s, e) => s.push(e))
#|}
#|priv struct Path(Int)
#|fn path(size : Int) -> Path {
#| loop (size, 0) {
#| (1, y) => Path(y)
#| (x, y) => continue (x >> 1, (y << 1) | (x & 1))
#| }
#|}
#|fn is_left(self : Path) -> Bool {
#| (self.0 & 1) == 0
#|}
#|fn next(self : Path) -> Path {
#| Path(self.0 >> 1)
#|}
#|pub fn[A : Compare] pop(self : PriorityQueue[A]) -> PriorityQueue[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 })
#| }
#| }
#|}
#|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))
#| }
#| }
#|}
#|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")
#| }
#| }
#|}
#|#internal(unsafe, "Panics if the queue is empty.")
#|pub fn[A : Compare] unsafe_pop(self : PriorityQueue[A]) -> PriorityQueue[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 }
#| }
#| }
#|}
#|pub fn[A : Compare] push(
#| self : PriorityQueue[A],
#| value : A,
#|) -> PriorityQueue[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 }
#| }
#| }
#|}
#|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()))
#| }
#| }
#| }
#|}
#|pub fn[A] peek(self : PriorityQueue[A]) -> A? {
#| match self.node {
#| Empty => None
#| Leaf(a) => Some(a)
#| Branch(a, ..) => Some(a)
#| }
#|}
#|pub fn[A] is_empty(self : PriorityQueue[A]) -> Bool {
#| self.node is Empty
#|}
#|pub fn[A] length(self : PriorityQueue[A]) -> Int {
#| self.size
#|}
#|pub fn[A : Compare] of(arr : FixedArray[A]) -> PriorityQueue[A] {
#| let mut pq = new()
#| for i in 0.. from_array
#|}
#|pub impl[A : Compare] Eq for PriorityQueue[A] with equal(self, other) {
#| self.length() == other.length() && self.to_array() == other.to_array()
#|}
#|pub impl[A : Hash + Compare] Hash for PriorityQueue[A] with hash_combine(
#| self,
#| hasher,
#|) {
#| for e in self {
#| hasher.combine(e)
#| }
#|}
#|pub impl[A : Compare] Compare for PriorityQueue[A] with compare(self, other) {
#| let len_cmp = self.length().compare(other.length())
#| if len_cmp != 0 {
#| return len_cmp
#| }
#| let self_arr = self.to_array()
#| let other_arr = other.to_array()
#| for i in 0.. SortedMap[K, V] {
#| Empty
#|}
#|#deprecated("use `@immut/sorted_map.singleton` instead")
#|#coverage.skip
#|pub fn[K, V] SortedMap::singleton(key : K, value : V) -> SortedMap[K, V] {
#| singleton(key, value)
#|}
#|#deprecated("use `@immut/sorted_map.from_array` instead")
#|#coverage.skip
#|pub fn[K : Compare, V] SortedMap::from_array(
#| array : Array[(K, V)],
#|) -> SortedMap[K, V] {
#| from_array(array)
#|}
#|#deprecated("use `@immut/sorted_map.from_iter` instead")
#|#coverage.skip
#|pub fn[K : Compare, V] SortedMap::from_iter(
#| iter : Iter[(K, V)],
#|) -> SortedMap[K, V] {
#| from_iter(iter)
#|}
#|#deprecated("use `@immut/sorted_map.of` instead")
#|#coverage.skip
#|pub fn[K : Compare, V] SortedMap::of(
#| array : FixedArray[(K, V)],
#|) -> SortedMap[K, V] {
#| of(array)
#|}
#|#deprecated("use `@immut/sorted_map.from_json` instead")
#|#coverage.skip
#|pub fn[V : @json.FromJson] SortedMap::from_json(
#| json : Json,
#|) -> SortedMap[String, V] raise @json.JsonDecodeError {
#| @json.from_json(json)
#|}
),
"inorder_iterator.mbt": (
#|priv struct InorderIterator[K, V](Array[SortedMap[K, V]])
#|fn[K, V] InorderIterator::new(root : SortedMap[K, V]) -> InorderIterator[K, V] {
#| let it = InorderIterator([])
#| it.move_left(root)
#| it
#|}
#|fn[K, V] InorderIterator::move_left(
#| self : InorderIterator[K, V],
#| node : SortedMap[K, V],
#|) -> Unit {
#| loop node {
#| Empty => ()
#| Tree(_, left, _, ..) as curr => {
#| let InorderIterator(self) = self
#| self.push(curr)
#| continue left
#| }
#| }
#|}
#|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))
#|}
#|test "InorderIterator" {
#| let arr = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7)]
#| let set = from_array(arr)
#| let iter = InorderIterator::new(set)
#| for i = 0; ; i = i + 1 {
#| match iter.next() {
#| None => break
#| Some(value) => assert_eq(value, arr[i])
#| }
#| }
#|}
),
"map.mbt": (
#|#alias(insert, deprecated)
#|pub fn[K : Compare, V] add(
#| self : SortedMap[K, V],
#| key : K,
#| value : V,
#|) -> SortedMap[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))
#| }
#| }
#| }
#|}
#|fn[K : Compare, V] split_max(self : SortedMap[K, V]) -> (K, V, SortedMap[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")
#| }
#|}
#|fn[K : Compare, V] split_min(self : SortedMap[K, V]) -> (K, V, SortedMap[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")
#| }
#|}
#|fn[K : Compare, V] glue(
#| l : SortedMap[K, V],
#| r : SortedMap[K, V],
#|) -> SortedMap[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)
#| }
#| }
#|}
#|pub fn[K : Compare, V] remove(
#| self : SortedMap[K, V],
#| key : K,
#|) -> SortedMap[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))
#| }
#| }
#| }
#|}
#|#deprecated("Use `filter_with_key` instead. `filter` will accept `(K, V) -> Bool` in the future.")
#|#coverage.skip
#|pub fn[K : Compare, V] filter(
#| self : SortedMap[K, V],
#| pred : (V) -> Bool raise?,
#|) -> SortedMap[K, V] raise? {
#| self.filter_with_key((_k, v) => pred(v))
#|}
#|pub fn[K : Compare, V] filter_with_key(
#| self : SortedMap[K, V],
#| pred : (K, V) -> Bool raise?,
#|) -> SortedMap[K, V] raise? {
#| match self {
#| Empty => Empty
#| Tree(k, value=v, l, r, ..) =>
#| if pred(k, v) {
#| balance(k, v, l.filter_with_key(pred), r.filter_with_key(pred))
#| } else {
#| glue(l.filter_with_key(pred), r.filter_with_key(pred))
#| }
#| }
#|}
#|pub fn[K, V] to_array(self : SortedMap[K, V]) -> Array[(K, V)] {
#| let arr = []
#| self.each((k, v) => arr.push((k, v)))
#| arr
#|}
#|let ratio = 5
#|fn[K, V] balance(
#| key : K,
#| value : V,
#| l : SortedMap[K, V],
#| r : SortedMap[K, V],
#|) -> SortedMap[K, V] {
#| 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))
#| }
#| 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))
#| }
#| 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 {
#| 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 {
#| 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)
#| }
#|}
#|test "from_array" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| inspect(
#| m.debug_tree(),
#| content="(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))",
#| )
#|}
#|test "insert" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one")])
#| inspect(m.debug_tree(), content="(3,three,(1,one,_,_),(8,eight,_,_))")
#| let m = m.add(5, "five").add(2, "two").add(0, "zero").add(1, "one_updated")
#| inspect(
#| m.debug_tree(),
#| content="(3,three,(1,one_updated,(0,zero,_,_),(2,two,_,_)),(8,eight,(5,five,_,_),_))",
#| )
#|}
#|test "remove" {
#| let m1 = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| inspect(
#| m1.debug_tree(),
#| content="(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))",
#| )
#| let m2 = m1.remove(1).remove(3)
#| inspect(m2.debug_tree(), content="(2,two,(0,zero,_,_),(8,eight,_,_))")
#| let m3 = m1.remove(8)
#| inspect(
#| m3.debug_tree(),
#| content="(2,two,(1,one,(0,zero,_,_),_),(3,three,_,_))",
#| )
#| let e : SortedMap[Int, Int] = Empty
#| inspect(e.remove(1).debug_tree(), content="_")
#|}
#|test "contains" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| inspect(
#| m.debug_tree(),
#| content="(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))",
#| )
#| inspect(m.contains(8), content="true")
#| inspect(m.contains(2), content="true")
#| inspect(m.contains(4), content="false")
#|}
#|test "map" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| let n = m.map(v => v + "X")
#| assert_eq(
#| n.debug_tree(),
#| "(3,threeX,(1,oneX,(0,zeroX,_,_),(2,twoX,_,_)),(8,eightX,_,_))",
#| )
#|}
#|test "map_with_key" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| let n = m.map_with_key((k, v) => "\{k}-\{v}")
#| assert_eq(
#| n.debug_tree(),
#| "(3,3-three,(1,1-one,(0,0-zero,_,_),(2,2-two,_,_)),(8,8-eight,_,_))",
#| )
#|}
#|test "filter" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| let fm = m.filter(v => v.length() > 3)
#| inspect(fm.debug_tree(), content="(3,three,(0,zero,_,_),(8,eight,_,_))")
#|}
#|test "filter_with_key" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| let fm = m.filter_with_key((k, v) => k > 3 && v.length() > 3)
#| inspect(fm.debug_tree(), content="(8,eight,_,_)")
#|}
#|test "singleton" {
#| let m = singleton(3, "three")
#| inspect(m.debug_tree(), content="(3,three,_,_)")
#|}
#|test "insert" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one")])
#| inspect(m.debug_tree(), content="(3,three,(1,one,_,_),(8,eight,_,_))")
#| let m = m.add(5, "five").add(2, "two").add(0, "zero").add(1, "one_updated")
#| inspect(
#| m.debug_tree(),
#| content="(3,three,(1,one_updated,(0,zero,_,_),(2,two,_,_)),(8,eight,(5,five,_,_),_))",
#| )
#|}
#|test "remove" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| inspect(
#| m.debug_tree(),
#| content="(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))",
#| )
#| let m = m.remove(1).remove(3)
#| inspect(m.debug_tree(), content="(2,two,(0,zero,_,_),(8,eight,_,_))")
#|}
#|test "filter" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| let fm = m.filter(v => v.length() > 3)
#| inspect(fm.debug_tree(), content="(3,three,(0,zero,_,_),(8,eight,_,_))")
#|}
#|test "filter_with_key" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| let fm = m.filter_with_key((k, v) => k > 3 && v.length() > 3)
#| inspect(fm.debug_tree(), content="(8,eight,_,_)")
#|}
#|test "empty" {
#| let m : SortedMap[Int, Int] = new()
#| inspect(m.debug_tree(), content="_")
#|}
#|test "split_max" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| assert_eq(
#| m.debug_tree(),
#| "(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))",
#| )
#| let (k, v, r) = m.split_max()
#| inspect(k, content="8")
#| inspect(v, content="eight")
#| inspect(
#| r.debug_tree(),
#| content="(2,two,(1,one,(0,zero,_,_),_),(3,three,_,_))",
#| )
#|}
#|test "split_min" {
#| let m = of([(3, "three"), (8, "eight"), (2, "two"), (1, "one"), (0, "zero")])
#| assert_eq(
#| m.debug_tree(),
#| "(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))",
#| )
#| let (k, v, r) = m.split_min()
#| inspect(k, content="0")
#| inspect(v, content="zero")
#| inspect(
#| r.debug_tree(),
#| content="(3,three,(1,one,_,(2,two,_,_)),(8,eight,_,_))",
#| )
#|}
#|test "glue" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| assert_eq(
#| m.debug_tree(),
#| "(3,three,(1,one,(0,zero,_,_),(2,two,_,_)),(8,eight,_,_))",
#| )
#| let (l, r) = match m {
#| Tree(_, l, r, ..) => (l, r)
#| _ => abort("unreachable")
#| }
#| let m = glue(l, r)
#| inspect(
#| m.debug_tree(),
#| content="(2,two,(1,one,(0,zero,_,_),_),(8,eight,_,_))",
#| )
#|}
#|test "split_max with non-empty tree" {
#| let m = of([(3, "three"), (8, "eight"), (1, "one"), (2, "two"), (0, "zero")])
#| let (k, v, r) = m.split_max()
#| inspect(k, content="8")
#| inspect(v, content="eight")
#| inspect(
#| r.debug_tree(),
#| content="(2,two,(1,one,(0,zero,_,_),_),(3,three,_,_))",
#| )
#|}
),
"traits_impl.mbt": (
#|pub impl[K, V] Default for SortedMap[K, V] with default() {
#| new()
#|}
#|pub impl[K : Eq, V : Eq] Eq for SortedMap[K, V] with equal(self, other) -> Bool {
#| let iter = InorderIterator::new(self)
#| let iter1 = InorderIterator::new(other)
#| loop (iter.next(), iter1.next()) {
#| (None, None) => true
#| (Some(a), Some(b)) => {
#| guard a == b else { break false }
#| continue (iter.next(), iter1.next())
#| }
#| (_, _) => false
#| }
#|}
#|pub impl[K : Compare, V : Compare] Compare for SortedMap[K, V] with compare(
#| self,
#| other,
#|) -> Int {
#| let iter = InorderIterator::new(self)
#| let iter1 = InorderIterator::new(other)
#| loop (iter.next(), iter1.next()) {
#| (None, None) => 0
#| (Some(a), Some(b)) => {
#| let cmp = a.compare(b)
#| guard cmp == 0 else { break cmp }
#| continue (iter.next(), iter1.next())
#| }
#| (Some(_), None) => 1
#| (None, Some(_)) => -1
#| }
#|}
#|pub impl[K : @quickcheck.Arbitrary + Compare, V : @quickcheck.Arbitrary] @quickcheck.Arbitrary for SortedMap[
#| K,
#| V,
#|] with arbitrary(size, rs) {
#| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array
#|}
#|pub impl[K : Hash, V : Hash] Hash for SortedMap[K, V] with hash_combine(
#| self,
#| hasher,
#|) {
#| for e in self {
#| hasher..combine(e.0)..combine(e.1)
#| }
#|}
#|pub impl[K : Show, V : Show] Show for SortedMap[K, V] with output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@immut/sorted_map.of([", suffix="])")
#|}
#|pub impl[K : Show, V : ToJson] ToJson for SortedMap[K, V] with to_json(self) {
#| let capacity = self.size()
#| guard capacity != 0 else { return Json::object(Map::new()) }
#| let jsons = Map::new(capacity~)
#| self.each((k, v) => jsons[k.to_string()] = v.to_json())
#| Json::object(jsons)
#|}
#|pub impl[V : @json.FromJson] @json.FromJson for SortedMap[String, V] with from_json(
#| json,
#| path,
#|) {
#| guard json is Object(obj) else {
#| raise @json.JsonDecodeError(
#| (path, "@immut/sorted_map.from_json: expected object"),
#| )
#| }
#| let mut map = new()
#| for k, v in obj {
#| map = map.add(k, V::from_json(v, path.add_key(k)))
#| }
#| map
#|}
),
"types.mbt": (
#|enum SortedMap[K, V] {
#| Empty
#| Tree(K, value~ : V, size~ : Int, SortedMap[K, V], SortedMap[K, V])
#|}
#|#deprecated("Use `SortedMap` instead of `T`")
#|pub typealias SortedMap as T
),
"utils.mbt": (
#|#deprecated("Use `new()` instead")
#|#coverage.skip
#|pub fn[K, V] SortedMap::empty() -> SortedMap[K, V] {
#| Empty
#|}
#|pub fn[K, V] new() -> SortedMap[K, V] {
#| Empty
#|}
#|pub fn[K, V] singleton(key : K, value : V) -> SortedMap[K, V] {
#| Tree(key, value~, size=1, Empty, Empty)
#|}
#|pub fn[K : Compare, V] contains(self : SortedMap[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
#| }
#| }
#| }
#|}
#|pub fn[K, V] size(self : SortedMap[K, V]) -> Int {
#| match self {
#| Empty => 0
#| Tree(_) as t => t.size
#| }
#|}
#|pub fn[K, V] is_empty(self : SortedMap[K, V]) -> Bool {
#| self.size() == 0
#|}
#|fn[K, V] make_tree(
#| key : K,
#| value : V,
#| l : SortedMap[K, V],
#| r : SortedMap[K, V],
#|) -> SortedMap[K, V] {
#| let size = l.size() + r.size() + 1
#| Tree(key, value~, size~, l, r)
#|}
#|#deprecated("Use `get` instead")
#|#coverage.skip
#|pub fn[K : Compare, V] lookup(self : SortedMap[K, V], key : K) -> V? {
#| self.get(key)
#|}
#|pub fn[K : Compare, V] get(self : SortedMap[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
#| }
#| }
#| }
#|}
#|pub fn[K : Compare, V] op_get(self : SortedMap[K, V], key : K) -> V {
#| loop self {
#| Empty => panic()
#| Tree(k, value~, l, r, ..) => {
#| let c = key.compare(k)
#| if c == 0 {
#| value
#| } else if c < 0 {
#| continue l
#| } else {
#| continue r
#| }
#| }
#| }
#|}
#|pub fn[K, V] each(self : SortedMap[K, V], f : (K, V) -> Unit) -> Unit {
#| match self {
#| Empty => ()
#| Tree(k, value~, l, r, ..) => {
#| l.each(f)
#| f(k, value)
#| r.each(f)
#| }
#| }
#|}
#|pub fn[K, V] eachi(self : SortedMap[K, V], f : (Int, K, V) -> Unit) -> Unit {
#| fn do_eachi(m : SortedMap[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)
#|}
#|#deprecated("Use `map_with_key` instead. `map` will accept `(K, X) -> Y` in the future.")
#|#coverage.skip
#|pub fn[K, X, Y] map(self : SortedMap[K, X], f : (X) -> Y) -> SortedMap[K, Y] {
#| match self {
#| Empty => Empty
#| Tree(k, value~, size~, l, r) =>
#| Tree(k, value=f(value), size~, l.map(f), r.map(f))
#| }
#|}
#|pub fn[K, X, Y] map_with_key(
#| self : SortedMap[K, X],
#| f : (K, X) -> Y,
#|) -> SortedMap[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))
#| }
#|}
#|#deprecated("Use `foldl_with_key` instead. `fold` will accept `(A, K, V) -> A` in the future.")
#|pub fn[K, V, A] fold(self : SortedMap[K, V], init~ : A, f : (A, V) -> A) -> A {
#| self.foldl_with_key((acc, _k, v) => f(acc, v), init~)
#|}
#|#alias(foldr_with_key)
#|pub fn[K, V, A] rev_fold(
#| self : SortedMap[K, V],
#| f : (A, K, V) -> A,
#| init~ : A,
#|) -> A {
#| fn go(m : SortedMap[K, V], acc) {
#| match m {
#| Empty => acc
#| Tree(k, value~, l, r, ..) => go(l, f(go(r, acc), k, value))
#| }
#| }
#| go(self, init)
#|}
#|pub fn[K, V, A] foldl_with_key(
#| self : SortedMap[K, V],
#| f : (A, K, V) -> A,
#| init~ : A,
#|) -> A {
#| fn go(m : SortedMap[K, V], acc) {
#| match m {
#| Empty => acc
#| Tree(k, value~, l, r, ..) => go(r, f(go(l, acc), k, value))
#| }
#| }
#| go(self, init)
#|}
#|fn[K : Show, V : Show] debug_tree(self : SortedMap[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})"
#| }
#| }
#|}
#|pub fn[K : Compare, V] from_array(array : Array[(K, V)]) -> SortedMap[K, V] {
#| for i = 0, mp = Empty; i < array.length(); {
#| let (k, v) = array[i]
#| continue i + 1, mp.add(k, v)
#| } else {
#| mp
#| }
#|}
#|pub fn[K, V] iter(self : SortedMap[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)
#| })
#|}
#|pub fn[K, V] iter2(self : SortedMap[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)
#| })
#|}
#|pub fn[K : Compare, V] from_iter(iter : Iter[(K, V)]) -> SortedMap[K, V] {
#| iter.fold(init=new(), (m, e) => m.add(e.0, e.1))
#|}
#|#deprecated("Use `keys_as_iter` instead. `keys` will return `Iter[K]` instead of `Array[K]` in the future.")
#|#coverage.skip
#|pub fn[K, V] keys(self : SortedMap[K, V]) -> Array[K] {
#| self.iter().map(p => p.0).collect()
#|}
#|pub fn[K, V] keys_as_iter(self : SortedMap[K, V]) -> Iter[K] {
#| self.iter().map(p => p.0)
#|}
#|pub fn[K, V] values(self : SortedMap[K, V]) -> Iter[V] {
#| self.iter().map(p => p.1)
#|}
#|#deprecated("Use `values` instead")
#|#coverage.skip
#|pub fn[K, V] elems(self : SortedMap[K, V]) -> Array[V] {
#| self.values().collect()
#|}
#|pub fn[K : Compare, V] of(array : FixedArray[(K, V)]) -> SortedMap[K, V] {
#| for i = 0, mp = Empty; i < array.length(); {
#| let (k, v) = array[i]
#| continue i + 1, mp.add(k, v)
#| } else {
#| mp
#| }
#|}
#|pub fn[K : Show, V : ToJson] to_json(self : SortedMap[K, V]) -> Json {
#| ToJson::to_json(self)
#|}
#|pub fn[V : @json.FromJson] from_json(
#| json : Json,
#|) -> SortedMap[String, V] raise @json.JsonDecodeError {
#| @json.from_json(json)
#|}
),
},
)
///|
let moonbitlang_core_immut_sorted_set_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/array",
#| "moonbitlang/core/quickcheck",
#| "moonbitlang/core/json"
#| ],
#| "targets": {
#| "panic_test.mbt": ["not", "native", "llvm"]
#| }
#|}
),
"deprecated.mbt": (
#|#deprecated("use `@immut/sorted_set.new` instead")
#|#coverage.skip
#|pub fn[A] SortedSet::new() -> SortedSet[A] {
#| Empty
#|}
#|#deprecated("use `immut/sorted_set.singleton` instead")
#|#coverage.skip
#|pub fn[A] SortedSet::singleton(value : A) -> SortedSet[A] {
#| singleton(value)
#|}
#|#deprecated("use `@immut/sorted_set.from_array` instead")
#|#coverage.skip
#|pub fn[A : Compare] SortedSet::from_array(array : Array[A]) -> SortedSet[A] {
#| from_array(array)
#|}
#|#deprecated("use `@immut/sorted_set.from_json` instead")
#|#coverage.skip
#|pub fn[A : @json.FromJson + Compare] SortedSet::from_json(
#| json : Json,
#|) -> SortedSet[A] raise @json.JsonDecodeError {
#| @json.from_json(json)
#|}
#|#deprecated("use `@immut/sorted_set.of` instead")
#|#coverage.skip
#|pub fn[A : Compare] SortedSet::of(array : FixedArray[A]) -> SortedSet[A] {
#| of(array)
#|}
),
"generic.mbt": (
#|pub fn[A] iter(self : SortedSet[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)
#| })
#|}
#|pub fn[A : Compare] from_iter(iter : Iter[A]) -> SortedSet[A] {
#| iter.fold(init=new(), (s, e) => s.add(e))
#|}
#|#deprecated("use `@immut/sorted_set.from_iter` instead")
#|pub fn[A : Compare] SortedSet::from_iter(iter : Iter[A]) -> SortedSet[A] {
#| from_iter(iter)
#|}
#|test {
#| @json.inspect(of([2, 7, 1, 2, 3, 4, 5]), content=[1, 2, 3, 4, 5, 7])
#|}
#|pub impl[A : Eq] Eq for SortedSet[A] with equal(self, other) -> Bool {
#| let iter = InorderIterator::new(self)
#| let iter1 = InorderIterator::new(other)
#| loop (iter.next(), iter1.next()) {
#| (None, None) => true
#| (Some(a), Some(b)) => {
#| guard a == b else { break false }
#| continue (iter.next(), iter1.next())
#| }
#| (_, _) => false
#| }
#|}
#|pub impl[A : Compare] Compare for SortedSet[A] with compare(self, other) -> Int {
#| let iter = InorderIterator::new(self)
#| let iter1 = InorderIterator::new(other)
#| loop (iter.next(), iter1.next()) {
#| (None, None) => 0
#| (Some(a), Some(b)) => {
#| let cmp = a.compare(b)
#| guard cmp == 0 else { break cmp }
#| continue (iter.next(), iter1.next())
#| }
#| (Some(_), None) => 1
#| (None, Some(_)) => -1
#| }
#|}
#|priv struct InorderIterator[A](Array[SortedSet[A]])
#|fn[A] InorderIterator::new(root : SortedSet[A]) -> InorderIterator[A] {
#| let it = InorderIterator([])
#| it.move_left(root)
#| it
#|}
#|fn[A] InorderIterator::move_left(
#| self : InorderIterator[A],
#| node : SortedSet[A],
#|) -> Unit {
#| loop node {
#| Empty => ()
#| Node(left~, ..) as curr => {
#| let InorderIterator(self) = self
#| self.push(curr)
#| continue left
#| }
#| }
#|}
#|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)
#|}
#|test "InorderIterator" {
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5, 6, 7]
#| let set = of(arr)
#| let iter = InorderIterator::new(set)
#| for i = 0; ; i = i + 1 {
#| match iter.next() {
#| None => break
#| Some(value) => assert_eq(value, arr[i])
#| }
#| }
#|}
),
"immutable_set.mbt": (
#|pub fn[A] new() -> SortedSet[A] {
#| Empty
#|}
#|pub impl[A] Default for SortedSet[A] with default() {
#| Empty
#|}
#|pub fn[A] singleton(value : A) -> SortedSet[A] {
#| Node(left=Empty, value~, right=Empty, size=1)
#|}
#|pub fn[A : Compare] from_array(array : Array[A]) -> SortedSet[A] {
#| for i = array.length() - 1, set = Empty; i >= 0; {
#| continue i - 1, set.add(array[i])
#| } else {
#| set
#| }
#|}
#|pub fn[A] to_array(self : SortedSet[A]) -> Array[A] {
#| let arr = []
#| fn aux(set : SortedSet[A]) {
#| match set {
#| Empty => ()
#| Node(left~, value~, right~, ..) => {
#| aux(left)
#| arr.push(value)
#| aux(right)
#| }
#| }
#| }
#| aux(self)
#| arr
#|}
#|pub fn[A : Compare] remove_min(self : SortedSet[A]) -> SortedSet[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)
#| }
#| }
#|}
#|pub fn[A : Compare] add(self : SortedSet[A], value : A) -> SortedSet[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)
#| }
#| }
#| }
#| }
#|}
#|pub fn[A : Compare] remove(self : SortedSet[A], value : A) -> SortedSet[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)
#| }
#| }
#| }
#| }
#|}
#|pub fn[A : Compare] min(self : SortedSet[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() }
#| }
#|}
#|pub fn[A : Compare] min_option(self : SortedSet[A]) -> A? {
#| match self {
#| Empty => None
#| Node(left~, value~, ..) =>
#| if left is Empty {
#| Some(value)
#| } else {
#| left.min_option()
#| }
#| }
#|}
#|pub fn[A : Compare] max(self : SortedSet[A]) -> A {
#| match self {
#| Empty => abort("max: there are no values in ImmutableSet.")
#| Node(right~, value~, ..) => if right is Empty { value } else { right.max() }
#| }
#|}
#|pub fn[A : Compare] max_option(self : SortedSet[A]) -> A? {
#| match self {
#| Empty => None
#| Node(right~, value~, ..) =>
#| if right is Empty {
#| Some(value)
#| } else {
#| right.max_option()
#| }
#| }
#|}
#|pub fn[A : Compare] split(
#| self : SortedSet[A],
#| divide : A,
#|) -> (SortedSet[A], Bool, SortedSet[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)
#| }
#| }
#| }
#|}
#|pub fn[A] is_empty(self : SortedSet[A]) -> Bool {
#| self is Empty
#|}
#|pub fn[A : Compare] contains(self : SortedSet[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)
#| }
#| }
#|}
#|pub fn[A : Compare] union(
#| self : SortedSet[A],
#| other : SortedSet[A],
#|) -> SortedSet[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))
#| }
#| }
#|}
#|pub impl[A : Compare] Add for SortedSet[A] with add(self, other) {
#| return self.union(other)
#|}
#|#deprecated("Use `intersection` instead")
#|#coverage.skip
#|pub fn[A : Compare] inter(
#| self : SortedSet[A],
#| other : SortedSet[A],
#|) -> SortedSet[A] {
#| self.intersection(other)
#|}
#|pub fn[A : Compare] intersection(
#| self : SortedSet[A],
#| other : SortedSet[A],
#|) -> SortedSet[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))
#| }
#| }
#|}
#|#deprecated("Use `difference` instead")
#|#coverage.skip
#|pub fn[A : Compare] diff(
#| self : SortedSet[A],
#| other : SortedSet[A],
#|) -> SortedSet[A] {
#| self.difference(other)
#|}
#|pub fn[A : Compare] difference(
#| self : SortedSet[A],
#| other : SortedSet[A],
#|) -> SortedSet[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))
#| }
#| }
#|}
#|pub fn[A : Compare] symmetric_difference(
#| self : SortedSet[A],
#| other : SortedSet[A],
#|) -> SortedSet[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))
#| }
#| }
#|}
#|pub fn[A : Compare] subset(self : SortedSet[A], other : SortedSet[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)
#| }
#| }
#| }
#|}
#|pub fn[A : Compare] disjoint(self : SortedSet[A], other : SortedSet[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
#| }
#| }
#| }
#|}
#|pub fn[A] each(self : SortedSet[A], f : (A) -> Unit raise?) -> Unit raise? {
#| match self {
#| Empty => ()
#| Node(left~, value~, right~, ..) => {
#| left.each(f)
#| f(value)
#| right.each(f)
#| }
#| }
#|}
#|pub fn[A : Compare, B] fold(
#| self : SortedSet[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| match self {
#| Empty => init
#| Node(left~, value~, right~, ..) =>
#| right.fold(init=f(left.fold(init~, f), value), f)
#| }
#|}
#|pub fn[A : Compare, B : Compare] map(
#| self : SortedSet[A],
#| f : (A) -> B raise?,
#|) -> SortedSet[B] raise? {
#| match self {
#| Empty => Empty
#| Node(left~, value~, right~, ..) =>
#| try_join(left.map(f), f(value), right.map(f))
#| }
#|}
#|pub fn[A : Compare] all(
#| self : SortedSet[A],
#| f : (A) -> Bool raise?,
#|) -> Bool raise? {
#| match self {
#| Empty => true
#| Node(left~, value~, right~, ..) => f(value) && left.all(f) && right.all(f)
#| }
#|}
#|pub fn[A : Compare] any(
#| self : SortedSet[A],
#| f : (A) -> Bool raise?,
#|) -> Bool raise? {
#| match self {
#| Empty => false
#| Node(left~, value~, right~, ..) => f(value) || left.any(f) || right.any(f)
#| }
#|}
#|pub fn[A : Compare] filter(
#| self : SortedSet[A],
#| f : (A) -> Bool raise?,
#|) -> SortedSet[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)
#| }
#| }
#| }
#|}
#|pub impl[A : Show] Show for SortedSet[A] with output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@immut/sorted_set.of([", suffix="])")
#|}
#|pub impl[A : ToJson] ToJson for SortedSet[A] with to_json(self) {
#| let capacity = self.iter().count()
#| guard capacity != 0 else { return Json::array([]) }
#| let jsons = Array::new(capacity~)
#| self.each(a => jsons.push(a.to_json()))
#| Json::array(jsons)
#|}
#|pub fn[A : ToJson] to_json(self : SortedSet[A]) -> Json {
#| ToJson::to_json(self)
#|}
#|pub impl[A : @json.FromJson + Compare] @json.FromJson for SortedSet[A] with from_json(
#| json,
#| path,
#|) {
#| guard json is Array(arr) else {
#| raise @json.JsonDecodeError(
#| (path, "@immut/sorted_set.from_json: expected array"),
#| )
#| }
#| let mut set = new()
#| for i, x in arr {
#| set = set.add(A::from_json(x, path.add_index(i)))
#| }
#| set
#|}
#|pub fn[A : @json.FromJson + Compare] from_json(
#| json : Json,
#|) -> SortedSet[A] raise @json.JsonDecodeError {
#| @json.from_json(json)
#|}
#|pub impl[X : @quickcheck.Arbitrary + Compare] @quickcheck.Arbitrary for SortedSet[
#| X,
#|] with arbitrary(size, rs) {
#| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array
#|}
#|const BALANCE_RATIO = 5
#|priv enum SplitBis[A] {
#| Found
#| NotFound(SortedSet[A], () -> SortedSet[A])
#|}
#|impl[T] Show for SplitBis[T] with output(self, logger) {
#| match self {
#| Found => logger.write_string("Found")
#| NotFound(_) => logger.write_string("NotFound")
#| }
#|}
#|fn[A : Compare] split_bis(self : SortedSet[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)
#| }
#| }
#| }
#| }
#|}
#|pub fn[A] size(self : SortedSet[A]) -> Int {
#| match self {
#| Empty => 0
#| Node(size~, ..) => size
#| }
#|}
#|fn[A] create(
#| left : SortedSet[A],
#| value : A,
#| right : SortedSet[A],
#|) -> SortedSet[A] {
#| Node(left~, right~, value~, size=left.size() + right.size() + 1)
#|}
#|fn[A] balance(
#| left : SortedSet[A],
#| value : A,
#| right : SortedSet[A],
#|) -> SortedSet[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)
#| }
#|}
#|fn[A : Compare] add_min_value(self : SortedSet[A], value : A) -> SortedSet[A] {
#| match self {
#| Empty => singleton(value)
#| Node(left~, value=node_value, right~, ..) =>
#| balance(left.add_min_value(value), node_value, right)
#| }
#|}
#|fn[A : Compare] add_max_value(self : SortedSet[A], value : A) -> SortedSet[A] {
#| match self {
#| Empty => singleton(value)
#| Node(left~, value=node_value, right~, ..) =>
#| balance(left, node_value, right.add_max_value(value))
#| }
#|}
#|fn[A : Compare] join(
#| left : SortedSet[A],
#| value : A,
#| right : SortedSet[A],
#|) -> SortedSet[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)
#| }
#| }
#|}
#|fn[A : Compare] try_join(
#| left : SortedSet[A],
#| value : A,
#| right : SortedSet[A],
#|) -> SortedSet[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))
#| }
#|}
#|fn[A : Compare] merge(
#| self : SortedSet[A],
#| other : SortedSet[A],
#|) -> SortedSet[A] {
#| match (self, other) {
#| (Empty, _) => other
#| (_, Empty) => self
#| _ => balance(self, other.min(), other.remove_min())
#| }
#|}
#|fn[A : Compare] concat(
#| self : SortedSet[A],
#| other : SortedSet[A],
#|) -> SortedSet[A] {
#| match (self, other) {
#| (Empty, _) => other
#| (_, Empty) => self
#| _ => join(self, other.min(), other.remove_min())
#| }
#|}
#|pub fn[A : Compare] of(array : FixedArray[A]) -> SortedSet[A] {
#| for i = array.length() - 1, set = Empty; i >= 0; {
#| continue i - 1, set.add(array[i])
#| } else {
#| set
#| }
#|}
#|pub impl[A : Hash] Hash for SortedSet[A] with hash_combine(self, hasher) {
#| for t in self {
#| t.hash_combine(hasher)
#| }
#|}
#|test "split_bis" {
#| inspect(of([1, 2, 3]).split_bis(1), content="Found")
#| inspect(of([1, 2, 3]).split_bis(3), content="Found")
#| inspect(of([1, 2, 3]).split_bis(0), content="NotFound")
#| inspect(of([1, 2, 3]).split_bis(4), content="NotFound")
#|}
#|test "balance with left height greater" {
#| let left = of([1, 2, 3])
#| let value = 4
#| let right = of([5])
#| let balanced_set = balance(left, value, right)
#| inspect(balanced_set, content="@immut/sorted_set.of([1, 2, 3, 4, 5])")
#|}
#|test "balance with right height greater" {
#| let left = of([1])
#| let value = 2
#| let right = of([3, 4, 5])
#| let balanced_set = balance(left, value, right)
#| inspect(balanced_set, content="@immut/sorted_set.of([1, 2, 3, 4, 5])")
#|}
#|test "join with different heights" {
#| let left = of([1, 2, 3])
#| let value = 4
#| let right = of([5, 6, 7])
#| let joined_set = join(left, value, right)
#| inspect(joined_set, content="@immut/sorted_set.of([1, 2, 3, 4, 5, 6, 7])")
#|}
#|test "hash" {
#| assert_eq(Hash::hash(of([1, 2, 3, 4])), Hash::hash(of([3, 2]).add(1).add(4)))
#| assert_not_eq(Hash::hash(of([1, 2, 3])), Hash::hash(of([1, 2, 4])))
#|}
),
"types.mbt": (
#|enum SortedSet[A] {
#| Empty
#| Node(left~ : SortedSet[A], right~ : SortedSet[A], size~ : Int, value~ : A)
#|}
#|#deprecated("Use `SortedSet` instead of `T`")
#|pub typealias SortedSet as T
),
},
)
///|
let moonbitlang_core_int_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/int",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/uint": moonbitlang_core_uint_module,
},
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin", "moonbitlang/core/uint"]
#|}
),
"int.mbt": (
#|pub let max_value = 2147483647
#|pub let min_value = -2147483648
#|pub fn Int::abs(self : Int) -> Int {
#| if self < 0 {
#| -self
#| } else {
#| self
#| }
#|}
#|pub fnalias Int::abs
#|pub fn to_be_bytes(self : Int) -> Bytes {
#| self.reinterpret_as_uint().to_be_bytes()
#|}
#|pub fn to_le_bytes(self : Int) -> Bytes {
#| self.reinterpret_as_uint().to_le_bytes()
#|}
),
},
)
///|
let moonbitlang_core_int16_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/int16",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
},
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin", "moonbitlang/core/json"],
#| "test-import": ["moonbitlang/core/uint16"]
#|}
),
"int16.mbt": (
#|pub let max_value : Int16 = 32767
#|pub let min_value : Int16 = -32768
#|pub impl Add for Int16 with add(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() + that.to_int()).to_int16()
#|}
#|pub impl Add for Int16 with op_add(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() + that.to_int()).to_int16()
#|}
#|pub impl Sub for Int16 with sub(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() - that.to_int()).to_int16()
#|}
#|pub impl Sub for Int16 with op_sub(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() - that.to_int()).to_int16()
#|}
#|pub impl Mul for Int16 with mul(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() * that.to_int()).to_int16()
#|}
#|pub impl Mul for Int16 with op_mul(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() * that.to_int()).to_int16()
#|}
#|pub impl Div for Int16 with div(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() / that.to_int()).to_int16()
#|}
#|pub impl Div for Int16 with op_div(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() / that.to_int()).to_int16()
#|}
#|pub impl Mod for Int16 with mod(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() % that.to_int()).to_int16()
#|}
#|pub impl Mod for Int16 with op_mod(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() % that.to_int()).to_int16()
#|}
#|pub impl Eq for Int16 with equal(self, that) {
#| self.to_int() == that.to_int()
#|}
#|pub impl Eq for Int16 with op_equal(self, that) {
#| self.to_int() == that.to_int()
#|}
#|pub impl Compare for Int16 with compare(self, that) {
#| self.to_int().compare(that.to_int())
#|}
#|pub impl Hash for Int16 with hash(self) {
#| self.to_int()
#|}
#|pub impl Hash for Int16 with hash_combine(self, hasher) {
#| hasher.combine_int(self.to_int())
#|}
#|pub impl Shl for Int16 with shl(self : Int16, that : Int) -> Int16 {
#| (self.to_int() << that).to_int16()
#|}
#|pub impl Shr for Int16 with shr(self : Int16, that : Int) -> Int16 {
#| (self.to_int() >> that).to_int16()
#|}
#|pub impl BitOr for Int16 with lor(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() | that.to_int()).to_int16()
#|}
#|pub impl BitAnd for Int16 with land(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() & that.to_int()).to_int16()
#|}
#|pub impl BitXOr for Int16 with lxor(self : Int16, that : Int16) -> Int16 {
#| (self.to_int() ^ that.to_int()).to_int16()
#|}
#|pub impl Neg for Int16 with neg(self : Int16) -> Int16 {
#| (-self.to_int()).to_int16()
#|}
#|pub fn Int16::abs(self : Int16) -> Int16 {
#| if self < 0 {
#| -self
#| } else {
#| self
#| }
#|}
#|pub impl Default for Int16 with default() {
#| 0
#|}
#|pub impl ToJson for Int16 with to_json(self : Int16) -> Json {
#| Json::number(self.to_int().to_double())
#|}
#|pub fn Int16::reinterpret_as_uint16(self : Int16) -> UInt16 {
#| self.to_int().to_uint16()
#|}
),
},
)
///|
let moonbitlang_core_int64_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin", "moonbitlang/core/bytes", "moonbitlang/core/uint", "moonbitlang/core/uint64"]
#|}
),
"int64.mbt": (
#|pub let max_value = 9223372036854775807L
#|pub let min_value = -9223372036854775808L
#|pub fn Int64::from_int(i : Int) -> Int64 {
#| i.to_int64()
#|}
#|pub fn from_int(i : Int) -> Int64 {
#| i.to_int64()
#|}
#|pub fn Int64::abs(self : Int64) -> Int64 {
#| if self < 0L {
#| -self
#| } else {
#| self
#| }
#|}
#|pub fnalias Int64::abs
#|pub fn to_be_bytes(self : Int64) -> Bytes {
#| self.reinterpret_as_uint64().to_be_bytes()
#|}
#|pub fn to_le_bytes(self : Int64) -> Bytes {
#| self.reinterpret_as_uint64().to_le_bytes()
#|}
),
"xxhash.mbt": (
#|let gPRIME2 = 0x85EBCA77U
#|let gPRIME3 = 0xC2B2AE3DU
#|let gPRIME4 = 0x27D4EB2FU
#|let gPRIME5 = 0x165667B1U
#|pub impl Hash for Int64 with hash(self) -> Int {
#| let mut input = self.reinterpret_as_uint64()
#| let seed = 0U
#| let mut acc = seed + gPRIME5 + 8
#| let mut x = acc + input.to_uint() * gPRIME3
#| let r = 17
#| acc = ((x << r) | (x >> (32 - r))) * gPRIME4
#| input = input >> 32
#| x = acc + input.to_uint() * gPRIME3
#| acc = ((x << r) | (x >> (32 - r))) * gPRIME4
#| input = input >> 32
#| acc = acc ^ (acc >> 15)
#| acc *= gPRIME2
#| acc = acc ^ (acc >> 13)
#| acc *= gPRIME3
#| acc = acc ^ (acc >> 16)
#| acc.reinterpret_as_int()
#|}
#|pub impl Hash for Int64 with hash_combine(self, hasher) {
#| hasher.combine_int64(self)
#|}
#|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()
#|}
#|test "int64 hash" {
#| let i0 = 9_223_372_036_854_775_807L // INT64_MAX
#| let i1 = -9_223_372_036_854_775_808L // INT64_MIN
#| let i2 = gPRIME2.to_int64()
#| let i3 = gPRIME3.to_int64()
#| let i4 = gPRIME4.to_int64()
#| let i5 = gPRIME5.to_int64()
#| let i6 = 0L
#| inspect(i0.hash().to_string(), content=i0.slow_hash().to_string())
#| inspect(i1.hash().to_string(), content=i1.slow_hash().to_string())
#| inspect(i2.hash().to_string(), content=i2.slow_hash().to_string())
#| inspect(i3.hash().to_string(), content=i3.slow_hash().to_string())
#| inspect(i4.hash().to_string(), content=i4.slow_hash().to_string())
#| inspect(i5.hash().to_string(), content=i5.slow_hash().to_string())
#| inspect(i6.hash().to_string(), content=i6.slow_hash().to_string())
#|}
),
},
)
///|
let moonbitlang_core_json_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/char",
#| "moonbitlang/core/double",
#| "moonbitlang/core/string",
#| "moonbitlang/core/strconv",
#| "moonbitlang/core/option"
#| ],
#| "test-import": [
#| "moonbitlang/core/result",
#| "moonbitlang/core/unit",
#| "moonbitlang/core/array",
#| "moonbitlang/core/bigint"
#| ]
#|}
),
"deprecated.mbt": (
#|#deprecated("Definition of json is moved to builtin package, use `Json` instead")
#|pub typealias Json as JsonValue
),
"from_json.mbt": (
#|pub(all) suberror JsonDecodeError (JsonPath, String) derive (
#| Eq,
#| Show,
#| ToJson(style="flat"),
#|)
#|pub(open) trait FromJson {
#| from_json(Json, JsonPath) -> Self raise JsonDecodeError
#|}
#|pub fn[T : FromJson] from_json(
#| json : Json,
#| path? : JsonPath = Root,
#|) -> T raise JsonDecodeError {
#| FromJson::from_json(json, path)
#|}
#|fn[T] decode_error(path : JsonPath, msg : String) -> T raise JsonDecodeError {
#| raise JsonDecodeError((path, msg))
#|}
#|pub impl FromJson for Bool with from_json(json, path) {
#| match json {
#| true => true
#| false => false
#| _ => decode_error(path, "Bool::from_json: expected boolean")
#| }
#|}
#|pub impl FromJson for Int with from_json(json, path) {
#| guard json is Number(n, ..) &&
#| n != @double.infinity &&
#| n != @double.neg_infinity else {
#| decode_error(path, "Int::from_json: expected number")
#| }
#| let max_ok = 2147483647.0
#| let min_ok = -2147483648.0
#| if n > max_ok || n < min_ok {
#| decode_error(path, "Int::from_json: overflow")
#| }
#| n.to_int()
#|}
#|pub impl FromJson for Int64 with from_json(json, path) {
#| guard json is String(str) else {
#| decode_error(
#| path, "Int64::from_json: expected number in string representation",
#| )
#| }
#| @strconv.parse_int64(str) catch {
#| error => decode_error(path, "Int64::from_json: parsing failure \{error}")
#| }
#|}
#|pub impl FromJson for UInt with from_json(json, path) {
#| guard json is Number(n, ..) &&
#| n != @double.infinity &&
#| n != @double.neg_infinity else {
#| decode_error(path, "UInt::from_json: expected number")
#| }
#| let max_ok = 4294967295.0
#| if n < 0.0 || n > max_ok {
#| decode_error(path, "UInt::from_json: overflow")
#| }
#| n.to_uint()
#|}
#|pub impl FromJson for UInt64 with from_json(json, path) {
#| guard json is String(str) else {
#| decode_error(
#| path, "UInt64::from_json: expected number in string representation",
#| )
#| }
#| @strconv.parse_uint64(str) catch {
#| error => decode_error(path, "UInt64::from_json: parsing failure \{error}")
#| }
#|}
#|pub impl FromJson for Double with from_json(json, path) {
#| match json {
#| String("NaN") => @double.not_a_number
#| String("Infinity") => @double.infinity
#| String("-Infinity") => @double.neg_infinity
#| Number(n, ..) if n != @double.infinity && n != @double.neg_infinity => n
#| _ => decode_error(path, "Double::from_json: expected number")
#| }
#|}
#|pub impl FromJson for String with from_json(json, path) {
#| guard json is String(a) else {
#| decode_error(path, "String::from_json: expected string")
#| }
#| a
#|}
#|pub impl FromJson for @string.View with from_json(json, path) {
#| guard json is String(a) else {
#| decode_error(path, "View::from_json: expected string")
#| }
#| a[:]
#|}
#|pub impl FromJson for Char with from_json(json, path) {
#| guard json is String(a) else {
#| decode_error(path, "Char::from_json: expected string")
#| }
#| let len = a.length()
#| if len == 1 {
#| a.unsafe_charcode_at(0).unsafe_to_char()
#| } else if len == 2 {
#| let c1 = a.unsafe_charcode_at(0)
#| let c2 = a.unsafe_charcode_at(1)
#| if c1 is (0xD800..=0xDBFF) && c2 is (0xDC00..=0xDFFF) {
#| let c3 = (c1 << 10) + c2 - 0x35fdc00
#| c3.unsafe_to_char()
#| } else {
#| decode_error(path, "Char::from_json: invalid surrogate pair")
#| }
#| } else {
#| decode_error(path, "Char::from_json: expected single character")
#| }
#|}
#|pub impl[X : FromJson] FromJson for Array[X] with from_json(json, path) {
#| guard json is Array(a) else {
#| decode_error(path, "Array::from_json: expected array")
#| }
#| guard Index(path, index=0) is (Index(_) as new_path)
#| a.mapi((i, x) => {
#| new_path.index = i
#| FromJson::from_json(x, new_path)
#| })
#|}
#|pub impl[X : FromJson] FromJson for FixedArray[X] with from_json(json, path) {
#| guard json is Array(a) else {
#| decode_error(path, "FixedArray::from_json: expected array")
#| }
#| let len = a.length()
#| if len == 0 {
#| return []
#| }
#| guard Index(path, index=0) is (Index(_) as new_path)
#| let res = FixedArray::make(
#| len,
#| FromJson::from_json(a.unsafe_get(0), new_path),
#| )
#| for i in 1.. None
#| Array([value]) => Some(FromJson::from_json(value, path.add_index(0)))
#| _ => decode_error(path, "Option::from_json: expected array or null")
#| }
#|}
#|pub impl[Ok : FromJson, Err : FromJson] FromJson for Result[Ok, Err] with from_json(
#| json,
#| path,
#|) {
#| guard json is Object(obj) else {
#| decode_error(path, "Result::from_json: expected object")
#| }
#| if obj.size() != 1 {
#| decode_error(path, "Result::from_json: expected object with one field")
#| }
#| match obj {
#| { "Ok": ok, .. } => Ok(FromJson::from_json(ok, path.add_key("Ok")))
#| { "Err": err, .. } => Err(FromJson::from_json(err, path.add_key("Err")))
#| _ =>
#| decode_error(
#| path, "Result::from_json: expected object with Ok or Err field",
#| )
#| }
#|}
#|pub impl FromJson for Unit with from_json(json, path) {
#| guard json is Null else {
#| decode_error(path, "Unit::from_json: expected null")
#| }
#|}
#|pub impl FromJson for Json with from_json(json, _path) {
#| json
#|}
),
"internal_types.mbt": (
#|priv struct ParseContext {
#| mut offset : Int
#| input : String
#| end_offset : Int
#|}
#|fn ParseContext::make(input : String) -> ParseContext {
#| { offset: 0, input, end_offset: input.length() }
#|}
#|priv struct CharClass(Array[(Char, Char)])
#|fn CharClass::of(array : Array[(Char, Char)]) -> CharClass {
#| CharClass(array)
#|}
#|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
#| }
#|}
#|priv enum Token {
#| Null
#| True
#| False
#| Number(Double, String?)
#| String(String)
#| LBrace
#| RBrace
#| LBracket
#| RBracket
#| Comma
#|}
),
"json.mbt": (
#|pub fn as_null(self : Json) -> Unit? {
#| guard self is Null else { return None }
#| Some(())
#|}
#|pub fn as_bool(self : Json) -> Bool? {
#| match self {
#| True => Some(true)
#| False => Some(false)
#| _ => None
#| }
#|}
#|pub fn as_number(self : Json) -> Double? {
#| guard self is Number(n, ..) else { return None }
#| Some(n)
#|}
#|pub fn as_string(self : Json) -> String? {
#| guard self is String(s) else { return None }
#| Some(s)
#|}
#|pub fn as_array(self : Json) -> Array[Json]? {
#| guard self is Array(arr) else { return None }
#| Some(arr)
#|}
#|pub fn item(self : Json, index : Int) -> Json? {
#| match self.as_array() {
#| Some(arr) => arr.get(index)
#| None => None
#| }
#|}
#|pub fn as_object(self : Json) -> Map[String, Json]? {
#| guard self is Object(obj) else { return None }
#| Some(obj)
#|}
#|pub fn value(self : Json, key : String) -> Json? {
#| match self.as_object() {
#| Some(obj) => obj.get(key)
#| None => None
#| }
#|}
#|fn indent_str(level : Int, indent : Int) -> String {
#| if indent == 0 {
#| ""
#| } else {
#| "\n" + " ".repeat(indent * level)
#| }
#|}
#|pub fn stringify(
#| self : Json,
#| escape_slash? : Bool = false,
#| indent? : Int = 0,
#|) -> String {
#| let buf = StringBuilder::new(size_hint=0)
#| fn stringify_inner(value : Json, level : Int) -> Unit {
#| match value {
#| Object(members) => {
#| if members.is_empty() {
#| buf.write_string("{}")
#| return
#| }
#| buf.write_char('{')
#| buf.write_string(indent_str(level + 1, indent))
#| let mut first = true
#| for k, v in members {
#| if first {
#| first = false
#| } else {
#| buf.write_char(',')
#| buf.write_string(indent_str(level + 1, indent))
#| }
#| buf
#| ..write_char('\"')
#| ..write_string(escape(k, escape_slash~))
#| ..write_char('\"')
#| if indent == 0 {
#| buf.write_char(':')
#| } else {
#| buf.write_string(": ")
#| }
#| stringify_inner(v, level + 1)
#| }
#| buf.write_string(indent_str(level, indent))
#| buf.write_char('}')
#| }
#| Array(arr) => {
#| if arr.is_empty() {
#| buf.write_string("[]")
#| return
#| }
#| buf.write_char('[')
#| buf.write_string(indent_str(level + 1, indent))
#| for i, v in arr {
#| if i > 0 {
#| buf.write_char(',')
#| buf.write_string(indent_str(level + 1, indent))
#| }
#| stringify_inner(v, level + 1)
#| }
#| buf.write_string(indent_str(level, indent))
#| buf.write_char(']')
#| }
#| String(s) =>
#| buf
#| ..write_char('\"')
#| ..write_string(escape(s, escape_slash~))
#| ..write_char('\"')
#| Number(n, repr~) =>
#| match repr {
#| None => buf.write_object(n)
#| Some(r) => buf.write_string(r)
#| }
#| True => buf.write_string("true")
#| False => buf.write_string("false")
#| Null => buf.write_string("null")
#| }
#| }
#| stringify_inner(self, 0)
#| buf.to_string()
#|}
#|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()
#|}
#|pub impl ToJson for Json with to_json(self) {
#| self
#|}
#|#callsite(autofill(args_loc, loc))
#|pub fn inspect(
#| obj : &ToJson,
#| content? : Json,
#| loc~ : SourceLoc,
#| args_loc~ : ArgsLoc,
#|) -> Unit raise InspectError {
#| let loc = loc.to_string().escape()
#| let args_loc = args_loc.to_json().escape()
#| let actual = obj.to_json().stringify(escape_slash=false)
#| let want = match content {
#| None => "".to_json().stringify(escape_slash=false)
#| Some(x) => x.stringify(escape_slash=false)
#| }
#| if actual != want {
#| raise InspectError(
#| "@EXPECT_FAILED {\"loc\": \{loc}, \"args_loc\": \{args_loc}, \"expect\": \{want.escape()}, \"actual\": \{actual.escape()}, \"mode\": \"json\"}",
#| )
#| }
#|}
),
"json_path.mbt": (
#|enum JsonPath {
#| Root
#| Key(JsonPath, mut key~ : String)
#| Index(JsonPath, mut index~ : Int)
#|} derive(Eq)
#|pub fn add_index(self : JsonPath, index : Int) -> JsonPath {
#| Index(self, index~)
#|}
#|pub fn add_key(self : JsonPath, key : String) -> JsonPath {
#| Key(self, key~)
#|}
#|pub impl Show for JsonPath with output(self, logger) {
#| match self {
#| Root => logger.write_string("$")
#| Key(p, key~) =>
#| logger..write_object(p)..write_string(".")..write_string(key)
#| Index(p, index~) =>
#| logger
#| ..write_object(p)
#| ..write_string("[")
#| ..write_object(index)
#| ..write_string("]")
#| }
#|}
#|pub impl ToJson for JsonPath with to_json(self) {
#| String(self.to_string())
#|}
#|test "show JsonPath" {
#| let path = Key(Index(Root, index=0), key="foo")
#| @builtin.inspect(path, content="$[0].foo")
#| @builtin.inspect(path.add_index(1), content="$[0].foo[1]")
#| @builtin.inspect(path.add_key("bar"), content="$[0].foo.bar")
#| @builtin.inspect(
#| Root.add_key("foo").add_key("foo1").add_index(2),
#| content="$.foo.foo1[2]",
#| )
#| @builtin.inspect(Root.add_key("foo").add_key("foo1"), content="$.foo.foo1")
#| @builtin.inspect(
#| Root.add_key("foo").add_key("foo1").add_index(2).add_key("bar"),
#| content="$.foo.foo1[2].bar",
#| )
#| @builtin.inspect(
#| Root.add_key("foo").add_key("foo1").add_index(2).add_key("bar").add_index(3),
#| content="$.foo.foo1[2].bar[3]",
#| )
#| @builtin.inspect(
#| Root
#| .add_key("foo")
#| .add_key("foo1")
#| .add_index(2)
#| .add_key("bar")
#| .add_index(3)
#| .add_key("baz"),
#| content="$.foo.foo1[2].bar[3].baz",
#| )
#| @builtin.inspect(
#| Root.add_key("foo").add_key("foo1").add_index(2).add_index(3).add_index(4),
#| content="$.foo.foo1[2][3][4]",
#| )
#|}
),
"lex_main.mbt": (
#|let non_ascii_whitespace : CharClass = CharClass::of([
#| ('\u00A0', '\u00A0'),
#| ('\u1680', '\u1680'),
#| ('\u2000', '\u200A'),
#| ('\u2028', '\u2029'),
#| ('\u202F', '\u202F'),
#| ('\u205F', '\u205F'),
#| ('\u3000', '\u3000'),
#| ('\uFEFF', '\uFEFF'),
#|])
#|fn ParseContext::lex_value(
#| ctx : ParseContext,
#| allow_rbracket~ : Bool,
#|) -> Token raise ParseError {
#| for {
#| match ctx.read_char() {
#| Some('\t' | ' ' | '\n' | '\r') => continue
#| Some('{') => return LBrace
#| Some('[') => return LBracket
#| Some(']') =>
#| if allow_rbracket {
#| return RBracket
#| } else {
#| ctx.invalid_char(shift=-1)
#| }
#| Some('n') => {
#| ctx.expect_ascii_char('u')
#| ctx.expect_ascii_char('l')
#| ctx.expect_ascii_char('l')
#| return Null
#| }
#| Some('t') => {
#| ctx.expect_ascii_char('r')
#| ctx.expect_ascii_char('u')
#| ctx.expect_ascii_char('e')
#| return True
#| }
#| Some('f') => {
#| ctx.expect_ascii_char('a')
#| ctx.expect_ascii_char('l')
#| ctx.expect_ascii_char('s')
#| ctx.expect_ascii_char('e')
#| return False
#| }
#| Some('-') =>
#| match ctx.read_char() {
#| Some('0') => {
#| let (n, repr) = ctx.lex_zero(start=ctx.offset - 2)
#| return Number(n, repr)
#| }
#| Some(c2) => {
#| if c2 is ('1'..='9') {
#| let (n, repr) = ctx.lex_decimal_integer(start=ctx.offset - 2)
#| return Number(n, repr)
#| }
#| ctx.invalid_char(shift=-1)
#| }
#| None => raise InvalidEof
#| }
#| Some('0') => {
#| let (n, repr) = ctx.lex_zero(start=ctx.offset - 1)
#| return Number(n, repr)
#| }
#| Some('1'..='9') => {
#| let (n, repr) = ctx.lex_decimal_integer(start=ctx.offset - 1)
#| return Number(n, repr)
#| }
#| Some('"') => {
#| let s = ctx.lex_string()
#| return String(s)
#| }
#| Some(c) => {
#| if c > '\u{7f}' && non_ascii_whitespace.contains(c) {
#| continue
#| }
#| let shift = -c.utf16_len()
#| ctx.invalid_char(shift~)
#| }
#| None => raise InvalidEof
#| }
#| }
#|}
),
"lex_misc.mbt": (
#|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
#| }
#|}
#|const SURROGATE_LOW_CHAR = 0xD800
#|const SURROGATE_HIGH_CHAR = 0xDFFF
#|fn ParseContext::expect_char(
#| ctx : ParseContext,
#| c : Char,
#|) -> Unit raise ParseError {
#| guard ctx.offset < ctx.end_offset else { raise InvalidEof }
#| let c1 = ctx.input.unsafe_charcode_at(ctx.offset)
#| ctx.offset += 1
#| let c0 = c.to_int()
#| if c0 < 0xFFFF {
#| if c0 != c1 {
#| ctx.invalid_char(shift=-1)
#| }
#| } else {
#| guard c1 is (SURROGATE_LOW_CHAR..=SURROGATE_HIGH_CHAR) &&
#| ctx.offset < ctx.end_offset else {
#| ctx.invalid_char(shift=-1)
#| }
#| let c2 = ctx.input.unsafe_charcode_at(ctx.offset)
#| let c3 = (c1 << 10) + c2 - 0x35fdc00
#| if c3 != c0 {
#| ctx.invalid_char(shift=-1)
#| } else {
#| ctx.offset += 1 // consume and move forward
#| }
#| }
#|}
#|fn ParseContext::expect_ascii_char(
#| ctx : ParseContext,
#| c : Byte,
#|) -> Unit raise ParseError {
#| guard ctx.offset < ctx.end_offset else { raise InvalidEof }
#| let c1 = ctx.input.unsafe_charcode_at(ctx.offset)
#| ctx.offset += 1
#| if c.to_int() != c1 {
#| ctx.invalid_char(shift=-1)
#| }
#|}
#|test "expect_char" {
#| let ctx = ParseContext::make("abc")
#| ctx.expect_char('a')
#| ctx.expect_char('b')
#| ctx.expect_char('c')
#| inspect(try? ctx.expect_char('d'), content={ "Err": "InvalidEof" })
#|}
#|test "expect_char with surrogate pair" {
#| let ctx = ParseContext::make("a\u{1F600}bc\u{1F600}c")
#| ctx.expect_char('a')
#| ctx.expect_char((0x1F600).unsafe_to_char())
#| ctx.expect_char('b')
#| ctx.expect_char('c')
#| ctx.expect_char((0x1F600).unsafe_to_char())
#| ctx.expect_char('c')
#| inspect(try? ctx.expect_char('d'), content={ "Err": "InvalidEof" })
#|}
#|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
#| }
#| }
#|}
#|fn ParseContext::lex_after_array_value(
#| ctx : ParseContext,
#|) -> Token raise ParseError {
#| ctx.lex_skip_whitespace()
#| match ctx.read_char() {
#| Some(']') => RBracket
#| Some(',') => Comma
#| Some(_) => ctx.invalid_char(shift=-1)
#| None => raise InvalidEof
#| }
#|}
#|fn ParseContext::lex_after_property_name(
#| ctx : ParseContext,
#|) -> Unit raise ParseError {
#| ctx.lex_skip_whitespace()
#| match ctx.read_char() {
#| Some(':') => ()
#| Some(_) => ctx.invalid_char(shift=-1)
#| None => raise InvalidEof
#| }
#|}
#|fn ParseContext::lex_after_object_value(
#| ctx : ParseContext,
#|) -> Token raise ParseError {
#| ctx.lex_skip_whitespace()
#| match ctx.read_char() {
#| Some('}') => RBrace
#| Some(',') => Comma
#| Some(_) => ctx.invalid_char(shift=-1)
#| None => raise InvalidEof
#| }
#|}
#|fn ParseContext::lex_property_name(
#| ctx : ParseContext,
#|) -> Token raise ParseError {
#| ctx.lex_skip_whitespace()
#| match ctx.read_char() {
#| Some('}') => RBrace
#| Some('"') => {
#| let s = ctx.lex_string()
#| String(s)
#| }
#| Some(_) => ctx.invalid_char(shift=-1)
#| None => raise InvalidEof
#| }
#|}
#|fn ParseContext::lex_property_name2(
#| ctx : ParseContext,
#|) -> Token raise ParseError {
#| ctx.lex_skip_whitespace()
#| match ctx.read_char() {
#| Some('"') => {
#| let s = ctx.lex_string()
#| String(s)
#| }
#| Some(_) => ctx.invalid_char(shift=-1)
#| None => raise InvalidEof
#| }
#|}
),
"lex_number.mbt": (
#|fn ParseContext::lex_decimal_integer(
#| ctx : ParseContext,
#| start~ : Int,
#|) -> (Double, String?) raise ParseError {
#| for {
#| match ctx.read_char() {
#| Some('.') => return ctx.lex_decimal_point(start~)
#| Some('e' | 'E') => return ctx.lex_decimal_exponent(start~)
#| Some(c) => {
#| if c >= '0' && c <= '9' {
#| continue
#| }
#| ctx.offset -= 1
#| return ctx.lex_number_end(start, ctx.offset)
#| }
#| None => return ctx.lex_number_end(start, ctx.offset)
#| }
#| }
#|}
#|fn ParseContext::lex_decimal_point(
#| ctx : ParseContext,
#| start~ : Int,
#|) -> (Double, String?) raise ParseError {
#| match ctx.read_char() {
#| Some(c) =>
#| if c >= '0' && c <= '9' {
#| ctx.lex_decimal_fraction(start~)
#| } else {
#| ctx.invalid_char(shift=-1)
#| }
#| None => raise InvalidEof
#| }
#|}
#|fn ParseContext::lex_decimal_fraction(
#| ctx : ParseContext,
#| start~ : Int,
#|) -> (Double, String?) raise ParseError {
#| for {
#| match ctx.read_char() {
#| Some('e' | 'E') => return ctx.lex_decimal_exponent(start~)
#| Some(c) => {
#| if c >= '0' && c <= '9' {
#| continue
#| }
#| ctx.offset -= 1
#| return ctx.lex_number_end(start, ctx.offset)
#| }
#| None => return ctx.lex_number_end(start, ctx.offset)
#| }
#| }
#|}
#|fn ParseContext::lex_decimal_exponent(
#| ctx : ParseContext,
#| start~ : Int,
#|) -> (Double, String?) raise ParseError {
#| match ctx.read_char() {
#| Some('+') | Some('-') => return ctx.lex_decimal_exponent_sign(start~)
#| Some(c) => {
#| if c >= '0' && c <= '9' {
#| return ctx.lex_decimal_exponent_integer(start~)
#| }
#| ctx.offset -= 1
#| ctx.invalid_char()
#| }
#| None => raise InvalidEof
#| }
#|}
#|fn ParseContext::lex_decimal_exponent_sign(
#| ctx : ParseContext,
#| start~ : Int,
#|) -> (Double, String?) raise ParseError {
#| match ctx.read_char() {
#| Some(c) => {
#| if c >= '0' && c <= '9' {
#| return ctx.lex_decimal_exponent_integer(start~)
#| }
#| ctx.offset -= 1
#| ctx.invalid_char()
#| }
#| None => raise InvalidEof
#| }
#|}
#|fn ParseContext::lex_decimal_exponent_integer(
#| ctx : ParseContext,
#| start~ : Int,
#|) -> (Double, String?) {
#| for {
#| match ctx.read_char() {
#| Some(c) => {
#| if c >= '0' && c <= '9' {
#| continue
#| }
#| ctx.offset -= 1
#| return ctx.lex_number_end(start, ctx.offset)
#| }
#| None => return ctx.lex_number_end(start, ctx.offset)
#| }
#| }
#|}
#|fn ParseContext::lex_zero(
#| ctx : ParseContext,
#| start~ : Int,
#|) -> (Double, String?) raise ParseError {
#| match ctx.read_char() {
#| Some('.') => ctx.lex_decimal_point(start~)
#| Some('e' | 'E') => ctx.lex_decimal_exponent(start~)
#| Some(c) => {
#| if c >= '0' && c <= '9' {
#| ctx.offset -= 1
#| ctx.invalid_char()
#| }
#| ctx.offset -= 1
#| return ctx.lex_number_end(start, ctx.offset)
#| }
#| None => return ctx.lex_number_end(start, ctx.offset)
#| }
#|}
#|fn ParseContext::lex_number_end(
#| ctx : ParseContext,
#| start : Int,
#| end : Int,
#|) -> (Double, String?) {
#| let s = ctx.input.substring(start~, end~)
#| if !s.contains(".") && !s.contains("e") && !s.contains("E") {
#| let parsed_int = try? @strconv.parse_int64(s)
#| match parsed_int {
#| Ok(i) if i <= 9007199254740991 && i >= -9007199254740991 =>
#| return (i.to_double(), None)
#| _ =>
#| return if s is ['-', ..] {
#| (@double.neg_infinity, Some(s))
#| } else {
#| (@double.infinity, Some(s))
#| }
#| }
#| } else {
#| let parsed_double = try? @strconv.parse_double(s)
#| match parsed_double {
#| Ok(d) => (d, None)
#| Err(_) =>
#| if s is ['-', ..] {
#| (@double.neg_infinity, Some(s))
#| } else {
#| (@double.infinity, Some(s))
#| }
#| }
#| }
#|}
),
"lex_string.mbt": (
#|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()
#|}
#|fn ParseContext::lex_hex_digits(
#| ctx : ParseContext,
#| n : Int,
#|) -> Int raise ParseError {
#| let mut r = 0
#| for i in 0..
#| if c >= 'A' {
#| let d = (c.to_int() & (32).lnot()) - 'A'.to_int() + 10
#| if d > 15 {
#| ctx.invalid_char(shift=-1)
#| }
#| r = (r << 4) | d
#| } else if c >= '0' {
#| let d = c.to_int() - '0'.to_int()
#| if d > 9 {
#| ctx.invalid_char(shift=-1)
#| }
#| r = (r << 4) | d
#| } else {
#| ctx.invalid_char(shift=-1)
#| }
#| None => raise InvalidEof
#| }
#| }
#| r
#|}
),
"parse.mbt": (
#|pub fn valid(input : String) -> Bool {
#| try {
#| parse(input) |> ignore
#| true
#| } catch {
#| _ => return false
#| }
#|}
#|pub fn parse(input : String) -> Json 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()
#| }
#|}
#|fn ParseContext::parse_value(ctx : ParseContext) -> Json raise ParseError {
#| let tok = ctx.lex_value(allow_rbracket=false)
#| ctx.parse_value2(tok)
#|}
#|fn ParseContext::parse_value2(
#| ctx : ParseContext,
#| tok : Token,
#|) -> Json raise ParseError {
#| match tok {
#| Null => null
#| True => Json::boolean(true)
#| False => Json::boolean(false)
#| Number(n, repr) => Json::number(n, repr?)
#| String(s) => Json::string(s)
#| LBrace => ctx.parse_object()
#| LBracket => ctx.parse_array()
#| RBracket | RBrace | Comma => abort("unreachable")
#| }
#|}
#|fn ParseContext::parse_object(ctx : ParseContext) -> Json 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")
#| }
#|}
#|fn ParseContext::parse_array(ctx : ParseContext) -> Json 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")
#| }
#| }
#| }
#|}
),
"tuple_fromjson.mbt": (
#|pub impl[A : FromJson, B : FromJson] FromJson for (A, B) with from_json(
#| json,
#| path,
#|) {
#| match json {
#| [a, b] => {
#| let a : A = FromJson::from_json(a, path.add_index(0))
#| let b : B = FromJson::from_json(b, path.add_index(1))
#| (a, b)
#| }
#| _ => decode_error(path, "expected tuple of size 2")
#| }
#|}
#|pub impl[A : FromJson, B : FromJson, C : FromJson] FromJson for (A, B, C) with from_json(
#| json,
#| path,
#|) {
#| match json {
#| [a, b, c] => {
#| let a : A = FromJson::from_json(a, path.add_index(0))
#| let b : B = FromJson::from_json(b, path.add_index(1))
#| let c : C = FromJson::from_json(c, path.add_index(2))
#| (a, b, c)
#| }
#| _ => decode_error(path, "expected tuple of size 3")
#| }
#|}
#|pub impl[A : FromJson, B : FromJson, C : FromJson, D : FromJson] FromJson for (
#| A,
#| B,
#| C,
#| D,
#|) with from_json(json, path) {
#| match json {
#| [a, b, c, d] => {
#| let a : A = FromJson::from_json(a, path.add_index(0))
#| let b : B = FromJson::from_json(b, path.add_index(1))
#| let c : C = FromJson::from_json(c, path.add_index(2))
#| let d : D = FromJson::from_json(d, path.add_index(3))
#| (a, b, c, d)
#| }
#| _ => decode_error(path, "expected tuple of size 4")
#| }
#|}
#|pub impl[A : FromJson, B : FromJson, C : FromJson, D : FromJson, E : FromJson] FromJson for (
#| A,
#| B,
#| C,
#| D,
#| E,
#|) with from_json(json, path) {
#| match json {
#| [a, b, c, d, e] => {
#| let a : A = FromJson::from_json(a, path.add_index(0))
#| let b : B = FromJson::from_json(b, path.add_index(1))
#| let c : C = FromJson::from_json(c, path.add_index(2))
#| let d : D = FromJson::from_json(d, path.add_index(3))
#| let e : E = FromJson::from_json(e, path.add_index(4))
#| (a, b, c, d, e)
#| }
#| _ => decode_error(path, "expected tuple of size 5")
#| }
#|}
#|pub impl[
#| A : FromJson,
#| B : FromJson,
#| C : FromJson,
#| D : FromJson,
#| E : FromJson,
#| F : FromJson,
#|] FromJson for (A, B, C, D, E, F) with from_json(json, path) {
#| match json {
#| [a, b, c, d, e, f] => {
#| let a : A = FromJson::from_json(a, path.add_index(0))
#| let b : B = FromJson::from_json(b, path.add_index(1))
#| let c : C = FromJson::from_json(c, path.add_index(2))
#| let d : D = FromJson::from_json(d, path.add_index(3))
#| let e : E = FromJson::from_json(e, path.add_index(4))
#| let f : F = FromJson::from_json(f, path.add_index(5))
#| (a, b, c, d, e, f)
#| }
#| _ => decode_error(path, "expected tuple of size 6")
#| }
#|}
#|pub impl[
#| A : FromJson,
#| B : FromJson,
#| C : FromJson,
#| D : FromJson,
#| E : FromJson,
#| F : FromJson,
#| G : FromJson,
#|] FromJson for (A, B, C, D, E, F, G) with from_json(json, path) {
#| match json {
#| [a, b, c, d, e, f, g] => {
#| let a : A = FromJson::from_json(a, path.add_index(0))
#| let b : B = FromJson::from_json(b, path.add_index(1))
#| let c : C = FromJson::from_json(c, path.add_index(2))
#| let d : D = FromJson::from_json(d, path.add_index(3))
#| let e : E = FromJson::from_json(e, path.add_index(4))
#| let f : F = FromJson::from_json(f, path.add_index(5))
#| let g : G = FromJson::from_json(g, path.add_index(6))
#| (a, b, c, d, e, f, g)
#| }
#| _ => decode_error(path, "expected tuple of size 7")
#| }
#|}
#|pub impl[
#| T0 : FromJson,
#| T1 : FromJson,
#| T2 : FromJson,
#| T3 : FromJson,
#| T4 : FromJson,
#| T5 : FromJson,
#| T6 : FromJson,
#| T7 : FromJson,
#|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7) with from_json(json, path) {
#| match json {
#| [x0, x1, x2, x3, x4, x5, x6, x7] => {
#| let x0 : T0 = FromJson::from_json(x0, path.add_index(0))
#| let x1 : T1 = FromJson::from_json(x1, path.add_index(1))
#| let x2 : T2 = FromJson::from_json(x2, path.add_index(2))
#| let x3 : T3 = FromJson::from_json(x3, path.add_index(3))
#| let x4 : T4 = FromJson::from_json(x4, path.add_index(4))
#| let x5 : T5 = FromJson::from_json(x5, path.add_index(5))
#| let x6 : T6 = FromJson::from_json(x6, path.add_index(6))
#| let x7 : T7 = FromJson::from_json(x7, path.add_index(7))
#| (x0, x1, x2, x3, x4, x5, x6, x7)
#| }
#| _ => decode_error(path, "expected tuple of size 8")
#| }
#|}
#|pub impl[
#| T0 : FromJson,
#| T1 : FromJson,
#| T2 : FromJson,
#| T3 : FromJson,
#| T4 : FromJson,
#| T5 : FromJson,
#| T6 : FromJson,
#| T7 : FromJson,
#| T8 : FromJson,
#|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8) with from_json(json, path) {
#| match json {
#| [x0, x1, x2, x3, x4, x5, x6, x7, x8] => {
#| let x0 : T0 = FromJson::from_json(x0, path.add_index(0))
#| let x1 : T1 = FromJson::from_json(x1, path.add_index(1))
#| let x2 : T2 = FromJson::from_json(x2, path.add_index(2))
#| let x3 : T3 = FromJson::from_json(x3, path.add_index(3))
#| let x4 : T4 = FromJson::from_json(x4, path.add_index(4))
#| let x5 : T5 = FromJson::from_json(x5, path.add_index(5))
#| let x6 : T6 = FromJson::from_json(x6, path.add_index(6))
#| let x7 : T7 = FromJson::from_json(x7, path.add_index(7))
#| let x8 : T8 = FromJson::from_json(x8, path.add_index(8))
#| (x0, x1, x2, x3, x4, x5, x6, x7, x8)
#| }
#| _ => decode_error(path, "expected tuple of size 9")
#| }
#|}
#|pub impl[
#| T0 : FromJson,
#| T1 : FromJson,
#| T2 : FromJson,
#| T3 : FromJson,
#| T4 : FromJson,
#| T5 : FromJson,
#| T6 : FromJson,
#| T7 : FromJson,
#| T8 : FromJson,
#| T9 : FromJson,
#|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) with from_json(
#| json,
#| path,
#|) {
#| match json {
#| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9] => {
#| let x0 : T0 = FromJson::from_json(x0, path.add_index(0))
#| let x1 : T1 = FromJson::from_json(x1, path.add_index(1))
#| let x2 : T2 = FromJson::from_json(x2, path.add_index(2))
#| let x3 : T3 = FromJson::from_json(x3, path.add_index(3))
#| let x4 : T4 = FromJson::from_json(x4, path.add_index(4))
#| let x5 : T5 = FromJson::from_json(x5, path.add_index(5))
#| let x6 : T6 = FromJson::from_json(x6, path.add_index(6))
#| let x7 : T7 = FromJson::from_json(x7, path.add_index(7))
#| let x8 : T8 = FromJson::from_json(x8, path.add_index(8))
#| let x9 : T9 = FromJson::from_json(x9, path.add_index(9))
#| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9)
#| }
#| _ => decode_error(path, "expected tuple of size 10")
#| }
#|}
#|pub impl[
#| T0 : FromJson,
#| T1 : FromJson,
#| T2 : FromJson,
#| T3 : FromJson,
#| T4 : FromJson,
#| T5 : FromJson,
#| T6 : FromJson,
#| T7 : FromJson,
#| T8 : FromJson,
#| T9 : FromJson,
#| T10 : FromJson,
#|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) with from_json(
#| json,
#| path,
#|) {
#| match json {
#| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10] => {
#| let x0 : T0 = FromJson::from_json(x0, path.add_index(0))
#| let x1 : T1 = FromJson::from_json(x1, path.add_index(1))
#| let x2 : T2 = FromJson::from_json(x2, path.add_index(2))
#| let x3 : T3 = FromJson::from_json(x3, path.add_index(3))
#| let x4 : T4 = FromJson::from_json(x4, path.add_index(4))
#| let x5 : T5 = FromJson::from_json(x5, path.add_index(5))
#| let x6 : T6 = FromJson::from_json(x6, path.add_index(6))
#| let x7 : T7 = FromJson::from_json(x7, path.add_index(7))
#| let x8 : T8 = FromJson::from_json(x8, path.add_index(8))
#| let x9 : T9 = FromJson::from_json(x9, path.add_index(9))
#| let x10 : T10 = FromJson::from_json(x10, path.add_index(10))
#| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)
#| }
#| _ => decode_error(path, "expected tuple of size 11")
#| }
#|}
#|pub impl[
#| T0 : FromJson,
#| T1 : FromJson,
#| T2 : FromJson,
#| T3 : FromJson,
#| T4 : FromJson,
#| T5 : FromJson,
#| T6 : FromJson,
#| T7 : FromJson,
#| T8 : FromJson,
#| T9 : FromJson,
#| T10 : FromJson,
#| T11 : FromJson,
#|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) with from_json(
#| json,
#| path,
#|) {
#| match json {
#| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11] => {
#| let x0 : T0 = FromJson::from_json(x0, path.add_index(0))
#| let x1 : T1 = FromJson::from_json(x1, path.add_index(1))
#| let x2 : T2 = FromJson::from_json(x2, path.add_index(2))
#| let x3 : T3 = FromJson::from_json(x3, path.add_index(3))
#| let x4 : T4 = FromJson::from_json(x4, path.add_index(4))
#| let x5 : T5 = FromJson::from_json(x5, path.add_index(5))
#| let x6 : T6 = FromJson::from_json(x6, path.add_index(6))
#| let x7 : T7 = FromJson::from_json(x7, path.add_index(7))
#| let x8 : T8 = FromJson::from_json(x8, path.add_index(8))
#| let x9 : T9 = FromJson::from_json(x9, path.add_index(9))
#| let x10 : T10 = FromJson::from_json(x10, path.add_index(10))
#| let x11 : T11 = FromJson::from_json(x11, path.add_index(11))
#| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)
#| }
#| _ => decode_error(path, "expected tuple of size 12")
#| }
#|}
#|pub impl[
#| T0 : FromJson,
#| T1 : FromJson,
#| T2 : FromJson,
#| T3 : FromJson,
#| T4 : FromJson,
#| T5 : FromJson,
#| T6 : FromJson,
#| T7 : FromJson,
#| T8 : FromJson,
#| T9 : FromJson,
#| T10 : FromJson,
#| T11 : FromJson,
#| T12 : FromJson,
#|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) with from_json(
#| json,
#| path,
#|) {
#| match json {
#| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12] => {
#| let x0 : T0 = FromJson::from_json(x0, path.add_index(0))
#| let x1 : T1 = FromJson::from_json(x1, path.add_index(1))
#| let x2 : T2 = FromJson::from_json(x2, path.add_index(2))
#| let x3 : T3 = FromJson::from_json(x3, path.add_index(3))
#| let x4 : T4 = FromJson::from_json(x4, path.add_index(4))
#| let x5 : T5 = FromJson::from_json(x5, path.add_index(5))
#| let x6 : T6 = FromJson::from_json(x6, path.add_index(6))
#| let x7 : T7 = FromJson::from_json(x7, path.add_index(7))
#| let x8 : T8 = FromJson::from_json(x8, path.add_index(8))
#| let x9 : T9 = FromJson::from_json(x9, path.add_index(9))
#| let x10 : T10 = FromJson::from_json(x10, path.add_index(10))
#| let x11 : T11 = FromJson::from_json(x11, path.add_index(11))
#| let x12 : T12 = FromJson::from_json(x12, path.add_index(12))
#| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12)
#| }
#| _ => decode_error(path, "expected tuple of size 13")
#| }
#|}
#|pub impl[
#| T0 : FromJson,
#| T1 : FromJson,
#| T2 : FromJson,
#| T3 : FromJson,
#| T4 : FromJson,
#| T5 : FromJson,
#| T6 : FromJson,
#| T7 : FromJson,
#| T8 : FromJson,
#| T9 : FromJson,
#| T10 : FromJson,
#| T11 : FromJson,
#| T12 : FromJson,
#| T13 : FromJson,
#|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) with from_json(
#| json,
#| path,
#|) {
#| match json {
#| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13] => {
#| let x0 : T0 = FromJson::from_json(x0, path.add_index(0))
#| let x1 : T1 = FromJson::from_json(x1, path.add_index(1))
#| let x2 : T2 = FromJson::from_json(x2, path.add_index(2))
#| let x3 : T3 = FromJson::from_json(x3, path.add_index(3))
#| let x4 : T4 = FromJson::from_json(x4, path.add_index(4))
#| let x5 : T5 = FromJson::from_json(x5, path.add_index(5))
#| let x6 : T6 = FromJson::from_json(x6, path.add_index(6))
#| let x7 : T7 = FromJson::from_json(x7, path.add_index(7))
#| let x8 : T8 = FromJson::from_json(x8, path.add_index(8))
#| let x9 : T9 = FromJson::from_json(x9, path.add_index(9))
#| let x10 : T10 = FromJson::from_json(x10, path.add_index(10))
#| let x11 : T11 = FromJson::from_json(x11, path.add_index(11))
#| let x12 : T12 = FromJson::from_json(x12, path.add_index(12))
#| let x13 : T13 = FromJson::from_json(x13, path.add_index(13))
#| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13)
#| }
#| _ => decode_error(path, "expected tuple of size 14")
#| }
#|}
#|pub impl[
#| T0 : FromJson,
#| T1 : FromJson,
#| T2 : FromJson,
#| T3 : FromJson,
#| T4 : FromJson,
#| T5 : FromJson,
#| T6 : FromJson,
#| T7 : FromJson,
#| T8 : FromJson,
#| T9 : FromJson,
#| T10 : FromJson,
#| T11 : FromJson,
#| T12 : FromJson,
#| T13 : FromJson,
#| T14 : FromJson,
#|] FromJson for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) with from_json(
#| json,
#| path,
#|) {
#| match json {
#| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14] => {
#| let x0 : T0 = FromJson::from_json(x0, path.add_index(0))
#| let x1 : T1 = FromJson::from_json(x1, path.add_index(1))
#| let x2 : T2 = FromJson::from_json(x2, path.add_index(2))
#| let x3 : T3 = FromJson::from_json(x3, path.add_index(3))
#| let x4 : T4 = FromJson::from_json(x4, path.add_index(4))
#| let x5 : T5 = FromJson::from_json(x5, path.add_index(5))
#| let x6 : T6 = FromJson::from_json(x6, path.add_index(6))
#| let x7 : T7 = FromJson::from_json(x7, path.add_index(7))
#| let x8 : T8 = FromJson::from_json(x8, path.add_index(8))
#| let x9 : T9 = FromJson::from_json(x9, path.add_index(9))
#| let x10 : T10 = FromJson::from_json(x10, path.add_index(10))
#| let x11 : T11 = FromJson::from_json(x11, path.add_index(11))
#| let x12 : T12 = FromJson::from_json(x12, path.add_index(12))
#| let x13 : T13 = FromJson::from_json(x13, path.add_index(13))
#| let x14 : T14 = FromJson::from_json(x14, path.add_index(14))
#| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14)
#| }
#| _ => decode_error(path, "expected tuple of size 15")
#| }
#|}
#|pub impl[
#| T0 : FromJson,
#| T1 : FromJson,
#| T2 : FromJson,
#| T3 : FromJson,
#| T4 : FromJson,
#| T5 : FromJson,
#| T6 : FromJson,
#| T7 : FromJson,
#| T8 : FromJson,
#| T9 : FromJson,
#| T10 : FromJson,
#| T11 : FromJson,
#| T12 : FromJson,
#| T13 : FromJson,
#| T14 : FromJson,
#| T15 : FromJson,
#|] FromJson for (
#| T0,
#| T1,
#| T2,
#| T3,
#| T4,
#| T5,
#| T6,
#| T7,
#| T8,
#| T9,
#| T10,
#| T11,
#| T12,
#| T13,
#| T14,
#| T15,
#|) with from_json(json, path) {
#| match json {
#| [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15] => {
#| let x0 : T0 = FromJson::from_json(x0, path.add_index(0))
#| let x1 : T1 = FromJson::from_json(x1, path.add_index(1))
#| let x2 : T2 = FromJson::from_json(x2, path.add_index(2))
#| let x3 : T3 = FromJson::from_json(x3, path.add_index(3))
#| let x4 : T4 = FromJson::from_json(x4, path.add_index(4))
#| let x5 : T5 = FromJson::from_json(x5, path.add_index(5))
#| let x6 : T6 = FromJson::from_json(x6, path.add_index(6))
#| let x7 : T7 = FromJson::from_json(x7, path.add_index(7))
#| let x8 : T8 = FromJson::from_json(x8, path.add_index(8))
#| let x9 : T9 = FromJson::from_json(x9, path.add_index(9))
#| let x10 : T10 = FromJson::from_json(x10, path.add_index(10))
#| let x11 : T11 = FromJson::from_json(x11, path.add_index(11))
#| let x12 : T12 = FromJson::from_json(x12, path.add_index(12))
#| let x13 : T13 = FromJson::from_json(x13, path.add_index(13))
#| let x14 : T14 = FromJson::from_json(x14, path.add_index(14))
#| let x15 : T15 = FromJson::from_json(x15, path.add_index(15))
#| (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15)
#| }
#| _ => decode_error(path, "expected tuple of size 16")
#| }
#|}
),
"types.mbt": (
#|pub(all) struct Position {
#| line : Int // 1-based
#| column : Int // 0-based
#|} derive(Eq, ToJson)
#|pub(all) suberror ParseError {
#| InvalidChar(Position, Char)
#| InvalidEof
#| InvalidNumber(Position, String)
#| InvalidIdentEscape(Position)
#|} derive(Eq, ToJson(style="flat"))
#|pub impl Show for ParseError with output(self, logger) {
#| match self {
#| InvalidChar({ line, column }, c) =>
#| logger
#| ..write_string("Invalid character ")
#| ..write_string(repr(c))
#| ..write_string(" at line ")
#| ..write_object(line)
#| ..write_string(", column ")
#| ..write_object(column)
#| InvalidEof => logger.write_string("Unexpected end of file")
#| InvalidNumber({ line, column }, s) =>
#| logger
#| ..write_string("Invalid number ")
#| ..write_string(s)
#| ..write_string(" at line ")
#| ..write_object(line)
#| ..write_string(", column ")
#| ..write_object(column)
#| InvalidIdentEscape({ line, column }) =>
#| logger
#| ..write_string("Invalid escape sequence in identifier at line ")
#| ..write_object(line)
#| ..write_string(", column ")
#| ..write_object(column)
#| }
#|}
#|pub impl Show for Json with output(self, logger) {
#| match self {
#| Null => logger.write_string("Null")
#| True => logger.write_string("True")
#| False => logger.write_string("False")
#| Number(n, repr~) => {
#| logger.write_string("Number(")
#| Show::output(n, logger)
#| if repr is Some(_) {
#| logger.write_string(", repr=")
#| Show::output(repr, logger)
#| }
#| logger.write_string(")")
#| }
#| String(s) => {
#| logger.write_string("String(")
#| Show::output(s, logger)
#| logger.write_string(")")
#| }
#| Array(a) => {
#| logger.write_string("Array(")
#| Show::output(a, logger)
#| logger.write_string(")")
#| }
#| Object(o) => {
#| logger.write_string("Object(")
#| Show::output(o, logger)
#| logger.write_string(")")
#| }
#| }
#|}
),
"utils.mbt": (
#|fn offset_to_position(input : String, offset : Int) -> Position {
#| let mut line = 1
#| let mut column = 0
#| for i in 0.. T raise ParseError {
#| let offset = ctx.offset + shift
#| let replacement_char : Char = '\u{fffd}'
#| raise InvalidChar(
#| offset_to_position(ctx.input, offset),
#| ctx.input.get_char(offset).unwrap_or(replacement_char),
#| )
#|}
),
},
)
///|
let moonbitlang_core_list_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/array",
#| "moonbitlang/core/quickcheck",
#| "moonbitlang/core/json"
#| ],
#| "test-import": [],
#| "targets": {
#| "panic_test.mbt": [
#| "not",
#| "native"
#| ]
#| }
#|}
),
"deprecated.mbt": (
#|#deprecated("use `_.to_array().rev_fold(...)` instead")
#|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
#|}
#|#deprecated("use `_.rev().foldi(...)` instead")
#|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))
#|}
#|#deprecated("use `unsafe_tail` instead")
#|pub fn[A] tail(self : List[A]) -> List[A] {
#| match self {
#| Empty => Empty
#| More(_, tail~) => tail
#| }
#|}
),
"list.mbt": (
#|pub fn[A] new() -> List[A] {
#| Empty
#|}
#|pub fn[A] empty() -> List[A] {
#| Empty
#|}
#|pub fn[A] construct(head : A, tail : List[A]) -> List[A] {
#| More(head, tail~)
#|}
#|pub fn[A] prepend(self : List[A], head : A) -> List[A] {
#| More(head, tail=self)
#|}
#|pub fn[A] add(self : List[A], head : A) -> List[A] {
#| More(head, tail=self)
#|}
#|pub impl[A : Show] Show for List[A] with output(xs, logger) {
#| logger.write_iter(xs.iter(), prefix="@list.of([", suffix="])")
#|}
#|pub impl[A : ToJson] ToJson for List[A] with to_json(self) {
#| let capacity = self.length()
#| guard capacity != 0 else { return [] }
#| let jsons = Array::new(capacity~)
#| for a in self {
#| jsons.push(a.to_json())
#| }
#| Json::array(jsons)
#|}
#|pub fn[A : ToJson] to_json(self : List[A]) -> Json {
#| ToJson::to_json(self)
#|}
#|pub impl[A : @json.FromJson] @json.FromJson for List[A] with from_json(
#| json,
#| path,
#|) {
#| guard json is Array(arr) else {
#| raise @json.JsonDecodeError((path, "@list.from_json: expected array"))
#| }
#| for i = arr.length() - 1, list = Empty; i >= 0; {
#| continue i - 1, list.prepend(A::from_json(arr[i], path.add_index(i)))
#| } else {
#| list
#| }
#|}
#|pub fn[A : @json.FromJson] from_json(
#| json : Json,
#|) -> List[A] raise @json.JsonDecodeError {
#| @json.from_json(json)
#|}
#|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
#| }
#|}
#|pub fn[A] length(self : List[A]) -> Int {
#| loop (self, 0) {
#| (Empty, len) => len
#| (More(_, tail=rest), acc) => continue (rest, acc + 1)
#| }
#|}
#|#locals(f)
#|pub fn[A] each(self : List[A], f : (A) -> Unit raise?) -> Unit raise? {
#| loop self {
#| Empty => ()
#| More(head, tail~) => {
#| f(head)
#| continue tail
#| }
#| }
#|}
#|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)
#| }
#| }
#|}
#|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)
#| }
#| (Empty, _) => panic()
#| }
#| dest
#| }
#| }
#|}
#|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)
#| }
#| (_, Empty, _) => panic()
#| }
#| dest
#| }
#| }
#|}
#|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)
#| }
#|}
#|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
#| }
#| }
#|}
#|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, _) =>
#| panic()
#| }
#| dest
#| }
#| }
#|}
#|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 }
#| }
#|}
#|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 }
#| }
#|}
#|#internal(unsafe, "Panic if the list is empty")
#|pub fn[A] unsafe_head(self : List[A]) -> A {
#| match self {
#| Empty => abort("head of empty list")
#| More(head, tail=_) => head
#| }
#|}
#|pub fn[A] unsafe_tail(self : List[A]) -> List[A] {
#| match self {
#| Empty => abort("tail of empty list")
#| More(_, tail~) => tail
#| }
#|}
#|pub fn[A] head(self : List[A]) -> A? {
#| match self {
#| Empty => None
#| More(head, tail=_) => Some(head)
#| }
#|}
#|#internal(unsafe, "Panic if the list is empty")
#|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
#| }
#|}
#|pub fn[A] last(self : List[A]) -> A? {
#| loop self {
#| Empty => None
#| More(head, tail=Empty) => Some(head)
#| More(_, tail~) => continue tail
#| }
#|}
#|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)
#| }
#| (Empty, _) => panic()
#| }
#| dest
#| }
#| }
#|}
#|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))
#| }
#|}
#|pub fn[A] rev(self : List[A]) -> List[A] {
#| self.rev_concat(Empty)
#|}
#|pub fn[A, B] fold(
#| self : List[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| loop (self, init) {
#| (Empty, acc) => acc
#| (More(head, tail~), acc) => continue (tail, f(acc, head))
#| }
#|}
#|pub fn[A, B] foldi(
#| self : List[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| fn go(
#| xs : List[A],
#| i : Int,
#| f : (Int, B, A) -> B raise?,
#| acc : B,
#| ) -> B raise? {
#| match xs {
#| Empty => acc
#| More(x, tail=xs) => go(xs, i + 1, f, f(i, acc, x))
#| }
#| }
#| go(self, 0, f, init)
#|}
#|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()
#|}
#|pub fn[A, B] flat_map(
#| self : List[A],
#| f : (A) -> List[B] raise?,
#|) -> List[B] raise? {
#| loop self {
#| Empty => Empty
#| More(head, tail~) =>
#| match f(head) {
#| Empty => continue tail
#| More(hd, tail=tl) => {
#| let dest = More(hd, tail=Empty)
#| 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()
#| }
#| loop_over_tail~: loop (dest1, tail) {
#| (_, Empty) => ()
#| (More(_) as dest, More(t_hd, tail=Empty)) => dest.tail = f(t_hd)
#| (dest, More(t_hd, tail=t_tl)) =>
#| loop (dest, f(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
#| }
#| }
#| }
#|}
#|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
#| }
#| }
#| }
#|}
#|#internal(unsafe, "Panic if the index is out of bounds")
#|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)
#| }
#|}
#|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)
#| }
#|}
#|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) }
#| }
#|}
#|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)
#| }
#| (Empty, _) => panic()
#| }
#| dest
#| }
#| }
#|}
#|pub fn[A] is_empty(self : List[A]) -> Bool {
#| self is Empty
#|}
#|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)
#| }
#| }
#|}
#|pub fn[A] flatten(self : List[List[A]]) -> List[A] {
#| loop self {
#| Empty => Empty
#| More(head, tail~) =>
#| match head {
#| Empty => continue tail
#| More(hd, tail=tl) => {
#| let dest = More(hd, tail=Empty)
#| 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()
#| }
#| 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
#| }
#| }
#| }
#|}
#|#internal(unsafe, "Panic if the list is empty")
#|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 })
#| }
#| }
#|}
#|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 })
#| }
#| }
#|}
#|#internal(unsafe, "Panic if the list is empty")
#|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 })
#| }
#| }
#|}
#|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 })
#| }
#| }
#|}
#|pub fn[A : Compare] sort(self : List[A]) -> List[A] {
#| let arr = self.to_array()
#| arr.sort()
#| from_array(arr)
#|}
#|pub impl[A] Add for List[A] with add(self, other) {
#| self.concat(other)
#|}
#|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 }
#| }
#|}
#|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
#| }
#| }
#|}
#|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))
#| }
#|}
#|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
#| }
#| }
#| }
#|}
#|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)
#| }
#| }
#|}
#|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
#| }
#| }
#|}
#|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) }
#| }
#|}
#|pub fn[A, E] scan_left(
#| self : List[A],
#| f : (E, A) -> E raise?,
#| init~ : E,
#|) -> List[E] raise? {
#| let dest = More(init, tail=Empty)
#| loop (dest, self, init) {
#| (_, Empty, _) => ()
#| (Empty, _, _) => panic()
#| (More(_) as dest, More(x, tail=xs), acc) => {
#| dest.tail = More(f(acc, x), tail=Empty)
#| continue (dest.tail, xs, f(acc, x))
#| }
#| }
#| dest
#|}
#|pub fn[A, B] scan_right(
#| self : List[A],
#| f : (B, A) -> B raise?,
#| init~ : B,
#|) -> List[B] raise? {
#| self.rev().scan_left(f, init~).reverse_inplace()
#|}
#|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 }
#| }
#|}
#|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
#| }
#| }
#|}
#|pub fn[A] List::find_index(
#| self : Self[A],
#| f : (A) -> Bool raise?,
#|) -> Int? raise? {
#| loop (self, 0) {
#| (Empty, _) => None
#| (More(element, tail=list), idx) =>
#| if f(element) {
#| Some(idx)
#| } else {
#| continue (list, idx + 1)
#| }
#| }
#|}
#|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)
#| }
#| }
#| }
#|}
#|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
#| }
#| }
#|}
#|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
#| }
#| }
#|}
#|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
#| }
#| }
#|}
#|pub fn[A : Eq] is_suffix(self : List[A], suffix : List[A]) -> Bool {
#| self.rev().is_prefix(suffix.rev())
#|}
#|pub fn[A] intercalate(self : List[List[A]], sep : List[A]) -> List[A] {
#| self.intersperse(sep).flatten()
#|}
#|pub impl[X] Default for List[X] with default() {
#| Empty
#|}
#|pub fn[X] default() -> List[X] {
#| Empty
#|}
#|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
#| }
#| })
#|}
#|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)
#| }
#| })
#|}
#|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
#|}
#|pub fn[A] from_iter_rev(iter : Iter[A]) -> List[A] {
#| iter.fold(init=Empty, (acc, e) => More(e, tail=acc))
#|}
#|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
#| }
#|}
#|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for List[X] with arbitrary(
#| size,
#| rs,
#|) {
#| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_array
#|}
#|pub fn[A] singleton(x : A) -> List[A] {
#| More(x, tail=Empty)
#|}
#|pub impl[A : Hash] Hash for List[A] with hash_combine(self, hasher) {
#| for e in self {
#| hasher.combine(e)
#| }
#|}
#|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)
#| }
#| }
#| }
#|}
#|pub fnalias List::zip
),
"types.mbt": (
#|pub enum List[A] {
#| Empty
#| More(A, mut tail~ : List[A])
#|} derive(Eq)
#|#deprecated("Use List instead of T")
#|pub typealias List as T
),
},
)
///|
let moonbitlang_core_math_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/double",
#| "moonbitlang/core/float",
#| "moonbitlang/core/int",
#| "moonbitlang/core/bigint",
#| "moonbitlang/core/random"
#| ],
#| "targets" : {
#| "algebraic_double_js.mbt": ["js"],
#| "algebraic_double_nonjs.mbt": ["not", "js"],
#| "exp_double_js.mbt": ["js"],
#| "exp_double_nonjs.mbt": ["not", "js"],
#| "log_double_js.mbt": ["js"],
#| "log_double_nonjs.mbt": ["not", "js"],
#| "pow_double_js.mbt": ["js"],
#| "pow_double_nonjs.mbt": ["not", "js"],
#| "trig_double_js.mbt": ["js"],
#| "trig_double_nonjs.mbt": ["not", "js"],
#| "trig_double_sincos_native.mbt": ["native"],
#| "trig_double_sincos_non_native_or_js.mbt": ["not", "js", "native"],
#| "hyperbolic_double_js.mbt": ["js"],
#| "hyperbolic_double_nonjs.mbt": ["not", "js"],
#| "utils.mbt": ["not", "js"]
#| }
#|}
),
"algebraic.mbt": (
#|#deprecated("Use @cmp.maximum instead")
#|pub fn[T : Compare] maximum(x : T, y : T) -> T {
#| if x > y {
#| x
#| } else {
#| y
#| }
#|}
#|#deprecated("Use @cmp.minimum instead")
#|pub fn[T : Compare] minimum(x : T, y : T) -> T {
#| if x > y {
#| y
#| } else {
#| x
#| }
#|}
#|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 {
#| return x + x
#| }
#| if hx < 0x00800000 {
#| 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
#| 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)
#| let r = t * t * t
#| let t = t * (dx + dx + r) / (dx + r + r)
#| t.to_float()
#|}
#|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()
#|}
),
"algebraic_double_js.mbt": (
#|pub fn cbrt(x : Double) -> Double = "Math" "cbrt"
#|pub fn hypot(x : Double, y : Double) -> Double = "Math" "hypot"
),
"algebraic_double_nonjs.mbt": (
#|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
#| }
#|}
#|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()
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `PI` instead")
#|pub let pi = 0x3.243F6A8885A308CA8A54
),
"exp.mbt": (
#|fn top12(x : Float) -> UInt {
#| x.reinterpret_as_uint() >> 20
#|}
#|fn __math_xflowf(sign : UInt, y : Float) -> Float {
#| return (if sign != 0 { -y } else { y }) * y
#|}
#|fn __math_oflowf(sign : UInt) -> Float {
#| return __math_xflowf(sign, 0x1.0p97)
#|}
#|fn __math_uflowf(sign : UInt) -> Float {
#| return __math_xflowf(sign, 0x1.0p-95)
#|}
#|let exp2f_table_bits = 5
#|priv struct Exp2fData {
#| tab : FixedArray[UInt64]
#| shift : Double
#| invln2_scaled : Double
#| poly_scaled : FixedArray[Double]
#|}
#|let expf_n : UInt64 = (1 << exp2f_table_bits).to_uint64()
#|let exp2f_data_n : Double = (1 << exp2f_table_bits).to_double()
#|let exp2f_data : Exp2fData = {
#| tab: [
#| 0x3ff0000000000000, 0x3fefd9b0d3158574, 0x3fefb5586cf9890f, 0x3fef9301d0125b51,
#| 0x3fef72b83c7d517b, 0x3fef54873168b9aa, 0x3fef387a6e756238, 0x3fef1e9df51fdee1,
#| 0x3fef06fe0a31b715, 0x3feef1a7373aa9cb, 0x3feedea64c123422, 0x3feece086061892d,
#| 0x3feebfdad5362a27, 0x3feeb42b569d4f82, 0x3feeab07dd485429, 0x3feea47eb03a5585,
#| 0x3feea09e667f3bcd, 0x3fee9f75e8ec5f74, 0x3feea11473eb0187, 0x3feea589994cce13,
#| 0x3feeace5422aa0db, 0x3feeb737b0cdc5e5, 0x3feec49182a3f090, 0x3feed503b23e255d,
#| 0x3feee89f995ad3ad, 0x3feeff76f2fb5e47, 0x3fef199bdd85529c, 0x3fef3720dcef9069,
#| 0x3fef5818dcfba487, 0x3fef7c97337b9b5f, 0x3fefa4afa2a490da, 0x3fefd0765b6e4540,
#| ],
#| shift: 0x1.8p+52,
#| invln2_scaled: 0x1.71547652b82fep+0 * exp2f_data_n,
#| poly_scaled: [
#| 0x1.c6af84b912394p-5 / exp2f_data_n / exp2f_data_n / exp2f_data_n,
#| 0x1.ebfce50fac4f3p-3 / exp2f_data_n / exp2f_data_n,
#| 0x1.62e42ff0c52d6p-1 / exp2f_data_n,
#| ],
#|}
#|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()
#|}
#|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
#| if hx >= 0x4195b844 {
#| if hx > 0x7f800000 {
#| 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
#| if hx > 0x3eb17218 {
#| if hx < 0x3F851592 {
#| 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 {
#| return x
#| } else {
#| k = 0
#| }
#| 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 {
#| return x - (x * e - hxs)
#| }
#| e = x * (e - c) - c
#| e -= hxs
#| 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)) {
#| 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
#| }
#|}
),
"exp_double_js.mbt": (
#|pub fn exp(x : Double) -> Double = "Math" "exp"
#|pub fn expm1(x : Double) -> Double = "Math" "expm1"
),
"exp_double_nonjs.mbt": (
#|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
#| }
#|}
#|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
#|}
),
"hyperbolic.mbt": (
#|fn k_expo2f(x : Float) -> Float {
#| let k = 235
#| let k_ln2 = (0x4322e3bc).reinterpret_as_float()
#| let scale = ((0x7f + k / 2) << 23).reinterpret_as_float()
#| expf(x - k_ln2) * scale * scale
#|}
#|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
#| }
#| ix = ix & 0x7fffffff
#| let absx = ix.reinterpret_as_float()
#| let w = ix
#| 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))
#| }
#| h * k_expo2f(absx) * 2.0
#|}
#|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
#| 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))
#| }
#| if w < 0x42b17217 {
#| let t = expf(x)
#| return (t + (1.0 : Float) / t) * 0.5
#| }
#| k_expo2f(x)
#|}
#|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 {
#| if w > 0x41200000 {
#| (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 {
#| let t = expm1f(x * 2.0)
#| t / (t + 2.0)
#| } else if w >= 0x00800000 {
#| let t = expm1f(x * -2.0)
#| -t / (t + 2.0)
#| } else {
#| x
#| }
#| if sign {
#| -tt
#| } else {
#| tt
#| }
#|}
#|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) {
#| lnf(x) + ln2
#| } else if i >= 0x3f800000U + (1U << 23) {
#| lnf(x * 2.0 + (1.0 : Float) / ((x * x + 1.0).sqrt() + x))
#| } else if i >= 0x3f800000U - (12U << 23) {
#| ln_1pf(x + x * x / ((x * x + 1.0).sqrt() + 1.0))
#| } else {
#| x
#| }
#| if sign {
#| -x
#| } else {
#| x
#| }
#|}
#|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) {
#| return ln_1pf(
#| x - 1.0 + ((x - 1.0) * (x - 1.0) + (2.0 : Float) * (x - 1.0)).sqrt(),
#| )
#| }
#| if a < 0x3f800000U + (12U << 23) {
#| return lnf(x * 2.0 - (1.0 : Float) / (x + (x * x - 1.0).sqrt()))
#| }
#| return lnf(x) + ln2
#|}
#|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 {
#| ln_1pf(x * 2.0 + x * 2.0 * x / ((1.0 : Float) - x)) * 0.5
#| }
#| } else {
#| ln_1pf(x / ((1.0 : Float) - x) * 2.0) * 0.5
#| }
#| if sign {
#| -x
#| } else {
#| x
#| }
#|}
),
"hyperbolic_double_js.mbt": (
#|pub fn sinh(x : Double) -> Double = "Math" "sinh"
#|pub fn cosh(x : Double) -> Double = "Math" "cosh"
#|pub fn tanh(x : Double) -> Double = "Math" "tanh"
#|pub fn asinh(x : Double) -> Double = "Math" "asinh"
#|pub fn acosh(x : Double) -> Double = "Math" "acosh"
#|pub fn atanh(x : Double) -> Double = "Math" "atanh"
),
"hyperbolic_double_nonjs.mbt": (
#|pub fn sinh(x : Double) -> 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
#|}
#|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
#|}
#|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
#| }
#|}
#|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
#| }
#|}
#|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
#| }
#|}
#|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
#| }
#|}
),
"log.mbt": (
#|let logf_off = 0x3f330000U
#|let logf_table_bits = 4
#|let logf_n : UInt = 1U << logf_table_bits
#|priv struct LogfData {
#| invc : FixedArray[Double]
#| logc : FixedArray[Double]
#| ln2 : Double
#| poly : FixedArray[Double]
#|}
#|let logf_data : LogfData = {
#| invc: [
#| 0x1.661ec79f8f3bep+0, 0x1.571ed4aaf883dp+0, 0x1.49539f0f010bp+0, 0x1.3c995b0b80385p+0,
#| 0x1.30d190c8864a5p+0, 0x1.25e227b0b8eap+0, 0x1.1bb4a4a1a343fp+0, 0x1.12358f08ae5bap+0,
#| 0x1.0953f419900a7p+0, 0x1.0p+0, 0x1.e608cfd9a47acp-1, 0x1.ca4b31f026aap-1, 0x1.b2036576afce6p-1,
#| 0x1.9c2d163a1aa2dp-1, 0x1.886e6037841edp-1, 0x1.767dcf5534862p-1,
#| ],
#| logc: [
#| -0x1.57bf7808caadep-2, -0x1.2bef0a7c06ddbp-2, -0x1.01eae7f513a67p-2, -0x1.b31d8a68224e9p-3,
#| -0x1.6574f0ac07758p-3, -0x1.1aa2bc79c81p-3, -0x1.a4e76ce8c0e5ep-4, -0x1.1973c5a611cccp-4,
#| -0x1.252f438e10c1ep-5, 0x0.0p+0, 0x1.aa5aa5df25984p-5, 0x1.c5e53aa362eb4p-4,
#| 0x1.526e57720db08p-3, 0x1.bc2860d22477p-3, 0x1.1058bc8a07ee1p-2, 0x1.4043057b6ee09p-2,
#| ],
#| ln2: 0x1.62e42fefa39efp-1,
#| poly: [-0x1.00ea348b88334p-2, 0x1.5575b0be00b6ap-2, -0x1.ffffef20a4123p-2],
#|}
#|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()
#|}
#|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
#|}
),
"log_double_js.mbt": (
#|pub fn ln(x : Double) -> Double = "Math" "log"
#|pub fn log2(x : Double) -> Double = "Math" "log2"
#|pub fn log10(x : Double) -> Double = "Math" "log10"
#|pub fn ln_1p(x : Double) -> Double = "Math" "log1p"
),
"log_double_nonjs.mbt": (
#|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)
#|}
#|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()
#|}
#|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
#|}
#|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)
#| }
#|}
),
"pow.mbt": (
#|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
#| if iy == 0 {
#| return 1.0
#| }
#| if hx == 0x3f800000 {
#| return 1.0
#| }
#| if ix > 0x7f800000 || iy > 0x7f800000 {
#| return x + y
#| }
#| 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)
#| }
#| }
#| }
#| if iy == 0x7f800000 {
#| if ix == 0x3f800000 {
#| return 1.0
#| } else if ix > 0x3f800000 {
#| return if hy >= 0 { y } else { 0.0 }
#| } else {
#| return if hy >= 0 { 0.0 } else { -y }
#| }
#| }
#| if iy == 0x3f800000 {
#| return if hy >= 0 { x } else { (1.0 : Float) / x }
#| }
#| if hy == 0x40000000 {
#| return x * x
#| }
#| if hy == 0x3f000000 && hx >= 0 {
#| return x.sqrt()
#| }
#| ax = x.abs()
#| if ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 {
#| z = ax
#| if hy < 0 {
#| 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 {
#| return @float.not_a_number
#| }
#| if yisint == 1 {
#| sn = -1.0
#| }
#| }
#| if iy > 0x4d000000 {
#| 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 }
#| }
#| 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
#| if ix < 0x00800000 {
#| ax *= two24
#| n -= 24
#| ix = ax.reinterpret_as_int()
#| }
#| n += (ix >> 23) - 0x7f
#| j = ix & 0x007fffff
#| ix = j | 0x3f800000 // normalize ix
#| if j <= 0x1cc471 {
#| k = 0
#| } else if j < 0x5db3d7 {
#| k = 1
#| } else {
#| k = 0
#| n += 1
#| ix -= 0x00800000
#| }
#| ax = ix.reinterpret_as_float()
#| u = ax - bp[k]
#| v = (1.0 : Float) / (ax + bp[k])
#| s = u * v
#| s_h = s
#| i_s = s_h.reinterpret_as_int()
#| s_h = (i_s & 0xfffff000).reinterpret_as_float()
#| i_s = (((ix.reinterpret_as_uint() >> 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)
#| 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 = s_h * t_h
#| v = s_l * t_h + t_l * 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]
#| 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)
#| }
#| 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 {
#| return sn * huge * huge // overflow
#| } else if j == 0x43000000 {
#| if p_l + ovt > z - p_h {
#| return sn * huge * huge
#| }
#| } else if ( // overflow
#| j & 0x7fffffff
#| ) >
#| 0x43160000 {
#| return sn * tiny * tiny // underflow
#| } else if j.reinterpret_as_uint() == 0xc3160000 && p_l <= z - p_h {
#| return sn * tiny * tiny
#| } // underflow
#| i = j & 0x7fffffff
#| k = (i >> 23) - 0x7f
#| n = 0
#| if i > 0x3f000000 {
#| 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 {
#| z = scalbnf(z, n)
#| } else {
#| z = j.reinterpret_as_float()
#| }
#| sn * z
#|}
),
"pow_double_js.mbt": (
#|pub fn pow(base : Double, exponent : Double) -> Double = "Math" "pow"
),
"pow_double_nonjs.mbt": (
#|let pow_bp : FixedArray[Double] = [1.0, 1.5]
#|let pow_dp_h : FixedArray[Double] = [0.0, 5.84962487220764160156e-01]
#|let pow_dp_l : FixedArray[Double] = [0.0, 1.35003920212974897128e-08]
#|const ZERO = 0.0
#|const ONE = 1.0
#|const TWO = 2.0
#|const POW_two53 = 9007199254740992.0
#|const POW_huge = 1.0e300
#|const POW_tiny = 1.0e-300
#|const POW_L1 = 5.99999999999994648725e-01
#|const POW_L2 = 4.28571428578550184252e-01
#|const POW_L3 = 3.33333329818377432918e-01
#|const POW_L4 = 2.72728123808534006489e-01
#|const POW_L5 = 2.30660745775561754067e-01
#|const POW_L6 = 2.06975017800338417784e-01
#|const POW_P1 = 1.66666666666666019037e-01
#|const POW_P2 = -2.77777777770155933842e-03
#|const POW_P3 = 6.61375632143793436117e-05
#|const POW_P4 = -1.65339022054652515390e-06
#|const POW_P5 = 4.13813679705723846039e-08
#|const POW_lg2 = 6.93147180559945286227e-01
#|const POW_lg2_h = 6.93147182464599609375e-01
#|const POW_lg2_l = -1.90465429995776804525e-09
#|const POW_ovt = 8.0085662595372944372e-0017
#|const POW_cp = 9.61796693925975554329e-01
#|const POW_cp_h = 9.61796700954437255859e-01
#|const POW_cp_l = -7.02846165095275826516e-09
#|const POW_ivln2 = 1.44269504088896338700e+00
#|const POW_ivln2_h = 1.44269502162933349609e+00
#|const POW_ivln2_l = 1.92596299112661746887e-08
#|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()
#| }
#| 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
#| 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
#| 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 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
#| if (iy.reinterpret_as_uint() | ly) == 0 {
#| return ONE
#| }
#| if ix > 0x7FF00000 ||
#| (ix == 0x7FF00000 && lx != 0) ||
#| iy > 0x7FF00000 ||
#| (iy == 0x7FF00000 && ly != 0) {
#| return x + y
#| }
#| 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)
#| }
#| }
#| }
#| }
#| 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()
#| 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 {
#| z = @double.not_a_number
#| } else if yisint == 1 {
#| z = -z // (x<0)**odd = -(|x|**odd)
#| }
#| }
#| return z
#| }
#| }
#| n = (hx >> 31) + 1
#| 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)
#| }
#| 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 }
#| }
#| }
#| 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
#| }
#| }
#| 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
#| if ix < 0x00100000 {
#| ax *= POW_two53
#| n -= 53
#| ix = get_high_word(ax).reinterpret_as_int()
#| }
#| n += (ix >> 20) - 0x3ff
#| j = ix & 0x000fffff
#| 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)
#| 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 = s_h * t_h
#| v = s_l * t_h + t_l * 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]
#| 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)
#| }
#| 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
#| }
#| }
#| 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
#|}
),
"prime.mbt": (
#|const DEFAULT_PRIME_TEST_ITERS = 64
#|let small_primes : Array[@bigint.BigInt] = [
#| 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
#| 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163,
#| 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251,
#| 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
#| 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
#| 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557,
#| 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647,
#| 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757,
#| 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
#| 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983,
#| 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069,
#| 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181,
#| 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283,
#| 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399,
#| 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487,
#| 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583,
#| 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693,
#| 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789,
#| 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907,
#| 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017,
#| 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129,
#| 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243,
#| 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347,
#| 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441,
#| 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579,
#| 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687,
#| 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777,
#| 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887,
#| 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011,
#| 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137,
#| 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257,
#| 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361,
#| 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491,
#| 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583,
#| 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697,
#| 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821,
#| 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923,
#| 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049,
#| 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157,
#| 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271,
#| 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409,
#| 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519,
#| 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649,
#| 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783,
#| 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909,
#| 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003,
#| 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113,
#| 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261,
#| 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399,
#| 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501,
#| 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639,
#| 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737,
#| 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849,
#| 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981,
#| 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101,
#| 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221,
#| 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329,
#| 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451,
#| 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581,
#| 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709,
#| 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833,
#| 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961,
#| 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069,
#| 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213,
#| 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349,
#| 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499,
#| 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589,
#| 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703,
#| 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853,
#| 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963,
#| 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111,
#| 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237,
#| 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369,
#| 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, 8513, 8521,
#| 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641,
#| 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741,
#| 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861,
#| 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001,
#| 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133,
#| 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241,
#| 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377,
#| 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473,
#| 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623,
#| 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 9739, 9743,
#| 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857,
#| 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007,
#| 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111,
#| 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223,
#| 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321,
#| 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453,
#| 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567,
#| 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667,
#| 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 10781, 10789,
#| 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889, 10891, 10903,
#| 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047,
#| 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149,
#| 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261,
#| 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383,
#| 11393, 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491,
#| 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621,
#| 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777,
#| 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863,
#| 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 11953, 11959,
#| 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071, 12073,
#| 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197,
#| 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289,
#| 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413,
#| 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511,
#| 12517, 12527, 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611,
#| 12613, 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713,
#| 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829,
#| 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953,
#| 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, 13037, 13043,
#| 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163,
#| 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291,
#| 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411,
#| 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, 13513, 13523,
#| 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, 13627, 13633, 13649, 13669,
#| 13679, 13681, 13687, 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751,
#| 13757, 13759, 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873,
#| 13877, 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967,
#| 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087,
#| 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, 14249,
#| 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389,
#| 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489,
#| 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593,
#| 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, 14713, 14717,
#| 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, 14771, 14779, 14783, 14797,
#| 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897,
#| 14923, 14929, 14939, 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053,
#| 15061, 15073, 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149,
#| 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269,
#| 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359,
#| 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461,
#| 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583,
#| 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679,
#| 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 15787, 15791,
#| 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, 15887, 15889, 15901, 15907,
#| 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007, 16033, 16057,
#| 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139,
#| 16141, 16183, 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267,
#| 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417,
#| 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529,
#| 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651,
#| 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763,
#| 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903,
#| 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, 17011, 17021,
#| 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, 17099, 17107, 17117, 17123,
#| 17137, 17159, 17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231, 17239, 17257,
#| 17291, 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383,
#| 17387, 17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477,
#| 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581,
#| 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713,
#| 17729, 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839,
#| 17851, 17863,
#|]
#|pub fn is_probable_prime(
#| number : @bigint.BigInt,
#| rand : @random.Rand,
#| iters? : Int = DEFAULT_PRIME_TEST_ITERS,
#|) -> Bool {
#| if iters <= 0 {
#| abort("non-positive iters for probably prime")
#| }
#| if number <= 1N {
#| return false
#| }
#| if number <= 3N {
#| return true
#| }
#| if number % 2N == 0 {
#| return false
#| }
#| trial_divisions(number) && miller_rabin_test(number, iters, rand)
#|}
#|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
#| }
#| }
#|}
#|fn trial_divisions(n : @bigint.BigInt) -> Bool {
#| let td = match n.bit_length() {
#| _..=512 => 64
#| 512..=1024 => 128
#| 1024..=2048 => 384
#| 2048..=4096 => 1024
#| _ => 2048
#| }
#| for i in 1.. Bool {
#| if w <= 3N {
#| abort("candidate of miller rabin test must larger than 3")
#| }
#| let w1 = w - 1N
#| let w3 = w - 3N
#| let a = w1.ctz()
#| let m = w1 >> a
#| let w3_len = w3.bit_length()
#| next~: for i in 0.. 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 {
#| 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()
#|}
#|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()
#|}
#|test "scalbn" {
#| inspect(scalbn(1.5, 2), content="6")
#| inspect(scalbn(2.0, -1), content="1")
#| inspect(scalbn(3.0, 0), content="3")
#| inspect(scalbn(1.0, 1024), content="Infinity")
#| inspect(scalbn(1.0, -1023), content="1.1125369292536007e-308")
#| inspect(scalbn(1.0, 2047), content="Infinity")
#| inspect(scalbn(1.0, -1992), content="0")
#| inspect(scalbn(1.0, 3070), content="Infinity")
#| inspect(scalbn(1.0, -2961), content="0")
#| inspect(scalbn(@double.infinity, 10), content="Infinity")
#| inspect(scalbn(@double.not_a_number, 10), content="NaN")
#| inspect(scalbn(0.0, 10), content="0")
#|}
),
"trig.mbt": (
#|pub const PI = 0x3.243F6A8885A308CA8A54
#|const SIN_SWITCHOVER : Float = 201.15625
#|const COS_SWITCHOVER : Float = 142.90625
#|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()
#|}
#|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())
#|}
#|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 += 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)
#|}
#|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
#|}
#|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
#|}
#|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
#|}
#|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()
#|}
#|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)
#|}
#|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)
#|}
#|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)
#|}
#|pub fn asinf(x : Float) -> Float {
#| let x1p120 = 0x3870000000000000UL.reinterpret_as_double()
#| let pio2 : Double = 1.570796326794896558e+00
#| 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
#| }
#|}
#|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)
#|}
#|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
#| }
#|}
#|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
#| }
#|}
),
"trig_double_js.mbt": (
#|pub fn sin(x : Double) -> Double = "Math" "sin"
#|pub fn cos(x : Double) -> Double = "Math" "cos"
#|pub fn tan(x : Double) -> Double = "Math" "tan"
#|pub fn asin(x : Double) -> Double = "Math" "asin"
#|pub fn acos(x : Double) -> Double = "Math" "acos"
#|pub fn atan(x : Double) -> Double = "Math" "atan"
#|pub fn atan2(y : Double, x : Double) -> Double = "Math" "atan2"
),
"trig_double_nonjs.mbt": (
#|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))
#| }
#|}
#|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 }
#| }
#|}
#|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)
#| }
#|}
#|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
#| }
#| }
#|}
#|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
#| }
#|}
#|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 {
#| y[0] = x
#| y[1] = 0.0
#| return 0
#| }
#| if ix < 0x4002d97c {
#| if hx > 0 {
#| z = x - PIO2_1
#| if ix != 0x3ff921fb {
#| y[0] = z - PIO2_1T
#| y[1] = z - y[0] - PIO2_1T
#| } else {
#| z = z - PIO2_2
#| y[0] = z - PIO2_2T
#| y[1] = z - y[0] - PIO2_2T
#| }
#| return 1
#| } else {
#| z = x + PIO2_1
#| if ix != 0x3ff921fb {
#| y[0] = z + PIO2_1T
#| y[1] = z - y[0] + PIO2_1T
#| } else {
#| let z = z + PIO2_2
#| y[0] = z + PIO2_2T
#| y[1] = z - y[0] + PIO2_2T
#| }
#| return -1
#| }
#| }
#| if ix <= 0x413921fb {
#| 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 {
#| 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 {
#| 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
#| }
#| }
#| if ix >= 0x7ff00000 {
#| y[0] = x - x
#| y[1] = y[0]
#| return 0
#| }
#| 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
#| }
#|}
#|fn __kernel_rem_pio2(
#| x : Array[Double],
#| y : Array[Double],
#| e0 : Int,
#| nx : Int,
#| prec : Int,
#|) -> Int {
#| let init_jk = [2, 3, 4, 6]
#| let two24 : Double = 16777216.0 // 0x41700000, 0x00000000
#| let twon24 : Double = 5.96046447753906250000e-08 // 0x3E700000, 0x00000000
#| let mut jz : Int = 0
#| let mut jx : Int = 0
#| let mut jv : Int = 0
#| let mut jp : Int = 0
#| let mut jk : Int = 0
#| let mut carry : Int = 0
#| let mut n : Int = 0
#| let iq : Array[Int] = Array::make(20, 0)
#| let mut i : Int = 0
#| let mut j : Int = 0
#| let mut k : Int = 0
#| let mut m : Int = 0
#| let mut q0 : Int = 0
#| let mut ih : Int = 0
#| let mut z : Double = 0
#| let mut fw : Double = 0
#| let f : Array[Double] = Array::make(20, 0.0)
#| let fq : Array[Double] = Array::make(20, 0.0)
#| let q : Array[Double] = Array::make(20, 0.0)
#| jk = init_jk[prec]
#| jp = jk
#| jx = nx - 1
#| jv = (e0 - 3) / 24
#| if jv < 0 {
#| jv = 0
#| }
#| q0 = e0 - 24 * (jv + 1)
#| j = jv - jx
#| m = jx + jk
#| i = 0
#| while i <= m {
#| f[i] = if j < 0 { 0.0 } else { two_over_pi[j].to_double() }
#| i += 1
#| j += 1
#| }
#| i = 0
#| while i <= jk {
#| j = 0
#| fw = 0.0
#| while j <= jx {
#| fw += x[j] * f[jx + i - j]
#| j += 1
#| }
#| q[i] = fw
#| i += 1
#| }
#| jz = jk
#| let mut recompute = true
#| while recompute {
#| recompute = false
#| i = 0
#| j = jz
#| z = q[jz]
#| while j > 0 {
#| fw = (twon24 * z).floor()
#| iq[i] = (z - two24 * fw).to_int()
#| z = q[j - 1] + fw
#| i += 1
#| j -= 1
#| }
#| z = scalbn(z, q0) // actual value of z
#| z -= 8.0 * (z * 0.125).floor() // trim off integer >= 8
#| n = z.to_int()
#| z -= n.to_double()
#| ih = 0
#| if q0 > 0 {
#| i = iq[jz - 1] >> (24 - q0)
#| n += i
#| iq[jz - 1] -= i << (24 - q0)
#| ih = iq[jz - 1] >> (23 - q0)
#| } else if q0 == 0 {
#| ih = iq[jz - 1] >> 23
#| } else if z >= 0.5 {
#| ih = 2
#| }
#| if ih > 0 {
#| n += 1
#| carry = 0
#| i = 0
#| while i < jz {
#| j = iq[i]
#| if carry == 0 {
#| if j != 0 {
#| carry = 1
#| iq[i] = 0x1000000 - j
#| }
#| } else {
#| iq[i] = 0xffffff - j
#| }
#| i += 1
#| }
#| if q0 > 0 {
#| match q0 {
#| 1 => iq[jz - 1] = iq[jz - 1] & 0x7fffff
#| 2 => iq[jz - 1] = iq[jz - 1] & 0x3fffff
#| _ => ()
#| }
#| }
#| if ih == 2 {
#| z = 1.0 - z
#| if carry != 0 {
#| z -= scalbn(1.0, q0)
#| }
#| }
#| }
#| if z == 0.0 {
#| j = 0
#| i = jz - 1
#| while i >= jk {
#| j = j | iq[i]
#| i -= 1
#| }
#| if j == 0 {
#| k = 1
#| while iq[jk - k] == 0 {
#| k += 1
#| }
#| i = jz + 1
#| while i <= jz + k {
#| f[jx + i] = two_over_pi[jv + i].to_double()
#| j = 0
#| fw = 0.0
#| while j <= jx {
#| fw += x[j] * f[jx + i - j]
#| j += 1
#| }
#| q[i] = fw
#| i += 1
#| }
#| jz += k
#| recompute = true // Continue to recompute
#| continue
#| }
#| } // Skip the rest of the loop and recompute
#| if z == 0.0 {
#| jz -= 1
#| q0 -= 24
#| while iq[jz] == 0 {
#| jz -= 1
#| q0 -= 24
#| }
#| } else {
#| z = scalbn(z, -q0)
#| if z >= two24 {
#| fw = (twon24 * z).floor()
#| iq[jz] = (z - two24 * fw).to_int()
#| jz += 1
#| q0 += 24
#| iq[jz] = fw.to_int()
#| } else {
#| iq[jz] = z.to_int()
#| }
#| }
#| fw = scalbn(1.0, q0)
#| i = jz
#| while i >= 0 {
#| q[i] = fw * iq[i].to_double()
#| fw *= twon24
#| i -= 1
#| }
#| i = jz
#| while i >= 0 {
#| fw = 0.0
#| k = 0
#| while k <= jp && k <= jz - i {
#| fw += pi_over_2[k] * q[i + k]
#| k += 1
#| }
#| fq[jz - i] = fw
#| i -= 1
#| }
#| match prec {
#| 0 => {
#| fw = 0.0
#| i = jz
#| while i >= 0 {
#| fw += fq[i]
#| i -= 1
#| }
#| y[0] = if ih == 0 { fw } else { -fw }
#| }
#| 1 | 2 => {
#| fw = 0.0
#| i = jz
#| while i >= 0 {
#| fw += fq[i]
#| i -= 1
#| }
#| y[0] = if ih == 0 { fw } else { -fw }
#| fw = fq[0] - fw
#| i = 1
#| while i <= jz {
#| fw += fq[i]
#| i += 1
#| }
#| y[1] = if ih == 0 { fw } else { -fw }
#| }
#| 3 => {
#| i = jz
#| while i > 0 {
#| fw = fq[i - 1] + fq[i]
#| fq[i] += fq[i - 1] - fw
#| fq[i - 1] = fw
#| i -= 1
#| }
#| i = jz
#| while i > 1 {
#| fw = fq[i - 1] + fq[i]
#| fq[i] += fq[i - 1] - fw
#| fq[i - 1] = fw
#| i -= 1
#| }
#| fw = 0.0
#| i = jz
#| while i >= 2 {
#| fw += fq[i]
#| i -= 1
#| }
#| if ih == 0 {
#| y[0] = fq[0]
#| y[1] = fq[1]
#| y[2] = fw
#| } else {
#| y[0] = -fq[0]
#| y[1] = -fq[1]
#| y[2] = -fw
#| }
#| }
#| _ => ()
#| }
#| }
#| n & 7
#|}
#|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)
#| }
#|}
#|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))
#| }
#|}
#|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)
#| }
#|}
),
"trig_double_sincos_native.mbt": (
#|pub extern "C" fn sin(x : Double) -> Double = "sin"
#|pub extern "C" fn cos(x : Double) -> Double = "cos"
),
"trig_double_sincos_non_native_or_js.mbt": (
#|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])
#| }
#| }
#|}
#|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)
#| }
#| }
#|}
),
"utils.mbt": (
#|fn abs(x : Double) -> Double {
#| if x < 0.0 {
#| -x
#| } else {
#| x
#| }
#|}
#|let two_over_pi : FixedArray[Int] = [
#| 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C, 0x439041,
#| 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C,
#| 0xFE1DEB, 0x1CB129, 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
#| 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F,
#| 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D,
#| 0x7527BA, 0xC7EBE5, 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
#| 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 0x91615E, 0xE61B08,
#| 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9,
#| 0x60E27B, 0xC08C6B,
#|]
#|let pi_over_2 : FixedArray[Double] = [
#| 1.57079625129699707031e+00, // 0x3FF921FB, 0x40000000 */
#| 7.54978941586159635335e-08, // 0x3E74442D, 0x00000000 */
#| 5.39030252995776476554e-15, // 0x3CF84698, 0x80000000 */
#| 3.28200341580791294123e-22, // 0x3B78CC51, 0x60000000 */
#| 1.27065575308067607349e-29, // 0x39F01B83, 0x80000000 */
#| 1.22933308981111328932e-36, // 0x387A2520, 0x40000000 */
#| 2.73370053816464559624e-44, // 0x36E38222, 0x80000000 */
#| 2.16741683877804819444e-51, // 0x3569F31D, 0x00000000 */
#|]
#|let npio2_hw : FixedArray[Int] = [
#| 0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C, 0x4025FDBB,
#| 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C, 0x40346B9C, 0x4035FDBB,
#| 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A, 0x403DD85A, 0x403F6A7A, 0x40407E4C,
#| 0x4041475C, 0x4042106C, 0x4042D97C, 0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB,
#| 0x4046C6CB, 0x40478FDB, 0x404858EB, 0x404921FB,
#|]
#|const PI_OVER_4 : Double = 0.785398163397448309616
#|const PIO2_1 : Double = 1.5707963267341256e+00 // 0x3FF921FB, 0x54400000 */
#|const PIO2_1T : Double = 6.0771005065061922e-11 // 0x3DD0B461, 0x1A600000 */
#|const PIO2_2 : Double = 6.0771005063039660e-11 // 0x3DD0B461, 0x1A600000 */
#|const PIO2_2T : Double = 2.0222662487959506e-21 // 0x3BA3198A, 0x2E037073 */
#|const PIO2_3 : Double = 2.0222662487111665e-21 // 0x3BA3198A, 0x2E037073 */
#|const PIO2_3T : Double = 8.4784276603688996e-32 // 0x397B839A, 0x252049C1 */
#|const INV_PIO2 : Double = 6.3661977236758138e-01 // 0x3FE45F30, 0x6DC9C883 */
#|const HALF : Double = 0.5
#|const TWO24 : Double = 16777216.0 // 0x41700000, 0x00000000 */
#|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()
#|}
#|const SQRT2 = 1.41421356237309504880168872420969807856967187537694807317667974
#|const LN2 = 0.693147180559945309417232121458176568075500134360255254120680009
#|const LN2_HI = 6.93147180369123816490e-01 // 3fe62e42 fee00000
#|const LN2_LO = 1.90821492927058770002e-10 // 3dea39ef 35793c76
#|fn normalize(f : Double) -> (Double, Int) {
#| if f.abs() < @double.min_positive {
#| return (f * (1L << 52).to_double(), -52)
#| }
#| (f, 0)
#|}
#|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)
#|}
),
},
)
///|
let moonbitlang_core_option_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/quickcheck",
#| "moonbitlang/core/quickcheck/splitmix"
#| ],
#| "targets": {
#| "panic_test.mbt": ["not", "native", "llvm"]
#| }
#|}
),
"deprecated.mbt": (
#|#deprecated("inline instead for such tiny function")
#|pub fn[T] when(condition : Bool, value : () -> T) -> T? {
#| if condition {
#| Some(value())
#| } else {
#| None
#| }
#|}
#|#deprecated("inline instead for such tiny function")
#|pub fn[T] unless(condition : Bool, value : () -> T) -> T? {
#| when(!condition, value)
#|}
#|#deprecated("inline instead for such tiny function")
#|pub fn[T] empty() -> T? {
#| None
#|}
#|#deprecated("inline instead for such tiny function")
#|pub fn[T] some(value : T) -> T? {
#| Some(value)
#|}
#|#deprecated("use unwrap_or instead")
#|pub fn[T] Option::or(self : T?, default : T) -> T {
#| match self {
#| None => default
#| Some(t) => t
#| }
#|}
#|#deprecated("use unwrap_or_else instead")
#|pub fn[T] Option::or_else(self : T?, default : () -> T) -> T {
#| match self {
#| None => default()
#| Some(t) => t
#| }
#|}
#|#deprecated("use unwrap_or_default instead")
#|pub fn[T : Default] Option::or_default(self : T?) -> T {
#| match self {
#| None => T::default()
#| Some(t) => t
#| }
#|}
#|#deprecated("use `x is Some(_)` instead")
#|pub fn[T] is_some(self : T?) -> Bool {
#| self is Some(_)
#|}
#|#deprecated("use `x is None` instead")
#|pub fn[T] is_none(self : T?) -> Bool {
#| self is None
#|}
),
"option.mbt": (
#|test "some equals to Some" {
#| let x : Int? = Some(5)
#| let y : Int? = some(5)
#| assert_eq(x, y)
#|}
#|pub fn[T, U] map(self : T?, f : (T) -> U raise?) -> U? raise? {
#| match self {
#| Some(t) => Some(f(t))
#| None => None
#| }
#|}
#|test "map" {
#| let a = Some(5)
#| let b : Int? = None
#| assert_eq(a.map(x => x * 2), Some(10))
#| assert_eq(b.map(x => x * 2), None)
#|}
#|pub fn[T, U] map_or(self : T?, default : U, f : (T) -> U raise?) -> U raise? {
#| match self {
#| None => default
#| Some(x) => f(x)
#| }
#|}
#|test "map_or" {
#| let a = Option::Some("foo")
#| let b : String? = Option::None
#| assert_eq(a.map_or(42, x => x.length()), 3)
#| assert_eq(b.map_or(42, x => x.length()), 42)
#|}
#|pub fn[T, U] map_or_else(
#| self : T?,
#| default : () -> U raise?,
#| f : (T) -> U raise?,
#|) -> U raise? {
#| match self {
#| None => default()
#| Some(x) => f(x)
#| }
#|}
#|test "map_or_else" {
#| let k = 21
#| let a = Option::Some("foo")
#| let b : String? = Option::None
#| assert_eq(a.map_or_else(() => 2 * k, x => x.length()), 3)
#| assert_eq(b.map_or_else(() => 2 * k, x => x.length()), 42)
#|}
#|pub fn[T, U] bind(self : T?, f : (T) -> U? raise?) -> U? raise? {
#| match self {
#| Some(t) => f(t)
#| None => None
#| }
#|}
#|test "bind" {
#| let a = Option::Some(5)
#| let b : Int? = None
#| assert_eq(a.bind(x => Some(x * 2)), Some(10))
#| assert_eq(b.bind(x => Some(x * 2)), None)
#|}
#|pub fn[T] flatten(self : T??) -> T? {
#| match self {
#| Some(inner) => inner
#| None => None
#| }
#|}
#|test "flatten" {
#| let a : Int?? = Some(Some(42))
#| assert_eq(a.flatten(), Some(42))
#| let b : Int?? = Some(None)
#| assert_eq(b.flatten(), None)
#|}
#|pub fn[T] is_empty(self : T?) -> Bool {
#| self is None
#|}
#|test "is_empty" {
#| let x = Option::Some(3)
#| let y : Int? = None
#| assert_false(x.is_empty())
#| assert_true(y.is_empty())
#|}
#|pub fn[T] filter(self : T?, f : (T) -> Bool raise?) -> T? raise? {
#| match self {
#| Some(t) => if f(t) { self } else { None }
#| None => None
#| }
#|}
#|test "filter" {
#| let x = Option::Some(3)
#| assert_eq(x.filter(x => x > 5), None)
#| assert_eq(x.filter(x => x < 5), Some(3))
#|}
#|pub fn[T] Option::unwrap_or(self : T?, default : T) -> T {
#| match self {
#| None => default
#| Some(t) => t
#| }
#|}
#|test "unwrap_or" {
#| let x = Option::Some(3)
#| assert_eq(x.unwrap_or(5), 3)
#| assert_eq((None : Int?).unwrap_or(5), 5)
#|}
#|pub fn[T] Option::unwrap_or_else(
#| self : T?,
#| default : () -> T raise?,
#|) -> T raise? {
#| match self {
#| None => default()
#| Some(t) => t
#| }
#|}
#|test "or else" {
#| let x = Option::Some(3)
#| assert_eq(x.unwrap_or_else(() => 5), 3)
#| assert_eq(None.unwrap_or_else(() => 5), 5)
#|}
#|pub fn[T : Default] Option::unwrap_or_default(self : T?) -> T {
#| match self {
#| None => T::default()
#| Some(t) => t
#| }
#|}
#|test "or default" {
#| let x = Option::Some(3)
#| assert_eq(x.unwrap_or_default(), 3)
#| assert_eq((None : Int?).unwrap_or_default(), 0)
#|}
#|pub impl[X : Compare] Compare for X? with compare(self, other) {
#| match (self, other) {
#| (Some(x), Some(y)) => x.compare(y)
#| (Some(_), None) => 1
#| (None, Some(_)) => -1
#| (None, None) => 0
#| }
#|}
#|test "compare" {
#| let some1 = Option::Some(1)
#| let some2 = Option::Some(2)
#| let none = Option::None
#| assert_eq(0, some1.compare(Option::Some(1)))
#| assert_eq(-1, some1.compare(some2))
#| assert_eq(1, some2.compare(some1))
#| assert_eq(0, none.compare(none))
#| assert_eq(-1, none.compare(some1))
#| assert_eq(1, some2.compare(none))
#|}
#|pub impl[X] Default for X? with default() {
#| None
#|}
#|pub fn[T] iter(self : T?) -> Iter[T] {
#| match self {
#| Some(v) => Iter::singleton(v)
#| None => Iter::empty()
#| }
#|}
#|test "iter" {
#| let x = Option::Some(42)
#| let exb = StringBuilder::new(size_hint=0)
#| x
#| .iter()
#| .each(x => {
#| exb.write_string(x.to_string())
#| exb.write_char('\n')
#| })
#| inspect(
#| exb,
#| content=(
#| #|42
#| #|
#| ),
#| )
#| exb.reset()
#| let y : Int? = None
#| y
#| .iter()
#| .each(x => {
#| exb.write_string(x.to_string())
#| exb.write_char('\n')
#| })
#| inspect(exb, content="")
#|}
#|pub fn[T, Err : Error] or_error(self : T?, err : Err) -> T raise Err {
#| match self {
#| Some(v) => v
#| None => raise err
#| }
#|}
#|test "or error" {
#| assert_eq(
#| (None : String?).or_error(Failure("This is serious")) catch {
#| Failure(err) => err
#| },
#| "This is serious",
#| )
#| assert_eq(
#| Some("This is ok").or_error(Failure("This is serious")) catch {
#| Failure(err) => err
#| },
#| "This is ok",
#| )
#|}
#|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for X? with arbitrary(
#| i,
#| rs,
#|) {
#| if rs.next_double() < 0.3 {
#| None
#| } else {
#| Some(@quickcheck.Arbitrary::arbitrary(i, rs))
#| }
#|}
#|test "arbitrary" {
#| let samples : Array[Int?] = @quickcheck.samples(10)
#| inspect(
#| samples,
#| content="[None, None, Some(-1), Some(0), None, Some(0), Some(-5), Some(2), None, Some(4)]",
#| )
#|}
),
},
)
///|
let moonbitlang_core_prelude_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/bigint",
#| "moonbitlang/core/set",
#| "moonbitlang/core/array"
#| ],
#| "alert-list": "-test_import_all"
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `@array.View` instead")
#|pub typealias @array.View as ArrayView
),
"prelude.mbt": (
#|pub typealias @builtin.(
#| ArgsLoc,
#| Array,
#| UninitializedArray,
#| Failure,
#| Hasher,
#| Iter,
#| Iter2,
#| IterResult,
#| Json,
#| Map,
#| InspectError,
#| SnapshotError,
#| SourceLoc,
#| StringBuilder
#|)
#|pub typealias @set.Set
#|pub typealias @bigint.BigInt
#|pub traitalias @builtin.(
#| Eq,
#| Compare,
#| Hash,
#| Logger,
#| Show,
#| ToJson,
#| Default,
#| Add,
#| Sub,
#| Mul,
#| Div,
#| Mod,
#| Neg,
#| Shl,
#| Shr,
#| BitAnd,
#| BitOr,
#| BitXOr
#|)
#|pub fnalias @builtin.(
#| abort,
#| assert_eq,
#| assert_not_eq,
#| assert_true,
#| assert_false,
#| fail,
#| ignore,
#| inspect,
#| panic,
#| physical_equal,
#| println,
#| not,
#| repr,
#| dump
#|)
#|pub fn[T] tap(value : T, f : (T) -> Unit) -> T {
#| f(value)
#| value
#|}
#|pub fn[T, R] then(value : T, f : (T) -> R) -> R {
#| f(value)
#|}
#|pub let null : Json = @builtin.null
),
},
)
///|
let moonbitlang_core_priority_queue_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/array",
#| "moonbitlang/core/quickcheck",
#| "moonbitlang/core/quickcheck/splitmix",
#| "moonbitlang/core/json"
#| ],
#| "test-import": ["moonbitlang/core/random"],
#| "targets": {
#| "panic_test.mbt": ["not", "native", "llvm"]
#| }
#|}
),
"priority_queue.mbt": (
#|pub fn[A] new() -> T[A] {
#| { len: 0, top: Nil }
#|}
#|pub fn[A : Compare] from_array(arr : Array[A]) -> T[A] {
#| 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 }
#| }
#| }
#|}
#|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),
#| )
#| }
#|}
#|pub fn[A] copy(self : T[A]) -> T[A] {
#| let new_que : T[A] = { len: self.len, top: copy_node(self.top) }
#| new_que
#|}
#|pub fn[A : Compare] to_array(self : T[A]) -> Array[A] {
#| let arr = Array::new(capacity=self.len)
#| let stack : Array[Node[A]] = [self.top]
#| while stack.pop() is Some(node) {
#| match node {
#| Nil => ()
#| Cons(content~, sibling~, child~) => {
#| arr.push(content)
#| stack.push(sibling)
#| stack.push(child)
#| }
#| }
#| }
#| arr.sort()
#| arr.rev_inplace()
#| arr
#|}
#|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
#|}
#|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
#| }
#| }
#|}
#|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)))
#| }
#| }
#|}
#|pub fn[A] length(self : T[A]) -> Int {
#| self.len
#|}
#|#internal(unsafe, "Panic if the queue is empty.")
#|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
#|}
#|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
#|}
#|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
#|}
#|pub fn[A] peek(self : T[A]) -> A? {
#| match self.top {
#| Nil => None
#| Cons(content~, ..) => Some(content)
#| }
#|}
#|pub fn[A] clear(self : T[A]) -> Unit {
#| self.top = Nil
#| self.len = 0
#|}
#|pub fn[A] is_empty(self : T[A]) -> Bool {
#| self.len == 0
#|}
#|pub fn[A : Compare] of(arr : FixedArray[A]) -> T[A] {
#| 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 }
#| }
#| }
#|}
#|test "meld_and_merges" {
#| inspect(
#| match meld(Cons(content=1, sibling=Nil, child=Nil), Nil) {
#| Nil => false
#| Cons(..) => true
#| },
#| content="true",
#| )
#|}
#|pub impl[A : Show + Compare] Show for T[A] with output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@priority_queue.of([", suffix="])")
#|}
#|pub impl[X : @quickcheck.Arbitrary + Compare] @quickcheck.Arbitrary for T[X] with arbitrary(
#| size,
#| rs,
#|) {
#| let len : Int = if size == 0 { 0 } else { rs.next_positive_int() % size }
#| for i = 0, acc = Node::Nil {
#| if i < len {
#| continue i + 1,
#| meld(acc, Cons(content=X::arbitrary(i, rs), sibling=Nil, child=Nil))
#| } else {
#| break { len, top: acc }
#| }
#| }
#|}
#|test "priority queue arbitrary" {
#| let samples : Array[T[Int]] = @quickcheck.samples(20)
#| inspect(
#| samples[5:10],
#| content="[@priority_queue.of([]), @priority_queue.of([]), @priority_queue.of([0]), @priority_queue.of([0, 0]), @priority_queue.of([3, 2, 1, 0, 0, 0, 0])]",
#| )
#| inspect(
#| samples[11:15],
#| content="[@priority_queue.of([0, 0, 0, -1, -2]), @priority_queue.of([8, 4, 0, 0, 0, 0, 0, 0, -2, -5]), @priority_queue.of([2, 0, 0, -1]), @priority_queue.of([0, 0])]",
#| )
#|}
#|pub impl[K] Default for T[K] with default() {
#| new()
#|}
),
"types.mbt": (
#|priv enum Node[A] {
#| Nil
#| Cons(content~ : A, mut sibling~ : Node[A], mut child~ : Node[A])
#|}
#|struct T[A] {
#| mut len : Int
#| mut top : Node[A]
#|}
),
},
)
///|
let moonbitlang_core_queue_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/queue",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
},
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin", "moonbitlang/core/quickcheck"],
#| "test-import": ["moonbitlang/core/array"],
#| "targets": {
#| "panic_test.mbt": ["not", "native", "llvm"]
#| }
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `unsafe_peek` instead")
#|#coverage.skip
#|pub fn[A] peek_exn(self : Queue[A]) -> A {
#| self.unsafe_peek()
#|}
#|#deprecated("Use `unsafe_pop` instead")
#|#coverage.skip
#|pub fn[A] pop_exn(self : Queue[A]) -> A {
#| self.unsafe_pop()
#|}
),
"queue.mbt": (
#|pub fn[A] new() -> Queue[A] {
#| { length: 0, first: None, last: None }
#|}
#|pub fn[A] from_array(arr : Array[A]) -> Queue[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) }
#|}
#|pub impl[A : Show] Show for Queue[A] with output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@queue.of([", suffix="])")
#|}
#|impl[A : Eq] Eq for Queue[A] with equal(self, other) {
#| self.length == other.length && self.first == other.first
#|}
#|pub fn[A] clear(self : Queue[A]) -> Unit {
#| self.length = 0
#| self.first = None
#| self.last = None
#|}
#|pub fn[A] length(self : Queue[A]) -> Int {
#| self.length
#|}
#|pub fn[A] is_empty(self : Queue[A]) -> Bool {
#| self.length == 0
#|}
#|pub fn[A] push(self : Queue[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
#| }
#| }
#|}
#|#internal(unsafe, "Panics if the queue is empty.")
#|pub fn[A] unsafe_peek(self : Queue[A]) -> A {
#| match self.first {
#| None => abort("Queue is empty")
#| Some(first) => first.content
#| }
#|}
#|pub fn[A] peek(self : Queue[A]) -> A? {
#| match self.first {
#| None => None
#| Some(first) => Some(first.content)
#| }
#|}
#|#internal(unsafe, "Panics if the queue is empty.")
#|pub fn[A] unsafe_pop(self : Queue[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
#| }
#| }
#|}
#|pub fn[A] pop(self : Queue[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)
#| }
#| }
#|}
#|pub fn[A] each(self : Queue[A], f : (A) -> Unit) -> Unit {
#| loop self.first {
#| Some({ content, next }) => {
#| f(content)
#| continue next
#| }
#| None => ()
#| }
#|}
#|pub fn[A] eachi(self : Queue[A], f : (Int, A) -> Unit) -> Unit {
#| loop (self.first, 0) {
#| (Some({ content, next }), index) => {
#| f(index, content)
#| continue (next, index + 1)
#| }
#| (None, _) => ()
#| }
#|}
#|pub fn[A, B] fold(self : Queue[A], init~ : B, f : (B, A) -> B) -> B {
#| loop (self.first, init) {
#| (None, acc) => acc
#| (Some({ content, next }), acc) => continue (next, f(acc, content))
#| }
#|}
#|pub fn[A] copy(self : Queue[A]) -> Queue[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) }
#|}
#|pub fn[A] transfer(self : Queue[A], dst : Queue[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()
#| }
#| }
#| }
#|}
#|pub fn[A] iter(self : Queue[A]) -> Iter[A] {
#| Iter::new(yield_ => loop self.first {
#| Some({ content, next }) => {
#| if yield_(content) == IterEnd {
#| break IterEnd
#| }
#| continue next
#| }
#| None => IterContinue
#| })
#|}
#|pub fn[A] from_iter(iter : Iter[A]) -> Queue[A] {
#| let q = new()
#| iter.each(e => q.push(e))
#| q
#|}
#|pub fn[A] of(arr : FixedArray[A]) -> Queue[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) }
#|}
#|test "from_fixed_array_2" {
#| let q = of([1, 2, 3, 4])
#| q.push(11)
#| assert_eq(q, of([1, 2, 3, 4, 11]))
#| q.unsafe_pop() |> ignore
#| assert_eq(q, of([2, 3, 4, 11]))
#|}
#|test "from_array_2" {
#| let q = of([1, 2, 3, 4])
#| q.push(11)
#| assert_eq(q, of([1, 2, 3, 4, 11]))
#| q.unsafe_pop() |> ignore
#| assert_eq(q, of([2, 3, 4, 11]))
#|}
#|test "op_equal" {
#| let queue = of([1, 2, 3, 4])
#| let queue2 = of([1, 2, 3, 4])
#| let queue3 = of([1, 2, 3, 5])
#| assert_true(queue == queue2)
#| assert_false(queue == queue3)
#| queue.unsafe_pop() |> ignore
#| assert_false(queue == queue2)
#| assert_eq(queue, of([2, 3, 4]))
#|}
#|test "push" {
#| let queue : Queue[Int] = new()
#| queue.push(1)
#| queue.push(2)
#| queue.push(3)
#| queue.push(1)
#| assert_eq(queue.length(), 4)
#| assert_eq(queue, of([1, 2, 3, 1]))
#|}
#|test "copy" {
#| let queue : Queue[Int] = of([1, 2, 3, 4])
#| let queue2 : Queue[Int] = queue.copy()
#| assert_eq(queue2.length(), 4)
#| assert_eq(queue2, of([1, 2, 3, 4]))
#| assert_eq(queue.length(), 4)
#| assert_eq(queue, of([1, 2, 3, 4]))
#|}
#|test "transfer" {
#| let queue : Queue[Int] = of([1, 2, 3, 4])
#| let queue2 : Queue[Int] = of([5, 6, 7, 8])
#| queue.transfer(queue2)
#| assert_eq(queue.length(), 0)
#| assert_eq(queue2.length(), 8)
#| assert_eq(queue2, of([5, 6, 7, 8, 1, 2, 3, 4]))
#|}
#|test "cell_equal" {
#| assert_false(of([]).first == of([1]).first)
#|}
#|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for Queue[X] with arbitrary(
#| size,
#| rs,
#|) {
#| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_iter
#|}
),
"types.mbt": (
#|priv struct Cons[A] {
#| content : A
#| mut next : Cons[A]?
#|} derive(Eq)
#|struct Queue[A] {
#| mut length : Int
#| mut first : Cons[A]?
#| mut last : Cons[A]?
#|}
#|#deprecated("use `Queue` instead of `T`")
#|pub typealias Queue as T
),
},
)
///|
let moonbitlang_core_quickcheck_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/quickcheck/splitmix",
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/char"
#| ],
#| "test-import": [
#| "moonbitlang/core/array",
#| "moonbitlang/core/bigint",
#| "moonbitlang/core/float",
#| "moonbitlang/core/double",
#| "moonbitlang/core/tuple"
#| ]
#|}
),
"arbitrary.mbt": (
#|pub(open) trait Arbitrary {
#| arbitrary(Int, @splitmix.RandomState) -> Self
#|}
#|pub impl Arbitrary for Unit with arbitrary(_, _) {
#| ()
#|}
#|pub impl Arbitrary for Bool with arbitrary(_, rs) {
#| rs.next_double() < 0.5
#|}
#|pub impl Arbitrary for Int with arbitrary(size, rs) {
#| if size == 0 {
#| 0
#| } else {
#| rs.next_int() % size
#| }
#|}
#|pub impl Arbitrary for UInt with arbitrary(size, rs) {
#| if size == 0 {
#| 0
#| } else {
#| rs.next_uint() % size.reinterpret_as_uint()
#| }
#|}
#|pub impl Arbitrary for Byte with arbitrary(_, rs) {
#| rs.next_uint().to_byte()
#|}
#|pub impl Arbitrary for Bytes with arbitrary(size, rs) {
#| if size == 0 {
#| Bytes::new(0)
#| } else {
#| let sz = rs.next_positive_int() % size
#| Bytes::makei(sz, _ => Arbitrary::arbitrary(size, rs))
#| }
#|}
#|pub impl Arbitrary for Int64 with arbitrary(size, rs) {
#| if size == 0 {
#| 0
#| } else {
#| rs.next_int64() % size.to_int64()
#| }
#|}
#|pub impl Arbitrary for UInt64 with arbitrary(size, rs) {
#| if size == 0 {
#| 0
#| } else {
#| rs.next_uint64() % size.to_uint64()
#| }
#|}
#|pub impl Arbitrary for Float with arbitrary(_, rs) {
#| rs.next_float()
#|}
#|pub impl Arbitrary for Double with arbitrary(_, rs) {
#| rs.next_double()
#|}
#|pub impl Arbitrary for Char with arbitrary(_, rs) {
#| ((rs.next_uint() % 128) |> UInt::reinterpret_as_int).unsafe_to_char()
#|}
#|pub impl Arbitrary for String with arbitrary(size, rs) {
#| let len = if size == 0 { 0 } else { rs.next_positive_int() % size }
#| let mut s = ""
#| for i in 0.. for i in 0.. 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)
#|}
),
"utils.mbt": (
#|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~)
#|}
),
"random.mbt": (
#|struct RandomState {
#| mut seed : UInt64
#| gamma : UInt64
#|} derive(Show, Default)
#|let golden_gamma : UInt64 = 0x9e3779b97f4a7c15
#|let double_ulp : Double = 1.0 / (1L << 53).to_double()
#|let float_ulp : Float = 1.0.to_float() / (1L << 24).to_float()
#|pub fn new(seed? : UInt64 = 37) -> RandomState {
#| { seed: mix64(seed), gamma: mix_gamma(seed + golden_gamma) }
#|}
#|pub fn clone(self : RandomState) -> RandomState {
#| { ..self }
#|}
#|pub fn next(self : RandomState) -> Unit {
#| self.next_uint64() |> ignore
#|}
#|pub fn next_uint64(self : RandomState) -> UInt64 {
#| let { seed, gamma } = self
#| self.seed = seed + gamma
#| mix64(self.seed)
#|}
#|pub fn next_uint(self : RandomState) -> UInt {
#| self.next_uint64().to_uint()
#|}
#|pub fn next_int64(self : RandomState) -> Int64 {
#| self.next_uint64().reinterpret_as_int64()
#|}
#|pub fn next_two_uint(self : RandomState) -> (UInt, UInt) {
#| let g = self.next_uint64()
#| ((g >> 32).to_uint(), g.to_uint())
#|}
#|pub fn next_int(self : RandomState) -> Int {
#| self.next_uint().reinterpret_as_int()
#|}
#|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
#| }
#|}
#|pub fn next_float(self : RandomState) -> Float {
#| let u = self.next_uint64()
#| (u >> 11).to_float() * float_ulp
#|}
#|pub fn next_double(self : RandomState) -> Double {
#| let u = self.next_uint64()
#| (u >> 11).to_double() * double_ulp
#|}
#|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) }
#|}
#|fn shift_xor(n : Int, w : UInt64) -> UInt64 {
#| w ^ (w >> n)
#|}
#|fn shift_xor_mul(n : Int, k : UInt64, w : UInt64) -> UInt64 {
#| shift_xor(n, w) * k
#|}
#|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)
#|}
#|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)
#|}
#|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 : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/double",
#| "moonbitlang/core/random/internal/random_source",
#| "moonbitlang/core/bigint"
#| ],
#| "test-import": [
#| "moonbitlang/core/float",
#| "moonbitlang/core/bench"
#| ]
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `Rand::new()` instead")
#|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
#|}
),
"random.mbt": (
#|struct Rand(&Source)
#|pub(open) trait Source {
#| next(Self) -> UInt64
#|}
#|impl Source for @random_source.ChaCha8 with next(self : @random_source.ChaCha8) -> UInt64 {
#| for {
#| if self.next() is Some(x) {
#| return x
#| }
#| self.refill()
#| }
#|}
#|pub fn Rand::chacha8(
#| seed? : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456",
#|) -> Rand {
#| if seed.length() != 32 {
#| abort("seed must be 32 bytes long")
#| }
#| Rand(@random_source.ChaCha8::new(seed) as &Source)
#|}
#|#deprecated("You may use `Rand::chacha8(seed~)` instead of `Rand::new(chacha8(seed~))")
#|pub fn chacha8(seed? : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456") -> &Source {
#| @random_source.ChaCha8::new(seed)
#|}
#|pub fn Rand::new(generator? : &Source) -> Rand {
#| match generator {
#| None => chacha8()
#| Some(gen) => Rand(gen)
#| }
#|}
#|fn next(self : Rand) -> UInt64 {
#| let Rand(s) = self
#| s.next()
#|}
#|test "next" {
#| let r = new()
#| let n = r.next()
#| let exp = 13219109469176600229UL
#| assert_eq(n, exp)
#|}
#|pub fn int(self : Rand, limit? : Int = 0) -> Int {
#| if limit == 0 {
#| (self.next() >> 33).to_int()
#| } else {
#| self.uint(limit=limit.reinterpret_as_uint()).reinterpret_as_int()
#| }
#|}
#|pub fn int64(self : Rand, limit? : Int64 = 0) -> Int64 {
#| if limit == 0 {
#| let mask : UInt64 = (1UL << 63) - 1UL
#| return (self.next() & mask).reinterpret_as_int64()
#| } else {
#| self.uint64(limit=limit.reinterpret_as_uint64()).reinterpret_as_int64()
#| }
#|}
#|pub fn uint(self : Rand, limit? : UInt = 0) -> UInt {
#| if limit == 0 {
#| return self.next().to_uint()
#| }
#| self.uint64(limit=limit.to_uint64()).to_uint()
#|}
#|test "uint" {
#| let r = new()
#| let n = r.uint(limit=10U)
#| inspect(n, content="7")
#| let n = r.uint(limit=10U)
#| inspect(n, content="0")
#| let n = r.uint(limit=10U)
#| inspect(n, content="5")
#|}
#|pub fn uint64(self : Rand, limit? : UInt64 = 0) -> UInt64 {
#| if limit == 0 {
#| return self.next()
#| } else if (limit & (limit - 1)) == 0 {
#| 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
#|}
#|test "UInt64" {
#| let r = new()
#| let n = r.uint64()
#| let exp = 13219109469176600229UL
#| assert_eq(n, exp)
#| let r = new()
#| let n = r.uint64(limit=10UL)
#| inspect(n, content="7")
#| let n = r.uint64(limit=10UL)
#| inspect(n, content="0")
#| let n = r.uint64(limit=10UL)
#| inspect(n, content="5")
#|}
#|pub fn double(self : Rand) -> Double {
#| Double::convert_uint64(self.next() << 11 >> 11) /
#| Double::convert_uint64(1UL << 53)
#|}
#|test "double" {
#| let r = new()
#| let n = r.double()
#| inspect(n, content="0.615969772029264")
#|}
#|pub fn float(self : Rand) -> Float {
#| (self.uint() << 8 >> 8).to_float() / (1U << 24).to_float()
#|}
#|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)
#|}
#|test "bigint" {
#| let r = new()
#| inspect(r.bigint(1), content="1")
#| inspect(r.bigint(3), content="4")
#| inspect(r.bigint(7), content="124")
#| inspect(r.bigint(8), content="214")
#| inspect(r.bigint(32), content="2910404175")
#| inspect(r.bigint(40), content="714745001576")
#| inspect(r.bigint(64), content="13430064486797060338")
#| inspect(r.bigint(128), content="251068071753473224445949321151725639522")
#|}
#|#valtype
#|priv struct UInt128 {
#| hi : UInt64
#| lo : UInt64
#|}
#|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 }
#|}
#|test "umul128" {
#| let r = umul128(0x123456789ABCDEF0, 0xFEDCBA9876543210)
#| assert_eq(r.hi, 1305938385386173474UL)
#| assert_eq(r.lo, 2552847189736476416UL)
#|}
#|test "umul128: handles small numbers correctly" {
#| let r = umul128(1UL, 1UL)
#| assert_eq(r.hi, 0UL)
#| assert_eq(r.lo, 1UL)
#|}
#|test "umul128: handles large numbers correctly" {
#| let r = umul128(1UL, 0xFFFFFFFFFFFFFFFFUL)
#| assert_eq(r.hi, 0UL)
#| assert_eq(r.lo, 0xFFFFFFFFFFFFFFFFUL)
#|}
#|test "umul128: handles zero correctly" {
#| let r = umul128(0UL, 0UL)
#| assert_eq(r.hi, 0UL)
#| assert_eq(r.lo, 0UL)
#|}
#|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)
#| }
#|}
#|test "shuffle" {
#| let r = new()
#| let a = [1, 2, 3, 4, 5]
#| r.shuffle(a.length(), (i : Int, j : Int) => {
#| let t = a[i]
#| a[i] = a[j]
#| a[j] = t
#| })
#| inspect(a, content="[3, 5, 2, 1, 4]")
#|}
),
},
)
///|
let moonbitlang_core_random_internal_random_source_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/array",
#| "moonbitlang/core/bytes"
#| ]
#|}
),
"random_source_chacha.mbt": (
#|struct ChaCha8 {
#| buffer : FixedArray[UInt]
#| seed : FixedArray[UInt]
#| mut i : UInt
#| mut n : UInt
#| mut counter : UInt
#|}
#|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() }
#|}
#|const COUNTER_INC = 4U
#|const COUNTER_MAX = 16U
#|const BUFFER_CHUNK_NUM = 32
#|const SEED_CHUNK_NUM = 4
#|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)
#|}
#|pub fn ChaCha8::refill(self : ChaCha8) -> Unit {
#| self.counter += COUNTER_INC
#| if self.counter == COUNTER_MAX {
#| 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()
#| }
#|}
#|#valtype
#|priv struct Quadruple {
#| _0 : UInt
#| _1 : UInt
#| _2 : UInt
#| _3 : UInt
#|}
#|fn chacha_block(
#| seed : FixedArray[UInt],
#| buf : FixedArray[UInt],
#| counter : UInt,
#|) -> Unit {
#| fn qr(t : Quadruple) -> Quadruple {
#| let a = t._0
#| let b = t._1
#| let c = t._2
#| let d = t._3
#| let a = a + b
#| let d = d ^ a
#| let d = (d << 16) | (d >> 16)
#| let c = c + d
#| let b = b ^ c
#| let b = (b << 12) | (b >> 20)
#| let a = a + b
#| let d = d ^ a
#| let d = (d << 8) | (d >> 24)
#| let c = c + d
#| let b = b ^ c
#| let b = (b << 7) | (b >> 25)
#| { _0: a, _1: b, _2: c, _3: d }
#| }
#| setup(seed, buf, counter)
#| for i in 0..<4 {
#| let mut b0 = buf[0 * 4 + i]
#| let mut b1 = buf[1 * 4 + i]
#| let mut b2 = buf[2 * 4 + i]
#| let mut b3 = buf[3 * 4 + i]
#| let mut b4 = buf[4 * 4 + i]
#| let mut b5 = buf[5 * 4 + i]
#| let mut b6 = buf[6 * 4 + i]
#| let mut b7 = buf[7 * 4 + i]
#| let mut b8 = buf[8 * 4 + i]
#| let mut b9 = buf[9 * 4 + i]
#| let mut b10 = buf[10 * 4 + i]
#| let mut b11 = buf[11 * 4 + i]
#| let mut b12 = buf[12 * 4 + i]
#| let mut b13 = buf[13 * 4 + i]
#| let mut b14 = buf[14 * 4 + i]
#| let mut b15 = buf[15 * 4 + i]
#| for round in 0..<4 {
#| let tb1 = qr({ _0: b0, _1: b4, _2: b8, _3: b12 })
#| b0 = tb1._0
#| b4 = tb1._1
#| b8 = tb1._2
#| b12 = tb1._3
#| let tb2 = qr({ _0: b1, _1: b5, _2: b9, _3: b13 })
#| b1 = tb2._0
#| b5 = tb2._1
#| b9 = tb2._2
#| b13 = tb2._3
#| let tb3 = qr({ _0: b2, _1: b6, _2: b10, _3: b14 })
#| b2 = tb3._0
#| b6 = tb3._1
#| b10 = tb3._2
#| b14 = tb3._3
#| let tb4 = qr({ _0: b3, _1: b7, _2: b11, _3: b15 })
#| b3 = tb4._0
#| b7 = tb4._1
#| b11 = tb4._2
#| b15 = tb4._3
#| let tb5 = qr({ _0: b0, _1: b5, _2: b10, _3: b15 })
#| b0 = tb5._0
#| b5 = tb5._1
#| b10 = tb5._2
#| b15 = tb5._3
#| let tb6 = qr({ _0: b1, _1: b6, _2: b11, _3: b12 })
#| b1 = tb6._0
#| b6 = tb6._1
#| b11 = tb6._2
#| b12 = tb6._3
#| let tb7 = qr({ _0: b2, _1: b7, _2: b8, _3: b13 })
#| b2 = tb7._0
#| b7 = tb7._1
#| b8 = tb7._2
#| b13 = tb7._3
#| let tb8 = qr({ _0: b3, _1: b4, _2: b9, _3: b14 })
#| b3 = tb8._0
#| b4 = tb8._1
#| b9 = tb8._2
#| b14 = tb8._3
#| }
#| buf[0 * 4 + i] = b0
#| buf[1 * 4 + i] = b1
#| buf[2 * 4 + i] = b2
#| buf[3 * 4 + i] = b3
#| buf[4 * 4 + i] += b4
#| buf[5 * 4 + i] += b5
#| buf[6 * 4 + i] += b6
#| buf[7 * 4 + i] += b7
#| buf[8 * 4 + i] += b8
#| buf[9 * 4 + i] += b9
#| buf[10 * 4 + i] += b10
#| buf[11 * 4 + i] += b11
#| buf[12 * 4 + i] = b12
#| buf[13 * 4 + i] = b13
#| buf[14 * 4 + i] = b14
#| buf[15 * 4 + i] = b15
#| }
#|}
#|fn setup(
#| seed : FixedArray[UInt],
#| b32 : FixedArray[UInt],
#| counter : UInt,
#|) -> Unit {
#| b32[0 * 4 + 0] = 0x61707865
#| b32[0 * 4 + 1] = 0x61707865
#| b32[0 * 4 + 2] = 0x61707865
#| b32[0 * 4 + 3] = 0x61707865
#| b32[1 * 4 + 0] = 0x3320646e
#| b32[1 * 4 + 1] = 0x3320646e
#| b32[1 * 4 + 2] = 0x3320646e
#| b32[1 * 4 + 3] = 0x3320646e
#| b32[2 * 4 + 0] = 0x79622d32
#| b32[2 * 4 + 1] = 0x79622d32
#| b32[2 * 4 + 2] = 0x79622d32
#| b32[2 * 4 + 3] = 0x79622d32
#| b32[3 * 4 + 0] = 0x6b206574
#| b32[3 * 4 + 1] = 0x6b206574
#| b32[3 * 4 + 2] = 0x6b206574
#| b32[3 * 4 + 3] = 0x6b206574
#| b32[4 * 4 + 0] = seed[0]
#| b32[4 * 4 + 1] = seed[0]
#| b32[4 * 4 + 2] = seed[0]
#| b32[4 * 4 + 3] = seed[0]
#| b32[5 * 4 + 0] = seed[1]
#| b32[5 * 4 + 1] = seed[1]
#| b32[5 * 4 + 2] = seed[1]
#| b32[5 * 4 + 3] = seed[1]
#| b32[6 * 4 + 0] = seed[2]
#| b32[6 * 4 + 1] = seed[2]
#| b32[6 * 4 + 2] = seed[2]
#| b32[6 * 4 + 3] = seed[2]
#| b32[7 * 4 + 0] = seed[3]
#| b32[7 * 4 + 1] = seed[3]
#| b32[7 * 4 + 2] = seed[3]
#| b32[7 * 4 + 3] = seed[3]
#| b32[8 * 4 + 0] = seed[4]
#| b32[8 * 4 + 1] = seed[4]
#| b32[8 * 4 + 2] = seed[4]
#| b32[8 * 4 + 3] = seed[4]
#| b32[9 * 4 + 0] = seed[5]
#| b32[9 * 4 + 1] = seed[5]
#| b32[9 * 4 + 2] = seed[5]
#| b32[9 * 4 + 3] = seed[5]
#| b32[10 * 4 + 0] = seed[6]
#| b32[10 * 4 + 1] = seed[6]
#| b32[10 * 4 + 2] = seed[6]
#| b32[10 * 4 + 3] = seed[6]
#| b32[11 * 4 + 0] = seed[7]
#| b32[11 * 4 + 1] = seed[7]
#| b32[11 * 4 + 2] = seed[7]
#| b32[11 * 4 + 3] = seed[7]
#| b32[12 * 4 + 0] = counter + 0
#| b32[12 * 4 + 1] = counter + 1
#| b32[12 * 4 + 2] = counter + 2
#| b32[12 * 4 + 3] = counter + 3
#| b32[13 * 4 + 0] = 0
#| b32[13 * 4 + 1] = 0
#| b32[13 * 4 + 2] = 0
#| b32[13 * 4 + 3] = 0
#| b32[14 * 4 + 0] = 0
#| b32[14 * 4 + 1] = 0
#| b32[14 * 4 + 2] = 0
#| b32[14 * 4 + 3] = 0
#| b32[15 * 4 + 0] = 0
#| b32[15 * 4 + 1] = 0
#| b32[15 * 4 + 2] = 0
#| b32[15 * 4 + 3] = 0
#|}
#|test "BUFFER_CHUNK_NUM is power of 2" {
#| assert_eq(BUFFER_CHUNK_NUM.clz() + BUFFER_CHUNK_NUM.ctz(), 31)
#|}
#|test "output" {
#| let s = ChaCha8::new(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456")
#| let res = Array::new(capacity=372)
#| fn uint64(s : ChaCha8) -> UInt64 {
#| for {
#| if s.next() is Some(x) {
#| return x
#| }
#| s.refill()
#| }
#| }
#| for i in 0..<372 {
#| let x = uint64(s)
#| res.push(x)
#| }
#| let expected = [
#| 13219109469176600229UL, 1252193259764759612UL, 10098646897834928252UL, 9142445797040479446UL,
#| 14963947397558572717UL, 1011356013395962489UL, 4360278772332321598UL, 11266561239126549327UL,
#| 16103107970030431910UL, 3951155890335085418UL, 17217491508779737119UL, 620366957612729398UL,
#| 15701003340574544488UL, 16946962128229337786UL, 5734710318278665825UL, 14107018073513584172UL,
#| 10514695901183618686UL, 8668570317698669510UL, 6644195231047269920UL, 5695522258251995816UL,
#| 18173674537264966642UL, 6561080880156464316UL, 7896566770606135777UL, 17198961315715285235UL,
#| 3258233649777561765UL, 4039019003980269744UL, 17199080872890330697UL, 17597083911441838460UL,
#| 9541597232904836516UL, 10269632480771352091UL, 1791309313159652499UL, 1121290688170442051UL,
#| 14767415290099658880UL, 18264015867885335344UL, 10795746865526236211UL, 7814966709161082135UL,
#| 5056082071174014306UL, 6606687772221963370UL, 902460967827941768UL, 15247644503822243389UL,
#| 13837920613503741631UL, 6215820458297045417UL, 2701601382099612372UL, 8049443921449462014UL,
#| 12580932726856406240UL, 5068579462968063859UL, 2054759765710618254UL, 8060325759976441792UL,
#| 3952703220727229276UL, 11868554197401451959UL, 5611917470950228677UL, 14826085289999852455UL,
#| 18131733951999902497UL, 6983040833037131399UL, 15098965934858340182UL, 7162487557317849930UL,
#| 389612597396113390UL, 5480468948381420210UL, 14924541494497045954UL, 438038016380948435UL,
#| 15107526033745383085UL, 3577988464916041960UL, 12379376873809997548UL, 4629939204773816090UL,
#| 4382836348202044776UL, 15911307370497934714UL, 16912525941835256446UL, 1749399752872286892UL,
#| 17865934552210109010UL, 6342441227090084049UL, 6679300346758746971UL, 16633103117551110662UL,
#| 369926567391976152UL, 3270154504052173416UL, 12351442307584366520UL, 14053856752323452444UL,
#| 5700095014850418212UL, 18134114469714363192UL, 11060594460025237009UL, 1231359220627153402UL,
#| 562452272787830041UL, 2978775404523127572UL, 4722226048622717816UL, 6253931703231703629UL,
#| 9215422719337958629UL, 3873253580645818250UL, 1288530853271360801UL, 11001669669030575221UL,
#| 15088099745414120440UL, 10121311161118028787UL, 2646319338087045047UL, 8736474933647836016UL,
#| 10270419548610515257UL, 4775977266197392933UL, 5858955664787759631UL, 15884112255303985129UL,
#| 1570402559843208890UL, 14683984304255533684UL, 4590793746421620769UL, 15088822470495597798UL,
#| 430063278371467896UL, 17951554591419905623UL, 871816740556950425UL, 17903421440867820178UL,
#| 13750571273678813240UL, 17408919480923799904UL, 14550467517685344003UL, 17801022151644150006UL,
#| 15135601085914355452UL, 3483086720686978374UL, 9411102566564534151UL, 1565275101947305404UL,
#| 18195171881473325257UL, 3771067494878101692UL, 7443114766343082856UL, 1311911009840065015UL,
#| 1031414546975514137UL, 16727931877057143004UL, 420176525623228030UL, 16779254430513255833UL,
#| 2085321528439172864UL, 14769502908867070793UL, 3476754806476653326UL, 9663999206884821105UL,
#| 6864012991572870279UL, 2719468417766812445UL, 13735767778024137757UL, 7331676388138190150UL,
#| 15110277136215905228UL, 118894811326561078UL, 6308935423749160781UL, 1857610629058673910UL,
#| 15843686394045370811UL, 10951543581626859443UL, 3587431610669043023UL, 670469650389812154UL,
#| 476209600999700306UL, 6589566024609793738UL, 8281611217869782149UL, 15129277549214352190UL,
#| 13446421929377692845UL, 17071158676955966275UL, 7349330903428905191UL, 3277698994734830674UL,
#| 14731635658592643043UL, 5477400073429632652UL, 67518392538487036UL, 11035168000757098093UL,
#| 9797693702590129641UL, 14649582299731326424UL, 15236666389149272153UL, 16511980240231261314UL,
#| 2249833951459307500UL, 13214955418772830438UL, 329963039908253864UL, 8574511220958401562UL,
#| 4538345089129965474UL, 16353802882881726632UL, 8935276449126753317UL, 13532443277699696063UL,
#| 8669346374187395779UL, 17810417737921607796UL, 3904677225590828551UL, 10264576476552345822UL,
#| 3042606770072189440UL, 12878478126980245939UL, 17862138228081367377UL, 16992359172961651842UL,
#| 17034107108697981338UL, 12909026467335450156UL, 2470441546010339704UL, 3634699771143106326UL,
#| 366960336551226348UL, 5510841956427041079UL, 15461212383052875073UL, 16433279593065139848UL,
#| 4486890193637877972UL, 14360905330534596440UL, 4449385520993789019UL, 3743094329222006520UL,
#| 2212668117926313829UL, 4681723502265844963UL, 13296513799272088946UL, 2343616111600662093UL,
#| 14717171566066041529UL, 11738831003851491807UL, 15851419960104864784UL, 8132762647638440149UL,
#| 3464418631265929631UL, 340027485718840165UL, 8395791638092059350UL, 3109485649064359417UL,
#| 10944349985020042736UL, 6522608726689095595UL, 17803052569896648610UL, 2064238649661354599UL,
#| 4092763376312896325UL, 15988266335744638521UL, 16848187183754420180UL, 199841868197609864UL,
#| 17491157950173501157UL, 12533485177359032661UL, 6254686503080376974UL, 5499127381395659705UL,
#| 10487847042307388775UL, 12368654789669906974UL, 2361938659724380109UL, 8148818964487342298UL,
#| 12717021730603072605UL, 15728257831000719154UL, 15823591063810279774UL, 6928887951986678348UL,
#| 17959062744186568888UL, 16016655507227678734UL, 14898526437837544110UL, 16974466848830908932UL,
#| 15320157178342639871UL, 8261903640164714632UL, 14435417271854760UL, 9182672404209601003UL,
#| 5994285655773158181UL, 15654703508405219038UL, 16079243345868226083UL, 10784497444694088416UL,
#| 4442318623009455690UL, 7578904045792755239UL, 4660917127407640248UL, 1338871040102977572UL,
#| 7923968833761895669UL, 16874906449763725362UL, 6867431507591727612UL, 6311558572587278442UL,
#| 11133241125491102835UL, 11738312930013082355UL, 11475845091361842759UL, 1643869946623606078UL,
#| 10415771985971144045UL, 16177299554619494974UL, 539570561320537202UL, 14686903393511273001UL,
#| 4445884513647149105UL, 5098090666552700373UL, 15054419504752089185UL, 3474469100259604016UL,
#| 6290470378995655110UL, 12581245818984890955UL, 12787308417917333104UL, 15615073174539148765UL,
#| 12984984669203863910UL, 5985056152809872019UL, 11524779172526084917UL, 12665285781050723551UL,
#| 17258307941988319274UL, 1228317169172941352UL, 11160397433235040502UL, 9071341095814202162UL,
#| 16466220084500004578UL, 17881879368693790694UL, 11823018491644357805UL, 16578188432210840351UL,
#| 9406010430949605407UL, 11905115929048085077UL, 9944213925190004442UL, 7029678422186467496UL,
#| 11401152387492259905UL, 10919895159361451251UL, 8495109194203518959UL, 16018667729961568082UL,
#| 167446916071967039UL, 5832416432401633017UL, 2555624166217836526UL, 4693948454793001376UL,
#| 15027938303073958689UL, 3816085682362256244UL, 3185235675206645589UL, 14811052307061536715UL,
#| 16390566561388972206UL, 16262619695511054469UL, 18052593823409859051UL, 3945540604022845918UL,
#| 15826009464703323776UL, 7719326347171925540UL, 9769778031520080067UL, 421859423473436660UL,
#| 13367093898566883586UL, 6779889834239319169UL, 609582038820777224UL, 8614685872506396309UL,
#| 4322299411370527537UL, 12846241946314463225UL, 7603764924892388925UL, 14478986206635481787UL,
#| 12755177540574038518UL, 6194314060039108547UL, 7432498317049243916UL, 13744344095303706494UL,
#| 4564573594452194471UL, 15206391374377392170UL, 14985029622013689232UL, 14328768324291300885UL,
#| 10654090591156151429UL, 7338671807663089189UL, 16334907285225846266UL, 7423398075744368270UL,
#| 13908293662617472937UL, 17175512688958868014UL, 7864028190390018941UL, 13126986956610526127UL,
#| 7926473773501694475UL, 1941817884837167576UL, 15856689629067382306UL, 11177334980354607906UL,
#| 7146885710676518584UL, 15983324774902192370UL, 17386093453964105449UL, 4150817240659351930UL,
#| 7715942048190956297UL, 7276773301104081815UL, 13271959532491042945UL, 1194118668544183835UL,
#| 17605071903565571062UL, 8948583740938417863UL, 3864418170274807074UL, 3699237212540510096UL,
#| 14714003198217388528UL, 14269453830925281739UL, 8957047989018367339UL, 12402048382093370001UL,
#| 11758047802384768757UL, 7093460309329455699UL, 384408371497488372UL, 1458858056370266940UL,
#| 15774153359596962328UL, 5577985376535770293UL, 3965786813088619889UL, 17835800480481320920UL,
#| 32994991092960231UL, 17146972595756459521UL, 12264557860820767038UL, 13718959782553074566UL,
#| 1372337231943282583UL, 15958043944784669526UL, 17520298198669188203UL, 3031291504644241637UL,
#| 6514984797562383624UL, 4345071177348538448UL, 3359260195018829989UL, 2607793539626362761UL,
#| 16792663172613334423UL, 9898393582456908268UL, 2786478731415243607UL, 12029113901756054096UL,
#| 3691479334576095829UL, 11929280456476427793UL, 18327972477027512052UL, 254886074006853656UL,
#| 2927328918014182935UL, 4439939690082200099UL, 5969478689443458641UL, 14369317615642310767UL,
#| 17764732325494572140UL, 10115938472474762880UL, 369466901724782737UL, 2269989694701338999UL,
#| 1231466417883291608UL, 4918841702239877720UL, 13883670878602349637UL, 11470126477371023265UL,
#| 17128636052794644986UL, 205335811880395712UL, 12443170494233065292UL, 15986026963143729439UL,
#| ]
#| assert_eq(res, expected)
#|}
),
},
)
///|
let moonbitlang_core_rational_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/double",
#| "moonbitlang/core/int64",
#| "moonbitlang/core/quickcheck"
#| ]
#|}
),
"rational.mbt": (
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|struct T {
#| numerator : Int64
#| denominator : Int64
#|}
#|fn gcd(a : Int64, b : Int64) -> Int64 {
#| for a = a, b = b {
#| if b == 0L {
#| break a
#| }
#| continue b, a % b
#| }
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|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 })
#| }
#|}
#|fn new_unchecked(numerator : Int64, denominator : Int64) -> T {
#| let gcd = gcd(numerator.abs(), denominator)
#| { numerator: numerator / gcd, denominator: denominator / gcd }
#|}
#|#coverage.skip
#|pub impl Add for T with add(self : T, other : T) -> T {
#| new_unchecked(
#| self.numerator * other.denominator + other.numerator * self.denominator,
#| self.denominator * other.denominator,
#| )
#|}
#|#coverage.skip
#|pub impl Sub for T with sub(self : T, other : T) -> T {
#| new_unchecked(
#| self.numerator * other.denominator - other.numerator * self.denominator,
#| self.denominator * other.denominator,
#| )
#|}
#|#coverage.skip
#|pub impl Mul for T with mul(self : T, other : T) -> T {
#| new_unchecked(
#| self.numerator * other.numerator,
#| self.denominator * other.denominator,
#| )
#|}
#|#coverage.skip
#|pub impl Div for T with div(self : T, other : T) -> T {
#| if other.numerator < 0L {
#| new_unchecked(
#| self.numerator * -other.denominator,
#| self.denominator * -other.numerator,
#| )
#| } else {
#| new_unchecked(
#| self.numerator * other.denominator,
#| self.denominator * other.numerator,
#| )
#| }
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|pub fn reciprocal(self : T) -> T {
#| if self.numerator < 0L {
#| new_unchecked(-self.denominator, -self.numerator)
#| } else {
#| new_unchecked(self.denominator, self.numerator)
#| }
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|pub fn T::neg(self : T) -> T {
#| new_unchecked(-self.numerator, self.denominator)
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|pub fn T::abs(self : T) -> T {
#| new_unchecked(self.numerator.abs(), self.denominator)
#|}
#|#coverage.skip
#|pub impl Eq for T with equal(self : T, other : T) -> Bool {
#| self.numerator * other.denominator == other.numerator * self.denominator
#|}
#|#coverage.skip
#|pub impl Compare for T with compare(self : T, other : T) -> Int {
#| let left = self.numerator * other.denominator
#| let right = other.numerator * self.denominator
#| left.compare(right)
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|pub fn to_double(self : T) -> Double {
#| self.numerator.to_double() / self.denominator.to_double()
#|}
#|fn[T] nan_error() -> T raise RationalError {
#| raise RationalError("Rational::from_double: cannot convert NaN")
#|}
#|fn[T] overflow_error() -> T raise RationalError {
#| raise RationalError("Rational::from_double: overflow")
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|pub(all) suberror RationalError String derive(Show, ToJson(style="flat"))
#|#coverage.skip
#|pub impl Eq for RationalError with equal(
#| self : RationalError,
#| other : RationalError,
#|) -> Bool {
#| match (self, other) {
#| (RationalError(e1), RationalError(e2)) => e1 == e2
#| }
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|pub fn from_double(value : Double) -> T raise RationalError {
#| 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
#| 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
#| 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
#| }
#| let (n_f, d_f) = (n.to_double(), d.to_double())
#| if (n_f / d_f - value).abs() < max_error {
#| break
#| }
#| if f < epsilon {
#| break
#| }
#| q = 1.0 / f
#| }
#| if d1 == 0L {
#| overflow_error()
#| }
#| match new(sign * n1, d1) {
#| Some(r) => r
#| None => abort("Impossible to reach")
#| }
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|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
#| }
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|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
#| }
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|pub fn T::trunc(self : T) -> Int64 {
#| if self.numerator < 0L {
#| -(-self.numerator / self.denominator)
#| } else {
#| self.numerator / self.denominator
#| }
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|pub fn fract(self : T) -> T {
#| new_unchecked(self.numerator % self.denominator, self.denominator)
#|}
#|#coverage.skip
#|pub impl Show for T with output(self, logger) {
#| if self.numerator == 0L {
#| logger.write_char('0')
#| } else if self.denominator == 1L {
#| self.numerator.output(logger)
#| } else {
#| self.numerator.output(logger)
#| logger.write_char('/')
#| self.denominator.output(logger)
#| }
#|}
#|#coverage.skip
#|pub impl @quickcheck.Arbitrary for T with arbitrary(size, rs) {
#| let numerator : Int64 = @quickcheck.Arbitrary::arbitrary(size, rs)
#| let denominator : Int64 = {
#| let d : Int64 = @quickcheck.Arbitrary::arbitrary(size, rs)
#| if d <= 0 {
#| -d + 1
#| } else {
#| d
#| }
#| }
#| new_unchecked(numerator, denominator)
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|pub fn is_integer(self : T) -> Bool {
#| self.denominator == 1L
#|}
#|#deprecated("Use @rational in module moonbitlang/x instead. Note that you need to rename Rational to Rational64.")
#|#coverage.skip
#|pub fnalias T::(neg, abs, ceil, floor, trunc)
),
},
)
///|
let moonbitlang_core_ref_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/ref",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
},
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin", "moonbitlang/core/quickcheck"]
#|}
),
"ref.mbt": (
#|pub fn[T] Ref::new(x : T) -> Ref[T] {
#| { val: x }
#|}
#|test "to_string" {
#| inspect(new(3), content="{val: 3}")
#|}
#|pub fn[T] new(x : T) -> Ref[T] {
#| { val: x }
#|}
#|pub fn[T, R] map(self : Ref[T], f : (T) -> R raise?) -> Ref[R] raise? {
#| { val: f(self.val) }
#|}
#|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
#| }
#| }
#|}
#|pub fn[T] Ref::swap(self : Ref[T], that : Ref[T]) -> Unit {
#| let tmp = self.val
#| self.val = that.val
#| that.val = tmp
#|}
#|pub fnalias Ref::swap
#|test "swap" {
#| let x = new(1)
#| let y = new(2)
#| swap(x, y)
#| inspect(x.val, content="2")
#| inspect(y.val, content="1")
#|}
#|pub fn[T] update(self : Ref[T], f : (T) -> T raise?) -> Unit raise? {
#| self.val = f(self.val)
#|}
#|test "decr" {
#| let a = new(1)
#| a.val -= 1
#| inspect(a.val, content="0")
#| a.val -= 5
#| inspect(a.val, content="-5")
#|}
#|test "incr" {
#| let a = new(1)
#| a.val += 1
#| inspect(a.val, content="2")
#| a.val += 5
#| inspect(a.val, content="7")
#|}
#|pub impl[X : @quickcheck.Arbitrary] @quickcheck.Arbitrary for Ref[X] with arbitrary(
#| size,
#| rs,
#|) {
#| new(X::arbitrary(size, rs))
#|}
),
},
)
///|
let moonbitlang_core_result_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/result",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/quickcheck": moonbitlang_core_quickcheck_module,
},
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin", "moonbitlang/core/quickcheck"],
#| "targets": {
#| "panic_test.mbt": ["not", "native", "llvm"]
#| }
#|}
),
"result.mbt": (
#|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)
#| }
#|}
#|test "map" {
#| let x : Result[Int, Unit] = Ok(6)
#| let y = x.map((v : Int) => v * 7)
#| let z : Result[Int, Int] = Err(3)
#| let w = z.map((v : Int) => v * 7)
#| assert_eq(y, Ok(42))
#| assert_eq(w, Err(3))
#|}
#|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))
#| }
#|}
#|test "map_err" {
#| let x : Result[Int, String] = Err("error")
#| let y = x.map_err((v : String) => v + "!")
#| let z : Result[Int, Int] = Ok(6)
#| let w = z.map_err((v : Int) => v + 6)
#| assert_eq(y, Err("error!"))
#| assert_eq(w, Ok(6))
#|}
#|pub fn[T, E] err(value : E) -> Result[T, E] {
#| Err(value)
#|}
#|test "err" {
#| let x : Result[Int, String] = err("error")
#| assert_eq(x, Err("error"))
#|}
#|pub fn[T, E] ok(value : T) -> Result[T, E] {
#| Ok(value)
#|}
#|test "ok" {
#| let x : Result[String, Unit] = ok("yes")
#| assert_eq(x, Ok("yes"))
#|}
#|pub fn[T, E] is_ok(self : Result[T, E]) -> Bool {
#| self is Ok(_)
#|}
#|test "is_ok" {
#| let x : Result[Int, String] = Ok(6)
#| let y : Result[Int, String] = Err("error")
#| assert_eq(x.is_ok(), true)
#| assert_eq(y.is_ok(), false)
#|}
#|pub fn[T, E] is_err(self : Result[T, E]) -> Bool {
#| self is Err(_)
#|}
#|test "is_err" {
#| let x : Result[Int, String] = Ok(6)
#| let y : Result[Int, String] = Err("error")
#| assert_eq(x.is_err(), false)
#| assert_eq(y.is_err(), true)
#|}
#|pub fn[T, E] or(self : Result[T, E], default : T) -> T {
#| match self {
#| Ok(value) => value
#| Err(_) => default
#| }
#|}
#|test "or" {
#| let x : Result[Int, String] = Ok(6)
#| let y : Result[Int, String] = Err("error")
#| let z = x.or(0)
#| let w = y.or(0)
#| assert_eq(z, 6)
#| assert_eq(w, 0)
#|}
#|pub fn[T, E] or_else(self : Result[T, E], default : () -> T) -> T {
#| match self {
#| Ok(value) => value
#| Err(_) => default()
#| }
#|}
#|test "or_else" {
#| let x : Result[Int, String] = Ok(6)
#| let y : Result[Int, String] = Err("error")
#| let z = x.or_else(() => 0)
#| let w = y.or_else(() => 0)
#| assert_eq(z, 6)
#| assert_eq(w, 0)
#|}
#|pub fn[T, E] flatten(self : Result[Result[T, E], E]) -> Result[T, E] {
#| match self {
#| Ok(value) => value
#| Err(err) => Err(err)
#| }
#|}
#|test "flatten" {
#| let x : Result[Result[Int, String], String] = Ok(Ok(6))
#| let y = x.flatten()
#| let z : Result[Result[Int, String], String] = Err("error")
#| let w = z.flatten()
#| assert_eq(y, Ok(6))
#| assert_eq(w, Err("error"))
#|}
#|pub fn[T, E, U] bind(
#| self : Result[T, E],
#| g : (T) -> Result[U, E],
#|) -> Result[U, E] {
#| match self {
#| Ok(value) => g(value)
#| Err(err) => Err(err)
#| }
#|}
#|test "bind" {
#| let x : Result[Int, String] = Ok(6)
#| let y = x.bind((v : Int) => Ok(v * 7))
#| assert_eq(y, Ok(42))
#|}
#|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)
#| }
#|}
#|test "fold" {
#| let x : Result[Int, String] = Ok(6)
#| let y = x.fold((v : Int) => v * 7, (_e : String) => 0)
#| let z : Result[Int, String] = Err("error")
#| let w = z.fold((v : Int) => v * 7, (_e : String) => 0)
#| assert_eq(y, 42)
#| assert_eq(w, 0)
#|}
#|pub fn[T, E] to_option(self : Result[T, E]) -> T? {
#| match self {
#| Ok(value) => Some(value)
#| Err(_) => None
#| }
#|}
#|test "to_option" {
#| let x : Result[Int, String] = Ok(6)
#| let y : Result[Int, String] = Err("error")
#| let z = x.to_option()
#| let w = y.to_option()
#| assert_eq(z, Some(6))
#| assert_eq(w, None)
#|}
#|pub impl[T : Compare, E : Compare] Compare for Result[T, E] with compare(
#| self : Result[T, E],
#| other : Result[T, E],
#|) -> Int {
#| match (self, other) {
#| (Ok(x), Ok(y)) => x.compare(y)
#| (Ok(_), Err(_)) => -1
#| (Err(_), Ok(_)) => 1
#| (Err(x), Err(y)) => x.compare(y)
#| }
#|}
#|test "compare" {
#| let ok1 = Result::Ok(1)
#| let ok2 = Result::Ok(2)
#| let err1 = Result::Err(1)
#| let err2 = Result::Err(2)
#| assert_eq(0, ok1.compare(ok1))
#| assert_eq(0, err2.compare(Result::Err(2)))
#| assert_eq(-1, ok1.compare(ok2))
#| assert_eq(1, ok2.compare(ok1))
#| assert_eq(-1, err1.compare(err2))
#| assert_eq(1, err2.compare(err1))
#| assert_eq(-1, ok2.compare(err1))
#| assert_eq(1, err1.compare(ok2))
#|}
#|pub fn[T, E] unwrap(self : Result[T, E]) -> T {
#| match self {
#| Ok(x) => x
#| Err(_) => abort("called `Result::unwrap()` on an `Err` value")
#| }
#|}
#|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
#| }
#|}
#|test "show" {
#| let ok : Result[_, String] = Ok("hello")
#| inspect(
#| ok,
#| content=(
#| #|Ok("hello")
#| ),
#| )
#| let err : Result[String, _] = Err("world")
#| inspect(
#| err,
#| content=(
#| #|Err("world")
#| ),
#| )
#|}
#|pub fn[T, E : Error] unwrap_or_error(self : Result[T, E]) -> T raise E {
#| match self {
#| Ok(x) => x
#| Err(e) => raise e
#| }
#|}
#|test "unwrap exn" {
#| (try
#| (Err(Failure("This is serious")) : Result[Unit, Failure]).unwrap_or_error()
#| |> Ok
#| catch {
#| Failure(msg) => Err(msg)
#| })
#| |> inspect(
#| content=(
#| #|Err("This is serious")
#| ),
#| )
#|}
#|pub impl[T : @quickcheck.Arbitrary, E : @quickcheck.Arbitrary] @quickcheck.Arbitrary for Result[
#| T,
#| E,
#|] with arbitrary(size, rs) {
#| if @quickcheck.Arbitrary::arbitrary(size, rs) {
#| Ok(T::arbitrary(size, rs))
#| } else {
#| Err(E::arbitrary(size, rs))
#| }
#|}
),
},
)
///|
let moonbitlang_core_set_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/set",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/int": moonbitlang_core_int_module,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/int"
#| ],
#| "test-import": [
#| "moonbitlang/core/json",
#| "moonbitlang/core/array"
#| ]
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `add` instead.")
#|#coverage.skip
#|pub fn[K : Hash + Eq] insert(self : Set[K], key : K) -> Unit {
#| self.add(key)
#|}
),
"grow_heuristic.mbt": (
#|fn calc_grow_threshold(capacity : Int) -> Int {
#| capacity * 13 / 16
#|}
),
"linked_hash_set.mbt": (
#|priv struct Entry[K] {
#| mut prev : Int
#| mut next : Entry[K]?
#| mut psl : Int
#| hash : Int
#| key : K
#|} derive(Show)
#|struct Set[K] {
#| mut entries : FixedArray[Entry[K]?]
#| mut size : Int // active keys count
#| mut capacity : Int // current capacity
#| mut capacity_mask : Int // capacity_mask = capacity - 1, used to find idx
#| mut grow_at : Int // threshold that triggers grow
#| mut head : Entry[K]? // head of linked list
#| mut tail : Int // tail of linked list
#|}
#|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),
#| head: None,
#| tail: -1,
#| }
#|}
#|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
#|}
#|pub fn[K : Hash + Eq] add(self : Set[K], key : K) -> Unit {
#| self.add_with_hash(key, key.hash())
#|}
#|fn[K : Eq] add_with_hash(self : Set[K], key : K, hash : Int) -> Unit {
#| if self.size >= self.grow_at {
#| self.grow()
#| }
#| 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 {
#| 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, hash }
#| self.add_entry_to_tail(idx, entry)
#|}
#|fn[K] push_away(self : Set[K], idx : Int, entry : Entry[K]) -> Unit {
#| for psl = entry.psl + 1, idx = (idx + 1) & self.capacity_mask, entry = entry {
#| match self.entries[idx] {
#| None => {
#| entry.psl = psl
#| self.set_entry(entry, idx)
#| break
#| }
#| Some(curr_entry) =>
#| if psl > curr_entry.psl {
#| entry.psl = psl
#| self.set_entry(entry, idx)
#| continue curr_entry.psl + 1,
#| (idx + 1) & self.capacity_mask,
#| curr_entry
#| } else {
#| continue psl + 1, (idx + 1) & self.capacity_mask, entry
#| }
#| }
#| }
#|}
#|fn[K] set_entry(self : Set[K], entry : Entry[K], new_idx : Int) -> Unit {
#| self.entries[new_idx] = Some(entry)
#| match entry.next {
#| None => self.tail = new_idx
#| Some(next) => next.prev = new_idx
#| }
#|}
#|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 (idx, psl, added) = for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries[idx] {
#| None => break (idx, psl, true)
#| Some(curr_entry) => {
#| if curr_entry.hash == hash && curr_entry.key == key {
#| break (idx, psl, false)
#| }
#| if psl > curr_entry.psl {
#| self.push_away(idx, curr_entry)
#| break (idx, psl, true)
#| }
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| }
#| }
#| if added {
#| let entry = { prev: self.tail, next: None, psl, key, hash }
#| self.add_entry_to_tail(idx, entry)
#| }
#| added
#|}
#|pub fn[K : Hash + Eq] Set::contains(self : Set[K], key : K) -> Bool {
#| 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
#| }
#|}
#|pub fn[K : Hash + Eq] remove(self : Set[K], 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
#| }
#|}
#|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 {
#| guard self.entries[idx] is Some(entry) else { break false }
#| if entry.hash == hash && entry.key == key {
#| 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
#| }
#|}
#|fn[K] add_entry_to_tail(self : Set[K], idx : Int, entry : Entry[K]) -> Unit {
#| match self.tail {
#| -1 => self.head = Some(entry)
#| tail => self.entries[tail].unwrap().next = Some(entry)
#| }
#| self.tail = idx
#| self.entries[idx] = Some(entry)
#| self.size += 1
#|}
#|fn[K] remove_entry(self : Set[K], entry : Entry[K]) -> 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
#| }
#|}
#|fn[K] shift_back(self : Set[K], 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)
#| }
#| }
#|}
#|fn[K : Eq] grow(self : Set[K]) -> 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, hash, .. }) => {
#| self.add_with_hash(key, hash)
#| continue next
#| }
#| None => break
#| }
#|}
#|pub impl[K : Show] Show for Set[K] with output(self, logger) {
#| logger.write_string("{")
#| loop (0, self.head) {
#| (_, None) => logger.write_string("}")
#| (i, Some({ key, next, .. })) => {
#| if i > 0 {
#| logger.write_string(", ")
#| }
#| logger.write_object(key)
#| continue (i + 1, next)
#| }
#| }
#|}
#|pub fn[K] size(self : Set[K]) -> Int {
#| self.size
#|}
#|pub fn[K] capacity(self : Set[K]) -> Int {
#| self.capacity
#|}
#|pub fn[K] is_empty(self : Set[K]) -> Bool {
#| self.size == 0
#|}
#|#locals(f)
#|pub fn[K] each(self : Set[K], f : (K) -> Unit raise?) -> Unit raise? {
#| loop self.head {
#| Some({ key, next, .. }) => {
#| f(key)
#| continue next
#| }
#| None => break
#| }
#|}
#|#locals(f)
#|pub fn[K] eachi(self : Set[K], f : (Int, K) -> Unit raise?) -> Unit raise? {
#| loop (0, self.head) {
#| (i, Some({ key, next, .. })) => {
#| f(i, key)
#| continue (i + 1, next)
#| }
#| (_, None) => break
#| }
#|}
#|pub fn[K] clear(self : Set[K]) -> Unit {
#| self.entries.fill(None)
#| self.size = 0
#| self.head = None
#| self.tail = -1
#|}
#|pub fn[K] iter(self : Set[K]) -> Iter[K] {
#| Iter::new(yield_ => loop self.head {
#| Some({ key, next, .. }) => {
#| guard yield_(key) is IterContinue else { break IterEnd }
#| continue next
#| }
#| None => break IterContinue
#| })
#|}
#|pub fn[K] to_array(self : Set[K]) -> Array[K] {
#| let arr = Array::new(capacity=self.size)
#| loop self.head {
#| Some({ key, next, .. }) => {
#| arr.push(key)
#| continue next
#| }
#| None => break
#| }
#| arr
#|}
#|pub impl[K : Hash + Eq] Eq for Set[K] with equal(self, other) {
#| guard self.size == other.size else { return false }
#| for k in self {
#| guard other.contains(k) else { return false }
#| } else {
#| true
#| }
#|}
#|pub fn[K : Hash + Eq] Set::of(arr : FixedArray[K]) -> Set[K] {
#| let length = arr.length()
#| let m = Set::new(capacity=length)
#| for i in 0.. Set[K] {
#| let m = Set::new()
#| for e in iter {
#| m.add(e)
#| }
#| m
#|}
#|pub impl[K] Default for Set[K] with default() {
#| Set::new()
#|}
#|pub fn[K] copy(self : Set[K]) -> Set[K] {
#| 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, .. }, idx, next) => {
#| let new_entry = { prev, next, psl, hash, key }
#| 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
#|}
#|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
#|}
#|pub fn[K : Hash + Eq] symmetric_difference(
#| self : Set[K],
#| other : Set[K],
#|) -> Set[K] {
#| let m = Set::new()
#| self.each(k => if !other.contains(k) { m.add(k) })
#| other.each(k => if !self.contains(k) { m.add(k) })
#| m
#|}
#|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
#|}
#|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
#|}
#|pub impl[X : ToJson] ToJson for Set[X] with to_json(self) {
#| let res = Array::new(capacity=self.size)
#| for v in self {
#| res.push(v.to_json())
#| }
#| Json::array(res)
#|}
#|pub fn[K : Hash + Eq] is_disjoint(self : Set[K], other : Set[K]) -> Bool {
#| if self.size() <= other.size() {
#| for k in self {
#| if other.contains(k) {
#| return false
#| }
#| }
#| } else {
#| for k in other {
#| if self.contains(k) {
#| return false
#| }
#| }
#| }
#| true
#|}
#|pub fn[K : Hash + Eq] is_subset(self : Set[K], other : Set[K]) -> Bool {
#| if self.size() <= other.size() {
#| for k in self {
#| if !other.contains(k) {
#| return false
#| }
#| }
#| true
#| } else {
#| false
#| }
#|}
#|pub fn[K : Hash + Eq] is_superset(self : Set[K], other : Set[K]) -> Bool {
#| other.is_subset(self)
#|}
#|pub impl[K : Hash + Eq] BitAnd for Set[K] with land(self, other) {
#| self.intersection(other)
#|}
#|pub impl[K : Hash + Eq] BitOr for Set[K] with lor(self, other) {
#| self.union(other)
#|}
#|pub impl[K : Hash + Eq] BitXOr for Set[K] with lxor(self, other) {
#| self.symmetric_difference(other)
#|}
#|pub impl[K : Hash + Eq] Sub for Set[K] with sub(self, other) {
#| self.difference(other)
#|}
#|pub fnalias Set::(new, from_array, from_iter, of)
),
},
)
///|
let moonbitlang_core_sorted_map_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/option",
#| "moonbitlang/core/tuple",
#| "moonbitlang/core/quickcheck"
#| ],
#| "test-import": ["moonbitlang/core/array"]
#|}
),
"deprecated.mbt": (
#|#deprecated("Use @sorted_map.from_array instead")
#|pub fn[K : Compare, V] of(entries : Array[(K, V)]) -> SortedMap[K, V] {
#| let map = { root: None, size: 0 }
#| entries.each(e => map.add(e.0, e.1))
#| map
#|}
#|#deprecated("Use `keys_as_iter` instead. `keys` will return `Iter[K]` instead of `Array[K]` in the future.")
#|#coverage.skip
#|pub fn[K, V] keys(self : SortedMap[K, V]) -> Array[K] {
#| let keys = Array::new(capacity=self.size)
#| self.each(fn(k, _v) { keys.push(k) })
#| keys
#|}
#|#deprecated("Use `values_as_iter` instead. `values` will return `Iter[V]` instead of `Array[V]` in the future.")
#|#coverage.skip
#|pub fn[K, V] values(self : SortedMap[K, V]) -> Array[V] {
#| let values = Array::new(capacity=self.size)
#| self.each(fn(_k, v) { values.push(v) })
#| values
#|}
),
"map.mbt": (
#|pub fn[K : Compare, V] op_set(
#| self : SortedMap[K, V],
#| key : K,
#| value : V,
#|) -> Unit {
#| self.add(key, value)
#|}
#|pub impl[K : Eq, V : Eq] Eq for SortedMap[K, V] with equal(self, other) {
#| self.to_array() == other.to_array()
#|}
#|pub fn[K, V] new() -> SortedMap[K, V] {
#| { root: None, size: 0 }
#|}
#|pub fn[K : Compare, V] from_array(entries : Array[(K, V)]) -> SortedMap[K, V] {
#| let map = { root: None, size: 0 }
#| entries.each(e => map.add(e.0, e.1))
#| map
#|}
#|pub fn[K : Compare, V] add(self : SortedMap[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
#| }
#|}
#|pub fn[K : Compare, V] remove(self : SortedMap[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
#| }
#| }
#|}
#|pub fn[K : Compare, V] get(self : SortedMap[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
#| }
#|}
#|pub fn[K : Compare, V] op_get(self : SortedMap[K, V], key : K) -> V {
#| loop self.root {
#| Some(node) => {
#| let cmp = key.compare(node.key)
#| if cmp == 0 {
#| break node.value
#| } else if cmp > 0 {
#| continue node.right
#| } else {
#| continue node.left
#| }
#| }
#| None => panic()
#| }
#|}
#|pub fn[K : Compare, V] contains(self : SortedMap[K, V], key : K) -> Bool {
#| match self.get(key) {
#| Some(_) => true
#| None => false
#| }
#|}
#|pub fn[K, V] is_empty(self : SortedMap[K, V]) -> Bool {
#| self.size == 0
#|}
#|pub fn[K, V] size(self : SortedMap[K, V]) -> Int {
#| self.size
#|}
#|pub fn[K, V] clear(self : SortedMap[K, V]) -> Unit {
#| self.root = None
#| self.size = 0
#|}
#|pub fn[K, V] each(
#| self : SortedMap[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)
#|}
#|pub fn[K, V] eachi(
#| self : SortedMap[K, V],
#| f : (Int, K, V) -> Unit raise?,
#|) -> Unit raise? {
#| let mut i = 0
#| self.each((k, v) => {
#| f(i, k, v)
#| i = i + 1
#| })
#|}
#|pub fn[K, V] keys_as_iter(self : SortedMap[K, V]) -> Iter[K] {
#| Iter::new(fn(yield_) {
#| fn go(x : Node[K, V]?) {
#| match x {
#| None => IterContinue
#| Some({ left, right, key, .. }) =>
#| if go(left) is IterEnd {
#| IterEnd
#| } else if yield_(key) is IterEnd {
#| IterEnd
#| } else {
#| go(right)
#| }
#| }
#| }
#| go(self.root)
#| })
#|}
#|pub fn[K, V] values_as_iter(self : SortedMap[K, V]) -> Iter[V] {
#| Iter::new(fn(yield_) {
#| fn go(x : Node[K, 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)
#| })
#|}
#|pub fn[K, V] to_array(self : SortedMap[K, V]) -> Array[(K, V)] {
#| let arr = Array::new(capacity=self.size)
#| self.each((k, v) => arr.push((k, v)))
#| arr
#|}
#|pub fn[K, V] iter(self : SortedMap[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)
#| })
#|}
#|pub fn[K, V] iter2(self : SortedMap[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)
#| })
#|}
#|pub fn[K : Compare, V] from_iter(iter : Iter[(K, V)]) -> SortedMap[K, V] {
#| let m = new()
#| iter.each(e => m[e.0] = e.1)
#| m
#|}
#|pub impl[K : @quickcheck.Arbitrary + Compare, V : @quickcheck.Arbitrary] @quickcheck.Arbitrary for SortedMap[
#| K,
#| V,
#|] with arbitrary(size, rs) {
#| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_iter
#|}
#|pub fn[K : Compare, V] range(
#| self : SortedMap[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)
#| })
#|}
#|fn[K : Compare, V] replace_root_with_min(
#| root : Node[K, V],
#| node : Node[K, V],
#|) -> Node[K, V]? {
#| let (l, r) = (node.left, node.right)
#| match l {
#| None => {
#| root.key = node.key
#| root.value = node.value
#| r
#| }
#| Some(ln) => {
#| node.left = replace_root_with_min(root, ln)
#| Some(balance(node))
#| }
#| }
#|}
#|fn[K, V] update_height(self : Node[K, V]) -> Unit {
#| self.height = 1 + max(height(self.left), height(self.right))
#|}
#|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
#| }
#| }
#|}
#|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
#|}
#|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
#|}
#|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
#|}
#|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)
#|}
#|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)
#|}
#|fn[K : Compare, V] add_node(
#| root : Node[K, V]?,
#| key : K,
#| value : V,
#|) -> (Node[K, V]?, Bool) {
#| match root {
#| None => (Some(new_node(key, value)), true)
#| Some(n) =>
#| if key == n.key {
#| n.value = value
#| (Some(n), false)
#| } else {
#| let (l, r) = (n.left, n.right)
#| if key < n.key {
#| let (nl, inserted) = add_node(l, key, value)
#| n.left = nl
#| (Some(balance(n)), inserted)
#| } else {
#| let (nr, inserted) = add_node(r, key, value)
#| n.right = nr
#| (Some(balance(n)), inserted)
#| }
#| }
#| }
#|}
#|fn[K : Compare, V] delete_node(
#| root : Node[K, V],
#| key : K,
#|) -> (Node[K, V]?, Bool) {
#| if key == root.key {
#| 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 key < root.key {
#| match root.left {
#| None => (Some(root), false)
#| Some(l) => {
#| let (nl, deleted) = delete_node(l, key)
#| root.left = nl
#| (Some(balance(root)), deleted)
#| }
#| }
#| } else {
#| match root.right {
#| None => (Some(root), false)
#| Some(r) => {
#| let (nr, deleted) = delete_node(r, key)
#| root.right = nr
#| (Some(balance(root)), deleted)
#| }
#| }
#| }
#|}
#|test "new" {
#| let map : SortedMap[Int, String] = new()
#| inspect(map.debug_tree(), content="_")
#| inspect(map.size(), content="0")
#|}
#|test "of" {
#| let map = from_array([(3, "c"), (2, "b"), (1, "a")])
#| inspect(map.debug_tree(), content="([2]2,b,([1]1,a,_,_),([1]3,c,_,_))")
#| inspect(map.size(), content="3")
#|}
#|test "add1" {
#| let map = new()
#| map.add(6, "a")
#| map.add(5, "b")
#| map.add(4, "c")
#| map.add(3, "d")
#| map.add(2, "e")
#| map.add(1, "f")
#| inspect(
#| map.debug_tree(),
#| content="([3]3,d,([2]2,e,([1]1,f,_,_),_),([2]5,b,([1]4,c,_,_),([1]6,a,_,_)))",
#| )
#| inspect(map.size(), content="6")
#|}
#|test "add2" {
#| let map = new()
#| map.add(1, "a")
#| map.add(2, "b")
#| map.add(3, "c")
#| map.add(4, "d")
#| map.add(5, "e")
#| map.add(6, "f")
#| inspect(
#| map.debug_tree(),
#| content="([3]4,d,([2]2,b,([1]1,a,_,_),([1]3,c,_,_)),([2]5,e,_,([1]6,f,_,_)))",
#| )
#| inspect(map.size(), content="6")
#|}
#|test "add3" {
#| let map = new()
#| map.add(4, "a")
#| map.add(1, "b")
#| map.add(3, "c")
#| map.add(2, "d")
#| inspect(
#| map.debug_tree(),
#| content="([3]3,c,([2]1,b,_,([1]2,d,_,_)),([1]4,a,_,_))",
#| )
#|}
#|test "add4" {
#| let map = new()
#| map.add(1, "a")
#| map.add(4, "b")
#| map.add(2, "c")
#| map.add(3, "d")
#| inspect(
#| map.debug_tree(),
#| content="([3]2,c,([1]1,a,_,_),([2]4,b,([1]3,d,_,_),_))",
#| )
#|}
#|test "add duplicate key" {
#| let map = from_array([(3, "c"), (2, "b"), (1, "a")])
#| inspect(map.debug_tree(), content="([2]2,b,([1]1,a,_,_),([1]3,c,_,_))")
#| map.add(1, "x")
#| inspect(map.debug_tree(), content="([2]2,b,([1]1,x,_,_),([1]3,c,_,_))")
#|}
#|test "remove" {
#| let map = from_array([
#| (1, "a"),
#| (2, "b"),
#| (3, "c"),
#| (4, "d"),
#| (5, "e"),
#| (6, "f"),
#| (7, "g"),
#| (8, "h"),
#| ])
#| inspect(
#| map.debug_tree(),
#| content="([4]4,d,([2]2,b,([1]1,a,_,_),([1]3,c,_,_)),([3]6,f,([1]5,e,_,_),([2]7,g,_,([1]8,h,_,_))))",
#| )
#| inspect(map.size(), content="8")
#| map.remove(6)
#| inspect(
#| map.debug_tree(),
#| content="([3]4,d,([2]2,b,([1]1,a,_,_),([1]3,c,_,_)),([2]7,g,([1]5,e,_,_),([1]8,h,_,_)))",
#| )
#| inspect(map.size(), content="7")
#| map.remove(4)
#| inspect(
#| map.debug_tree(),
#| content="([3]5,e,([2]2,b,([1]1,a,_,_),([1]3,c,_,_)),([2]7,g,_,([1]8,h,_,_)))",
#| )
#| inspect(map.size(), content="6")
#| map.remove(2)
#| inspect(
#| map.debug_tree(),
#| content="([3]5,e,([2]3,c,([1]1,a,_,_),_),([2]7,g,_,([1]8,h,_,_)))",
#| )
#| inspect(map.size(), content="5")
#| map.remove(3)
#| inspect(
#| map.debug_tree(),
#| content="([3]5,e,([1]1,a,_,_),([2]7,g,_,([1]8,h,_,_)))",
#| )
#| inspect(map.size(), content="4")
#| map.remove(5)
#| inspect(map.debug_tree(), content="([2]7,g,([1]1,a,_,_),([1]8,h,_,_))")
#| inspect(map.size(), content="3")
#| map.remove(7)
#| inspect(map.debug_tree(), content="([2]8,h,([1]1,a,_,_),_)")
#| inspect(map.size(), content="2")
#| map.remove(8)
#| inspect(map.debug_tree(), content="([1]1,a,_,_)")
#| inspect(map.size(), content="1")
#| map.remove(1)
#| inspect(map.debug_tree(), content="_")
#| inspect(map.size, content="0")
#|}
#|test "op_set" {
#| let map = new()
#| map[1] = "a"
#| map[2] = "b"
#| map[3] = "c"
#| inspect(map.debug_tree(), content="([2]2,b,([1]1,a,_,_),([1]3,c,_,_))")
#|}
#|test "clear" {
#| let map = from_array([(3, "c"), (2, "b"), (1, "a")])
#| map.clear()
#| inspect(map.debug_tree(), content="_")
#| inspect(map.size(), content="0")
#|}
#|pub impl[K, V] Default for SortedMap[K, V] with default() {
#| new()
#|}
),
"types.mbt": (
#|priv struct Node[K, V] {
#| mut key : K
#| mut value : V
#| mut left : Node[K, V]?
#| mut right : Node[K, V]?
#| mut height : Int
#|}
#|struct SortedMap[K, V] {
#| mut root : Node[K, V]?
#| mut size : Int
#|}
#|#deprecated("Use `SortedMap` instead of `T`")
#|pub typealias SortedMap as T
),
"utils.mbt": (
#|fn[K, V] new_node(key : K, value : V) -> Node[K, V] {
#| { key, value, left: None, right: None, height: 1 }
#|}
#|impl[K : Eq, V] Eq for Node[K, V] with equal(self, other) {
#| self.key == other.key
#|}
#|fn max(x : Int, y : Int) -> Int {
#| if x > y {
#| x
#| } else {
#| y
#| }
#|}
#|fn[K, V] height(node : Node[K, V]?) -> Int {
#| match node {
#| None => 0
#| Some(n) => n.height
#| }
#|}
#|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})"
#|}
#|fn[K : Show, V : Show] debug_tree(self : SortedMap[K, V]) -> String {
#| match self.root {
#| Some(root) => root.debug_node()
#| None => "_"
#| }
#|}
#|pub impl[K : Show, V : Show] Show for SortedMap[K, V] with output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@sorted_map.of([", suffix="])")
#|}
),
},
)
///|
let moonbitlang_core_sorted_set_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin", "moonbitlang/core/option", "moonbitlang/core/quickcheck"],
#| "test-import": ["moonbitlang/core/array"]
#|}
),
"deprecated.mbt": (
#|#deprecated("use `@sorted_set.from_iter` instead")
#|#coverage.skip
#|pub fn[V : Compare] SortedSet::from_iter(iter : Iter[V]) -> SortedSet[V] {
#| from_iter(iter)
#|}
#|#deprecated("Use @sorted_set.from_array instead")
#|pub fn[V : Compare] of(array : Array[V]) -> SortedSet[V] {
#| let set = new()
#| for i in 0.. SortedSet[V] {
#| self.copy()
#|}
#|#deprecated("Use `difference` instead")
#|#coverage.skip
#|pub fn[V : Compare] diff(
#| self : SortedSet[V],
#| src : SortedSet[V],
#|) -> SortedSet[V] {
#| let ret = new()
#| self.each(x => if !src.contains(x) { ret.add(x) })
#| ret
#|}
#|#deprecated("Use `intersection` instead")
#|#coverage.skip
#|pub fn[V : Compare] intersect(
#| self : SortedSet[V],
#| src : SortedSet[V],
#|) -> SortedSet[V] {
#| self.intersection(src)
#|}
),
"set.mbt": (
#|pub fn[V] new() -> SortedSet[V] {
#| { root: None, size: 0 }
#|}
#|pub fn[V] singleton(value : V) -> SortedSet[V] {
#| { root: Some({ value, left: None, right: None, height: 1 }), size: 1 }
#|}
#|pub fn[V : Compare] from_array(array : Array[V]) -> SortedSet[V] {
#| let set = new()
#| for i in 0.. SortedSet[V] {
#| match self.root {
#| None => new()
#| Some(_) => { root: copy_tree(self.root), size: self.size }
#| }
#|}
#|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)
#| }
#| }
#|}
#|fn[V] new_node(
#| value : V,
#| left? : Node[V]? = None,
#| right? : Node[V]? = None,
#| height? : Int = 1,
#|) -> Node[V] {
#| { value, left, right, height }
#|}
#|fn[V] new_node_update_height(
#| value : V,
#| left~ : Node[V]?,
#| right~ : Node[V]?,
#|) -> Node[V] {
#| { value, left, right, height: max(height(left), height(right)) + 1 }
#|}
#|pub fn[V : Compare] add(self : SortedSet[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
#| }
#|}
#|pub fn[V : Compare] remove(self : SortedSet[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
#| }
#| }
#|}
#|pub fn[V : Compare] contains(self : SortedSet[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)
#| }
#| }
#| }
#|}
#|pub fn[V : Compare] union(
#| self : SortedSet[V],
#| src : SortedSet[V],
#|) -> SortedSet[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 }
#| 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()
#| }
#|}
#|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)
#| }
#| }
#| }
#|}
#|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~)
#| }
#|}
#|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
#|}
#|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
#|}
#|pub fn[V : Compare] difference(
#| self : SortedSet[V],
#| src : SortedSet[V],
#|) -> SortedSet[V] {
#| let ret = new()
#| self.each(x => if !src.contains(x) { ret.add(x) })
#| ret
#|}
#|pub fn[V : Compare] symmetric_difference(
#| self : SortedSet[V],
#| other : SortedSet[V],
#|) -> SortedSet[V] {
#| let set1 = self.difference(other)
#| let set2 = other.difference(self)
#| set1.union(set2)
#|}
#|pub fn[V : Compare] intersection(
#| self : SortedSet[V],
#| src : SortedSet[V],
#|) -> SortedSet[V] {
#| let ret = new()
#| self.each(x => if src.contains(x) { ret.add(x) })
#| ret
#|}
#|pub fn[V : Compare] subset(self : SortedSet[V], src : SortedSet[V]) -> Bool {
#| let mut ret = true
#| self.each(x => if !src.contains(x) { ret = false })
#| ret
#|}
#|pub fn[V : Compare] disjoint(self : SortedSet[V], src : SortedSet[V]) -> Bool {
#| let mut ret = true
#| self.each(x => if src.contains(x) { ret = false })
#| ret
#|}
#|pub impl[V : Eq] Eq for SortedSet[V] with equal(self, other) {
#| self.to_array() == other.to_array()
#|}
#|pub fn[V] is_empty(self : SortedSet[V]) -> Bool {
#| self.root is None
#|}
#|pub fn[V] size(self : SortedSet[V]) -> Int {
#| self.size
#|}
#|pub fn[V] each(self : SortedSet[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)
#|}
#|pub fn[V] eachi(
#| self : SortedSet[V],
#| f : (Int, V) -> Unit raise?,
#|) -> Unit raise? {
#| let mut i = 0
#| self.each(v => {
#| f(i, v)
#| i = i + 1
#| })
#|}
#|pub fn[V] to_array(self : SortedSet[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
#| }
#|}
#|pub fn[V] iter(self : SortedSet[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)
#| })
#|}
#|pub fn[V : Compare] from_iter(iter : Iter[V]) -> SortedSet[V] {
#| let s = new()
#| iter.each(e => s.add(e))
#| s
#|}
#|pub impl[V : Show] Show for SortedSet[V] with output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@sorted_set.from_array([", suffix="])")
#|}
#|pub impl[X : @quickcheck.Arbitrary + Compare] @quickcheck.Arbitrary for SortedSet[
#| X,
#|] with arbitrary(size, rs) {
#| @quickcheck.Arbitrary::arbitrary(size, rs) |> from_iter
#|}
#|impl[T : Show] Show for Node[T] with output(self, logger) {
#| let x = { root: Some(self), size: 0 } // Hack for test
#| logger.write_iter(x.iter())
#|}
#|pub fn[V : Compare] range(self : SortedSet[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)
#| })
#|}
#|fn[V : Compare] replace_root_with_min(
#| root : Node[V],
#| node : Node[V],
#|) -> Node[V]? {
#| let (l, r) = (node.left, node.right)
#| match l {
#| None => {
#| root.value = node.value
#| r
#| }
#| Some(ln) => {
#| node.left = replace_root_with_min(root, ln)
#| Some(balance(node))
#| }
#| }
#|}
#|fn[V] update_height(self : Node[V]) -> Unit {
#| self.height = 1 + max(height(self.left), height(self.right))
#|}
#|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
#| }
#| }
#|}
#|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
#|}
#|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
#|}
#|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
#|}
#|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)
#|}
#|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)
#|}
#|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)
#| }
#| }
#| }
#| }
#|}
#|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)
#| }
#| }
#| }
#|}
#|test "copy" {
#| let set = from_array([1, 2, 3, 4, 5])
#| let copied_set = set.copy()
#| inspect(copied_set, content="@sorted_set.from_array([1, 2, 3, 4, 5])")
#| inspect(set.debug_tree() == copied_set.debug_tree(), content="true")
#| let set : SortedSet[Int] = from_array([])
#| let copied_set = set.copy()
#| inspect(copied_set, content="@sorted_set.from_array([])")
#| inspect(set.debug_tree() == copied_set.debug_tree(), content="true")
#|}
#|test "union" {
#| let set1 = from_array([1, 2, 3])
#| let set2 = from_array([4, 5, 6])
#| let set3 = set1.union(set2)
#| inspect(set3, content="@sorted_set.from_array([1, 2, 3, 4, 5, 6])")
#| inspect(
#| set3.debug_tree(),
#| content="([3]3,([2]2,([1]1,_,_),_),([2]5,([1]4,_,_),([1]6,_,_)))",
#| )
#| let set1 = from_array([1, 2, 3])
#| let set2 = from_array([2, 3, 4])
#| let set3 = set1.union(set2)
#| inspect(set3, content="@sorted_set.from_array([1, 2, 3, 4])")
#| inspect(set3.debug_tree(), content="([3]2,([1]1,_,_),([2]3,_,([1]4,_,_)))")
#| let set1 = from_array([1, 2, 3])
#| let set2 = from_array([2, 3])
#| let set3 = set1.union(set2)
#| inspect(set3, content="@sorted_set.from_array([1, 2, 3])")
#| inspect(set3.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))")
#| let set1 : SortedSet[Int] = new()
#| let set2 = new()
#| let set3 = set1.union(set2)
#| inspect(set3, content="@sorted_set.from_array([])")
#| inspect(set3.debug_tree(), content="_")
#| let set1 = from_array([1, 2, 3])
#| let set2 = from_array([])
#| let set3 = set1.union(set2)
#| inspect(set3, content="@sorted_set.from_array([1, 2, 3])")
#| inspect(set3.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))")
#| let set1 = from_array([])
#| let set2 = from_array([1, 2, 3])
#| let set3 = set1.union(set2)
#| inspect(set3, content="@sorted_set.from_array([1, 2, 3])")
#| inspect(set3.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))")
#| let set1 = from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
#| let set2 = from_array([11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
#| let set3 = set1.union(set2)
#| inspect(
#| set3,
#| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])",
#| )
#| inspect(
#| set3.debug_tree(),
#| content="([5]14,([4]8,([3]4,([2]2,([1]1,_,_),([1]3,_,_)),([2]6,([1]5,_,_),([1]7,_,_))),([3]12,([2]10,([1]9,_,_),([1]11,_,_)),([1]13,_,_))),([3]18,([2]16,([1]15,_,_),([1]17,_,_)),([2]19,_,([1]20,_,_))))",
#| )
#| let set1 = from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
#| let set2 = from_array([6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
#| let set3 = set1.union(set2)
#| inspect(
#| set3,
#| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])",
#| )
#| inspect(
#| set3.debug_tree(),
#| content="([5]11,([4]4,([2]2,([1]1,_,_),([1]3,_,_)),([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]9,_,([1]10,_,_)))),([3]13,([1]12,_,_),([2]14,_,([1]15,_,_))))",
#| )
#| let set1 = from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
#| let set2 = from_array([6, 7, 8, 9, 10])
#| let set3 = set1.union(set2)
#| inspect(
#| set3,
#| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])",
#| )
#| inspect(
#| set3.debug_tree(),
#| content="([4]4,([2]2,([1]1,_,_),([1]3,_,_)),([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]9,_,([1]10,_,_))))",
#| )
#|}
#|test "split" {
#| let (l, r) = split(from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root, 5)
#| inspect(l, content="Some([1, 2, 3, 4])")
#| inspect(r, content="Some([6, 7, 8, 9])")
#| let (l, r) = split(from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root, 0)
#| inspect(l, content="None")
#| inspect(r, content="Some([1, 2, 3, 4, 5, 6, 7, 8, 9])")
#| let (l, r) = split(from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root, 10)
#| inspect(l, content="Some([1, 2, 3, 4, 5, 6, 7, 8, 9])")
#| inspect(r, content="None")
#| let (l, r) = split(from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root, 4)
#| inspect(l, content="Some([1, 2, 3])")
#| inspect(r, content="Some([5, 6, 7, 8, 9])")
#| let (l, r) = split(from_array([]).root, 7)
#| inspect(l, content="None")
#| inspect(r, content="None")
#| let (l, r) = split(
#| from_array([
#| 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
#| 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
#| 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
#| 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
#| 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
#| 98, 99, 100,
#| ]).root,
#| 50,
#| )
#| inspect(
#| l,
#| content="Some([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49])",
#| )
#| inspect(
#| r,
#| content="Some([51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100])",
#| )
#|}
#|test "join" {
#| let l = from_array([13, 8, 17, 1, 11, 15, 25, 6])
#| let r = from_array([27, 28, 40, 35, 33])
#| inspect(
#| join(l.root, 26, r.root),
#| content="[1, 6, 8, 11, 13, 15, 17, 25, 26, 27, 28, 33, 35, 40]",
#| )
#| let l = from_array([3, 2, 5, 1, 4])
#| let r = from_array([7])
#| inspect(join(l.root, 6, r.root), content="[1, 2, 3, 4, 5, 6, 7]")
#| let l = from_array([3, 2, 5, 1, 4])
#| let r = from_array([])
#| inspect(join(l.root, 6, r.root), content="[1, 2, 3, 4, 5, 6]")
#| let l = from_array([])
#| let r = from_array([])
#| inspect(join(l.root, 6, r.root), content="[6]")
#| let l = from_array([])
#| let r = from_array([7, 8, 9, 10, 11, 12])
#| inspect(join(l.root, 6, r.root), content="[6, 7, 8, 9, 10, 11, 12]")
#|}
#|test "add to empty set" {
#| let set = new()
#| set.add(1)
#| assert_eq(set.contains(1), true)
#| inspect(set.debug_tree(), content="([1]1,_,_)")
#|}
#|test "add to non-empty set" {
#| let set = new()
#| set.add(1)
#| set.add(2)
#| assert_eq(set.contains(1), true)
#| assert_eq(set.contains(2), true)
#| inspect(set.debug_tree(), content="([2]1,_,([1]2,_,_))")
#|}
#|test "add duplicate value" {
#| let set = new()
#| set.add(1)
#| set.add(1)
#| assert_eq(set.contains(1), true)
#| assert_eq(set.size(), 1)
#| inspect(set.debug_tree(), content="([1]1,_,_)")
#|}
#|test "add multiple values" {
#| let set = new()
#| set.add(1)
#| set.add(2)
#| set.add(3)
#| assert_eq(set.contains(1), true)
#| assert_eq(set.contains(2), true)
#| assert_eq(set.contains(3), true)
#| assert_eq(set.size(), 3)
#| inspect(set.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))")
#|}
#|test "add_and_remove" {
#| let set = from_array([7, 2, 9, 4, 5, 6, 3, 8, 1])
#| set.remove(8)
#| inspect(set, content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 9])")
#| inspect(
#| set.debug_tree(),
#| content="([4]5,([3]3,([2]2,([1]1,_,_),_),([1]4,_,_)),([2]7,([1]6,_,_),([1]9,_,_)))",
#| )
#| let set = from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
#| set.remove(1)
#| inspect(set, content="@sorted_set.from_array([2, 3, 4, 5, 6, 7, 8, 9, 10])")
#| inspect(
#| set.debug_tree(),
#| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]9,_,([1]10,_,_))))",
#| )
#| set.remove(5)
#| inspect(set, content="@sorted_set.from_array([2, 3, 4, 6, 7, 8, 9, 10])")
#| inspect(
#| set.debug_tree(),
#| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,_,([1]7,_,_)),([2]9,_,([1]10,_,_))))",
#| )
#| set.remove(10)
#| inspect(set, content="@sorted_set.from_array([2, 3, 4, 6, 7, 8, 9])")
#| inspect(
#| set.debug_tree(),
#| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,_,([1]7,_,_)),([1]9,_,_)))",
#| )
#| set.remove(4)
#| inspect(set, content="@sorted_set.from_array([2, 3, 6, 7, 8, 9])")
#| inspect(
#| set.debug_tree(),
#| content="([3]6,([2]2,_,([1]3,_,_)),([2]8,([1]7,_,_),([1]9,_,_)))",
#| )
#| set.add(1)
#| inspect(set, content="@sorted_set.from_array([1, 2, 3, 6, 7, 8, 9])")
#| inspect(
#| set.debug_tree(),
#| content="([3]6,([2]2,([1]1,_,_),([1]3,_,_)),([2]8,([1]7,_,_),([1]9,_,_)))",
#| )
#| set.add(5)
#| inspect(set, content="@sorted_set.from_array([1, 2, 3, 5, 6, 7, 8, 9])")
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([3]2,([1]1,_,_),([2]3,_,([1]5,_,_))),([2]8,([1]7,_,_),([1]9,_,_)))",
#| )
#| set.add(10)
#| inspect(set, content="@sorted_set.from_array([1, 2, 3, 5, 6, 7, 8, 9, 10])")
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([3]2,([1]1,_,_),([2]3,_,([1]5,_,_))),([3]8,([1]7,_,_),([2]9,_,([1]10,_,_))))",
#| )
#| set.add(4)
#| inspect(
#| set,
#| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])",
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([3]2,([1]1,_,_),([2]4,([1]3,_,_),([1]5,_,_))),([3]8,([1]7,_,_),([2]9,_,([1]10,_,_))))",
#| )
#| set.add(11)
#| inspect(
#| set,
#| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])",
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([3]2,([1]1,_,_),([2]4,([1]3,_,_),([1]5,_,_))),([3]8,([1]7,_,_),([2]10,([1]9,_,_),([1]11,_,_))))",
#| )
#| set.remove(11)
#| inspect(
#| set,
#| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])",
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([3]2,([1]1,_,_),([2]4,([1]3,_,_),([1]5,_,_))),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))",
#| )
#| set.remove(12)
#| inspect(
#| set,
#| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])",
#| )
#| set.add(10)
#| inspect(
#| set,
#| content="@sorted_set.from_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])",
#| )
#| set.remove(1)
#| inspect(set, content="@sorted_set.from_array([2, 3, 4, 5, 6, 7, 8, 9, 10])")
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([3]4,([2]2,_,([1]3,_,_)),([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))",
#| )
#| set.remove(2)
#| inspect(set, content="@sorted_set.from_array([3, 4, 5, 6, 7, 8, 9, 10])")
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([2]4,([1]3,_,_),([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))",
#| )
#| set.remove(3)
#| inspect(set, content="@sorted_set.from_array([4, 5, 6, 7, 8, 9, 10])")
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([2]4,_,([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))",
#| )
#| set.remove(4)
#| inspect(set, content="@sorted_set.from_array([5, 6, 7, 8, 9, 10])")
#| inspect(
#| set.debug_tree(),
#| content="([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]10,([1]9,_,_),_))",
#| )
#| set.remove(5)
#| inspect(set, content="@sorted_set.from_array([6, 7, 8, 9, 10])")
#| inspect(
#| set.debug_tree(),
#| content="([3]8,([2]6,_,([1]7,_,_)),([2]10,([1]9,_,_),_))",
#| )
#| set.remove(6)
#| inspect(set, content="@sorted_set.from_array([7, 8, 9, 10])")
#| inspect(set.debug_tree(), content="([3]8,([1]7,_,_),([2]10,([1]9,_,_),_))")
#| set.remove(7)
#| inspect(set, content="@sorted_set.from_array([8, 9, 10])")
#| inspect(set.debug_tree(), content="([2]9,([1]8,_,_),([1]10,_,_))")
#| set.remove(8)
#| inspect(set, content="@sorted_set.from_array([9, 10])")
#| inspect(set.debug_tree(), content="([2]9,_,([1]10,_,_))")
#| set.remove(9)
#| inspect(set, content="@sorted_set.from_array([10])")
#| inspect(set.debug_tree(), content="([1]10,_,_)")
#| set.remove(10)
#| inspect(set, content="@sorted_set.from_array([])")
#| inspect(set.debug_tree(), content="_")
#| let set = from_array([7, 2, 9, 4, 5, 6, 3, 1])
#| set.remove(3)
#| inspect(set, content="@sorted_set.from_array([1, 2, 4, 5, 6, 7, 9])")
#| inspect(
#| set.debug_tree(),
#| content="([3]5,([2]2,([1]1,_,_),([1]4,_,_)),([2]7,([1]6,_,_),([1]9,_,_)))",
#| )
#| set.remove(2)
#| inspect(set, content="@sorted_set.from_array([1, 4, 5, 6, 7, 9])")
#| inspect(
#| set.debug_tree(),
#| content="([3]5,([2]4,([1]1,_,_),_),([2]7,([1]6,_,_),([1]9,_,_)))",
#| )
#| set.remove(5)
#| inspect(set, content="@sorted_set.from_array([1, 4, 6, 7, 9])")
#| inspect(
#| set.debug_tree(),
#| content="([3]6,([2]4,([1]1,_,_),_),([2]7,_,([1]9,_,_)))",
#| )
#| set.remove(9)
#| inspect(set, content="@sorted_set.from_array([1, 4, 6, 7])")
#| inspect(set.debug_tree(), content="([3]6,([2]4,([1]1,_,_),_),([1]7,_,_))")
#| set.remove(1)
#| inspect(set, content="@sorted_set.from_array([4, 6, 7])")
#| inspect(set.debug_tree(), content="([2]6,([1]4,_,_),([1]7,_,_))")
#| set.remove(7)
#| inspect(set, content="@sorted_set.from_array([4, 6])")
#| inspect(set.debug_tree(), content="([2]6,([1]4,_,_),_)")
#| set.remove(4)
#| inspect(set, content="@sorted_set.from_array([6])")
#| inspect(set.debug_tree(), content="([1]6,_,_)")
#| set.remove(6)
#| inspect(set, content="@sorted_set.from_array([])")
#| inspect(set.debug_tree(), content="_")
#|}
#|pub impl[K] Default for SortedSet[K] with default() {
#| new()
#|}
),
"types.mbt": (
#|struct SortedSet[V] {
#| mut root : Node[V]?
#| mut size : Int
#|}
#|priv struct Node[V] {
#| mut value : V
#| mut left : Node[V]?
#| mut right : Node[V]?
#| mut height : Int
#|}
#|#deprecated("Use `SortedSet` instead of `T`")
#|pub typealias SortedSet as T
),
"utils.mbt": (
#|impl[V : Eq] Eq for Node[V] with equal(self, other) {
#| self.value == other.value
#|}
#|fn max(x : Int, y : Int) -> Int {
#| if x > y {
#| x
#| } else {
#| y
#| }
#|}
#|fn[V] height(node : Node[V]?) -> Int {
#| match node {
#| None => 0
#| Some(n) => n.height
#| }
#|}
#|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})"
#|}
#|fn[V : Show] debug_tree(self : SortedSet[V]) -> String {
#| match self.root {
#| Some(root) => root.debug_node()
#| None => "_"
#| }
#|}
),
},
)
///|
let moonbitlang_core_strconv_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/double",
#| "moonbitlang/core/uint64",
#| "moonbitlang/core/string",
#| "moonbitlang/core/char"
#| ]
#|}
),
"bool.mbt": (
#|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()
#| }
#|}
#|test "parse_bool" {
#| let tests : Array[(String, Result[Bool, String])] = [
#| ("", Err(syntax_err_str)),
#| ("zutomayo", Err(syntax_err_str)),
#| ("0", Ok(false)),
#| ("f", Ok(false)),
#| ("F", Ok(false)),
#| ("FALSE", Ok(false)),
#| ("false", Ok(false)),
#| ("False", Ok(false)),
#| ("1", Ok(true)),
#| ("t", Ok(true)),
#| ("T", Ok(true)),
#| ("TRUE", Ok(true)),
#| ("true", Ok(true)),
#| ("True", Ok(true)),
#| ]
#| for i in 0.. Err(err)
#| },
#| t.1,
#| )
#| }
#|}
),
"decimal.mbt": (
#|let max_shift = 59
#|let powtab = [
#| 1, 3, 6, 9, 13, 16, 19, 23, 26, 29, 33, 36, 39, 43, 46, 49, 53, 56, 59,
#|]
#|fn Decimal::new_priv() -> Decimal {
#| {
#| digits: FixedArray::make(800, Byte::default()),
#| digits_num: 0,
#| decimal_point: 0,
#| negative: false,
#| truncated: false,
#| }
#|}
#|fn Decimal::from_int64_priv(v : Int64) -> Decimal {
#| let d = Decimal::new_priv()
#| d.assign(v)
#| d
#|}
#|fn parse_decimal_priv(str : @string.View) -> Decimal raise StrConvError {
#| parse_decimal_from_view(str)
#|}
#|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
#| let rest = match str {
#| ['-', .. rest] => {
#| d.negative = true
#| rest
#| }
#| ['+', .. rest] => rest
#| _ => str
#| }
#| 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 {
#| 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
#| }
#| 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
#| }
#| guard rest is [] else { syntax_err() }
#| d.trim()
#| d
#|}
#|fn to_double_priv(self : Decimal) -> Double raise StrConvError {
#| let mut exponent = 0
#| let mut mantissa = 0L
#| if self.digits_num == 0 || self.decimal_point < -330 {
#| mantissa = 0
#| exponent = double_info.bias
#| let bits = assemble_bits(mantissa, exponent, self.negative)
#| return bits.reinterpret_as_double()
#| }
#| if self.decimal_point > 310 {
#| range_err()
#| }
#| 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
#| }
#| 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
#| }
#| exponent -= 1
#| 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 {
#| range_err()
#| }
#| self.shift_priv(double_info.mantissa_bits + 1)
#| mantissa = self.rounded_integer()
#| if mantissa == 2L << double_info.mantissa_bits {
#| mantissa = mantissa << 1
#| exponent += 1
#| if exponent - double_info.bias >= (1 << double_info.exponent_bits) - 1 {
#| range_err()
#| }
#| }
#| if (mantissa & (1L << double_info.mantissa_bits)) == 0L {
#| exponent = double_info.bias
#| }
#| let bits = assemble_bits(mantissa, exponent, self.negative)
#| bits.reinterpret_as_double()
#|}
#|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)
#| }
#|}
#|fn assemble_bits(mantissa : Int64, exponent : Int, negative : Bool) -> Int64 {
#| let biased_exp = exponent - double_info.bias
#| let mut bits = mantissa & ((1L << double_info.mantissa_bits) - 1L)
#| let exp_bits = (biased_exp & ((1 << double_info.exponent_bits) - 1)).to_int64()
#| bits = bits | (exp_bits << double_info.mantissa_bits)
#| if negative {
#| bits = bits | (1L << double_info.mantissa_bits << double_info.exponent_bits)
#| }
#| bits
#|}
#|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
#|}
#|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 {
#| if self.truncated {
#| return true
#| }
#| return d > 0 && self.digits[d - 1].to_int() % 2 != 0
#| }
#| self.digits[d].to_int() >= 5
#|}
#|fn assign(self : Decimal, v : Int64) -> Unit {
#| let buf = FixedArray::make(24, Byte::default())
#| 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
#| }
#| 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()
#|}
#|fn right_shift(self : Decimal, s : Int) -> Unit {
#| let mut read_index = 0
#| let mut write_index = 0
#| 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
#| let mask = (1UL << s) - 1
#| while read_index < self.digits_num {
#| let out = acc >> s
#| self.digits[write_index] = out.to_byte()
#| write_index += 1
#| acc = acc & mask
#| let d = self.digits[read_index]
#| acc = acc * 10 + d.to_int64().reinterpret_as_uint64()
#| read_index += 1
#| }
#| 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
#| }
#| self.digits_num = write_index
#| self.trim()
#|}
#|let left_shift_cheats = [
#| (0, ""),
#| (1, "5"), // * 2
#| (1, "25"), // * 4
#| (1, "125"), // * 8
#| (2, "625"), // * 16
#| (2, "3125"), // * 32
#| (2, "15625"), // * 64
#| (3, "78125"), // * 128
#| (3, "390625"), // * 256
#| (3, "1953125"), // * 512
#| (4, "9765625"), // * 1024
#| (4, "48828125"), // * 2048
#| (4, "244140625"), // * 4096
#| (4, "1220703125"), // * 8192
#| (5, "6103515625"), // * 16384
#| (5, "30517578125"), // * 32768
#| (5, "152587890625"), // * 65536
#| (6, "762939453125"), // * 131072
#| (6, "3814697265625"), // * 262144
#| (6, "19073486328125"), // * 524288
#| (7, "95367431640625"), // * 1048576
#| (7, "476837158203125"), // * 2097152
#| (7, "2384185791015625"), // * 4194304
#| (7, "11920928955078125"), // * 8388608
#| (8, "59604644775390625"), // * 16777216
#| (8, "298023223876953125"), // * 33554432
#| (8, "1490116119384765625"), // * 67108864
#| (9, "7450580596923828125"), // * 134217728
#| (9, "37252902984619140625"), // * 268435456
#| (9, "186264514923095703125"), // * 536870912
#| (10, "931322574615478515625"), // * 1073741824
#| (10, "4656612873077392578125"), // * 2147483648
#| (10, "23283064365386962890625"), // * 4294967296
#| (10, "116415321826934814453125"), // * 8589934592
#| (11, "582076609134674072265625"), // * 17179869184
#| (11, "2910383045673370361328125"), // * 34359738368
#| (11, "14551915228366851806640625"), // * 68719476736
#| (12, "72759576141834259033203125"), // * 137438953472
#| (12, "363797880709171295166015625"), // * 274877906944
#| (12, "1818989403545856475830078125"), // * 549755813888
#| (13, "9094947017729282379150390625"), // * 1099511627776
#| (13, "45474735088646411895751953125"), // * 2199023255552
#| (13, "227373675443232059478759765625"), // * 4398046511104
#| (13, "1136868377216160297393798828125"), // * 8796093022208
#| (14, "5684341886080801486968994140625"), // * 17592186044416
#| (14, "28421709430404007434844970703125"), // * 35184372088832
#| (14, "142108547152020037174224853515625"), // * 70368744177664
#| (15, "710542735760100185871124267578125"), // * 140737488355328
#| (15, "3552713678800500929355621337890625"), // * 281474976710656
#| (15, "17763568394002504646778106689453125"), // * 562949953421312
#| (16, "88817841970012523233890533447265625"), // * 1125899906842624
#| (16, "444089209850062616169452667236328125"), // * 2251799813685248
#| (16, "2220446049250313080847263336181640625"), // * 4503599627370496
#| (16, "11102230246251565404236316680908203125"), // * 9007199254740992
#| (17, "55511151231257827021181583404541015625"), // * 18014398509481984
#| (17, "277555756156289135105907917022705078125"), // * 36028797018963968
#| (17, "1387778780781445675529539585113525390625"), // * 72057594037927936
#| (18, "6938893903907228377647697925567626953125"), // * 144115188075855872
#| (18, "34694469519536141888238489627838134765625"), // * 288230376151711744
#| (18, "173472347597680709441192448139190673828125"), // * 576460752303423488
#| (19, "867361737988403547205962240695953369140625"), // * 1152921504606846976
#|]
#|fn new_digits(self : Decimal, s : Int) -> Int {
#| let new_digits = left_shift_cheats[s].0
#| let cheat_num = left_shift_cheats[s].1
#| 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
#| }
#|}
#|fn left_shift(self : Decimal, s : Int) -> Unit {
#| let new_digits = self.new_digits(s)
#| let mut read_index = self.digits_num
#| let mut write_index = self.digits_num + new_digits
#| 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
#| }
#| 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
#| }
#| 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()
#|}
#|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
#| }
#|}
#|pub impl Show for Decimal with output(self, logger) {
#| if self.digits_num == 0 {
#| logger.write_char('0')
#| return
#| }
#| if self.decimal_point <= 0 {
#| logger.write_string("0.")
#| for i in 0..<-self.decimal_point {
#| logger.write_char('0')
#| }
#| for i in 0.. String {
#| Show::to_string(self)
#|}
#|test "new" {
#| let hpd = Decimal::from_int64_priv(1L)
#| inspect(hpd.digits.length(), content="800")
#| inspect(hpd.digits_num, content="1")
#| inspect(hpd.decimal_point, content="1")
#| inspect(hpd.negative, content="false")
#| inspect(hpd.truncated, content="false")
#|}
#|test "from_int64" {
#| let hpd = Decimal::from_int64_priv(123456789L)
#| inspect(hpd.to_string(), content="123456789")
#|}
#|test "parse_decimal" {
#| let s = "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625"
#| assert_eq(parse_decimal_priv(s).to_string(), s)
#| assert_eq(parse_decimal_priv("1.0e-10").to_string(), "0.0000000001")
#|}
#|test "to_string" {
#| let hpd = Decimal::from_int64_priv(123456789L)
#| hpd.decimal_point = 1
#| inspect(hpd.to_string(), content="1.23456789")
#| hpd.decimal_point = 0
#| inspect(hpd.to_string(), content="0.123456789")
#| hpd.decimal_point = -1
#| inspect(hpd.to_string(), content="0.0123456789")
#| hpd.decimal_point = 10
#| inspect(hpd.to_string(), content="1234567890")
#|}
#|test "shift" {
#| let tests : Array[_] = [
#| (0L, 100, "0"),
#| (0L, -100, "0"),
#| (1L, 100, "1267650600228229401496703205376"),
#| (
#| 1L, -100, "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625",
#| ),
#| (12345678L, 8, "3160493568"),
#| (12345678L, -8, "48225.3046875"),
#| (195312L, 9, "99999744"),
#| (1953125L, 9, "1000000000"),
#| ]
#| for i in 0.. 20" {
#| let decimal = Decimal::new_priv()
#| decimal.negative = false
#| decimal.decimal_point = 25 // This is > 20 but < 310
#| decimal.digits_num = 1
#| decimal.digits[0] = (1 : Int).to_byte()
#| decimal.truncated = false
#| let result = decimal.rounded_integer()
#| inspect(result, content="-1") // Should be Int64::max_value
#|}
#|test "corner cases" {
#| inspect(try? parse_decimal_priv(".123"), content="Ok(0.123)")
#| inspect(try? parse_decimal_priv("."), content="Err(invalid syntax)")
#| inspect(try? parse_decimal_priv("-"), content="Err(invalid syntax)")
#|}
),
"deprecated.mbt": (
#|#deprecated("Decimal will be changed to private. Use `@strconv.parse_double` instead")
#|struct Decimal {
#| digits : FixedArray[Byte]
#| mut digits_num : Int
#| mut decimal_point : Int
#| mut negative : Bool
#| mut truncated : Bool
#|}
#|#deprecated("Decimal will be changed to private. Use `@strconv.parse_double` instead")
#|pub fn Decimal::new() -> Decimal {
#| Decimal::new_priv()
#|}
#|#deprecated("Decimal will be changed to private. Use `@strconv.parse_double` instead")
#|pub fn Decimal::from_int64(v : Int64) -> Decimal {
#| Decimal::from_int64_priv(v)
#|}
#|#deprecated("use `@strconv.parse_double` instead")
#|pub fn parse_decimal(str : @string.View) -> Decimal raise StrConvError {
#| parse_decimal_from_view(str)
#|}
#|#deprecated("use `@strconv.parse_double` instead")
#|pub fn Decimal::parse_decimal(str : @string.View) -> Decimal raise StrConvError {
#| parse_decimal_from_view(str)
#|}
#|#deprecated("use `@strconv.parse_double` instead to avoid using this method.")
#|pub fn to_double(self : Decimal) -> Double raise StrConvError {
#| self.to_double_priv()
#|}
#|#deprecated("use `@strconv.parse_double` instead to avoid using this method.")
#|pub fn shift(self : Decimal, s : Int) -> Unit {
#| self.shift_priv(s)
#|}
),
"double.mbt": (
#|priv struct FloatInfo {
#| mantissa_bits : Int
#| exponent_bits : Int
#| bias : Int
#|}
#|let double_info : FloatInfo = {
#| mantissa_bits: 52,
#| exponent_bits: 11,
#| bias: -1023,
#|}
#|let mantissa_explicit_bits = 52
#|let min_exponent_fast_path : Int64 = -22L
#|let max_exponent_fast_path : Int64 = 22L
#|let max_exponent_disguised_fast_path : Int64 = 37L
#|let max_mantissa_fast_path : UInt64 = 2UL << mantissa_explicit_bits
#|pub fn parse_double(str : @string.View) -> Double raise StrConvError {
#| if str.length() == 0 {
#| syntax_err()
#| }
#| if !check_underscore(str) {
#| syntax_err()
#| }
#| 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()
#| }
#| match num.try_fast_path() {
#| Some(value) => value
#| None => {
#| let ret = parse_decimal_priv(str)
#| ret.to_double_priv()
#| }
#| }
#|}
#|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
#|}
#|let table : FixedArray[Double] = [
#| 1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 10000000.0, 100000000.0,
#| 1000000000.0, 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
#| 100000000000000.0, 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
#| 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0, 1000000000000000000000.0,
#| 10000000000000000000000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
#|]
#|fn pow10_fast_path(exponent : Int) -> Double {
#| table[exponent & 31]
#|}
#|let int_pow10 : FixedArray[UInt64] = [
#| 1UL, 10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL, 100000000UL,
#| 1000000000UL, 10000000000UL, 100000000000UL, 1000000000000UL, 10000000000000UL,
#| 100000000000000UL, 1000000000000000UL,
#|]
#|fn try_fast_path(self : Number) -> Double? {
#| if self.is_fast_path() {
#| let mut value = if self.exponent <= max_exponent_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 {
#| 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
#| }
#|}
#|test "parse_double" {
#| let tests : Array[(String, Result[Double, String])] = [
#| ("", Err(syntax_err_str)),
#| ("1x", Err(syntax_err_str)),
#| ("1.1.", Err(syntax_err_str)),
#| ("1e", Err(syntax_err_str)),
#| ("1e-", Err(syntax_err_str)),
#| (".e-1", Err(syntax_err_str)),
#| ("1", Ok(1.0)),
#| ("+1", Ok(1.0)),
#| ("1e23", Ok(1.0e23)),
#| ("1E23", Ok(1.0e23)),
#| ("100000000000000000000000", Ok(1.0e23)),
#| ("1e-100", Ok(1.0e-100)),
#| ("123456700", Ok(1.234567e+08)),
#| ("99999999999999974834176", Ok(9.999999999999997e+22)),
#| ("100000000000000000000001", Ok(1.0000000000000001e+23)),
#| ("100000000000000008388608", Ok(1.0000000000000001e+23)),
#| ("100000000000000016777215", Ok(1.0000000000000001e+23)),
#| ("100000000000000016777216", Ok(1.0000000000000003e+23)),
#| ("-1", Ok(-1.0)),
#| ("-0.1", Ok(-0.1)),
#| ("-0", Ok(-0.0)),
#| ("1e-20", Ok(1.0e-20)),
#| ("625e-3", Ok(0.625)),
#| ("6.62607015e-34", Ok(6.62607015e-34)),
#| ("2.2250738585072012e-308", Ok(2.2250738585072014e-308)),
#| ("2.2250738585072011e-308", Ok(2.225073858507201e-308)),
#| ("0", Ok(0.0)),
#| ("0e0", Ok(0.0)),
#| ("-0e0", Ok(-0.0)),
#| ("+0e0", Ok(0.0)),
#| ("0e-0", Ok(0.0)),
#| ("-0e-0", Ok(-0.0)),
#| ("+0e-0", Ok(0.0)),
#| ("0e+0", Ok(0.0)),
#| ("-0e+0", Ok(-0.0)),
#| ("+0e+0", Ok(0.0)),
#| ("0e+01234567890123456789", Ok(0.0)),
#| ("0.00e-01234567890123456789", Ok(0.0)),
#| ("-0e+01234567890123456789", Ok(-0.0)),
#| ("-0.00e-01234567890123456789", Ok(-0.0)),
#| ("0e292", Ok(0.0)),
#| ("0e347", Ok(0.0)),
#| ("0e348", Ok(0.0)),
#| ("-0e291", Ok(-0.0)),
#| ("-0e292", Ok(-0.0)),
#| ("-0e347", Ok(-0.0)),
#| ("-0e348", Ok(-0.0)),
#| ("1.7976931348623157e308", Ok(1.7976931348623157e308)),
#| ("-1.7976931348623157e308", Ok(-1.7976931348623157e308)),
#| ("1.7976931348623158e308", Ok(1.7976931348623157e308)),
#| ("-1.7976931348623158e308", Ok(-1.7976931348623157e308)),
#| ("1e308", Ok(1.0e308)),
#| (
#| "1.7976931348623159e308",
#| Err(
#| range_err_str,
#| ),
#| ),
#| (
#| "-1.7976931348623159e308",
#| Err(
#| range_err_str,
#| ),
#| ),
#| ("2e308", Err(range_err_str)),
#| ("1e309", Err(range_err_str)),
#| ("1e310", Err(range_err_str)),
#| ("1e400", Err(range_err_str)),
#| ("1e40000", Err(range_err_str)),
#| ("1e-305", Ok(1.0e-305)),
#| ("1e-306", Ok(1.0e-306)),
#| ("1e-307", Ok(1.0e-307)),
#| ("1e-308", Ok(1.0e-308)),
#| ("1e-309", Ok(1.0e-309)),
#| ("1e-310", Ok(1.0e-310)),
#| ("1e-322", Ok(1.0e-322)),
#| ("5e-324", Ok(5.0e-324)),
#| ("4e-324", Ok(5.0e-324)),
#| ("3e-324", Ok(5.0e-324)),
#| ("2e-324", Ok(0.0)),
#| ("1e-350", Ok(0.0)),
#| ("1e-400000", Ok(0.0)),
#| ("1_23.50_0_0e+1_2", Ok(1.235e+14)),
#| ("-_123.5e+12", Err(syntax_err_str)),
#| ("+_123.5e+12", Err(syntax_err_str)),
#| ("_123.5e+12", Err(syntax_err_str)),
#| ("1__23.5e+12", Err(syntax_err_str)),
#| ("123_.5e+12", Err(syntax_err_str)),
#| ("123._5e+12", Err(syntax_err_str)),
#| ("123.5_e+12", Err(syntax_err_str)),
#| ("123.5__0e+12", Err(syntax_err_str)),
#| ("123.5e_+12", Err(syntax_err_str)),
#| ("123.5e+_12", Err(syntax_err_str)),
#| ("123.5e_-12", Err(syntax_err_str)),
#| ("123.5e-_12", Err(syntax_err_str)),
#| ("123.5e+1__2", Err(syntax_err_str)),
#| ("123.5e+12_", Err(syntax_err_str)),
#| ]
#| for i in 0.. Err(err)
#| },
#| t.1,
#| )
#| }
#|}
#|test "parse_double_inf" {
#| assert_eq(parse_double("inf"), @double.infinity)
#| assert_eq(parse_double("+Inf"), @double.infinity)
#| assert_eq(parse_double("-Inf"), @double.neg_infinity)
#| assert_eq(parse_double("+Infinity"), @double.infinity)
#| assert_eq(parse_double("-Infinity"), @double.neg_infinity)
#| assert_eq(parse_double("+INFINITY"), @double.infinity)
#| assert_eq(parse_double("-INFINITY"), @double.neg_infinity)
#|}
#|test "parse_double_nan" {
#| assert_true(parse_double("nan").is_nan())
#| assert_true(parse_double("NaN").is_nan())
#| assert_true(parse_double("NAN").is_nan())
#|}
),
"errors.mbt": (
#|pub(all) suberror StrConvError String
#|pub impl Show for StrConvError with output(self, logger) {
#| match self {
#| StrConvError(err) => logger.write_string(err)
#| }
#|}
#|let range_err_str = "value out of range"
#|let syntax_err_str = "invalid syntax"
#|let base_err_str = "invalid base"
#|fn[T] range_err() -> T raise StrConvError {
#| raise StrConvError(range_err_str)
#|}
#|fn[T] syntax_err() -> T raise StrConvError {
#| raise StrConvError(syntax_err_str)
#|}
#|fn[T] base_err() -> T raise StrConvError {
#| raise StrConvError(base_err_str)
#|}
),
"int.mbt": (
#|const INT_MIN = 0x80000000
#|const INT_MAX = 0x7fffffff
#|const INT64_MIN = -0x8000000000000000L
#|const INT64_MAX = 0x7fffffffffffffffL
#|fn check_and_consume_base(
#| view : @string.View,
#| base : Int,
#|) -> (Int, @string.View, Bool) raise StrConvError {
#| if base == 0 {
#| match view {
#| ['0', 'x' | 'X', .. rest] => (16, rest, true)
#| ['0', 'o' | 'O', .. rest] => (8, rest, true)
#| ['0', 'b' | 'B', .. rest] => (2, rest, true)
#| _ => (10, view, false)
#| }
#| } else {
#| match view {
#| ['0', 'x' | 'X', .. rest] if base == 16 => (16, rest, true)
#| ['0', 'o' | 'O', .. rest] if base == 8 => (8, rest, true)
#| ['0', 'b' | 'B', .. rest] if base == 2 => (2, rest, true)
#| _ => if base is (2..=36) { (base, view, false) } else { base_err() }
#| }
#| }
#|}
#|test {
#| inspect(try? parse_int64("0b01", base=3), content="Err(invalid syntax)")
#| inspect(try? parse_int64("0x01", base=3), content="Err(invalid syntax)")
#| inspect(try? parse_int64("0o01", base=3), content="Err(invalid syntax)")
#|}
#|pub fn parse_int64(
#| str : @string.View,
#| base? : Int = 0,
#|) -> Int64 raise StrConvError {
#| guard str != "" else { syntax_err() }
#| let (neg, rest) = match str.view() {
#| ['+', .. rest] => (false, rest)
#| ['-', .. rest] => (true, rest)
#| rest => (false, rest)
#| }
#| let (num_base, rest, allow_underscore) = check_and_consume_base(rest, base)
#| let overflow_threshold = overflow_threshold(num_base, neg)
#| let has_digit = rest
#| is (['0'..='9' | 'a'..='z' | 'A'..='Z', ..]
#| | ['_', '0'..='9' | 'a'..='z' | 'A'..='Z', ..])
#| guard has_digit else { syntax_err() }
#| loop (rest, 0L, allow_underscore) {
#| (['_'], _, _) =>
#| syntax_err()
#| (['_', ..], _, false) => syntax_err()
#| (['_', .. rest], acc, true) => continue (rest, acc, false)
#| ([c, .. rest], acc, _) => {
#| let c = c.to_int()
#| let d = match c {
#| '0'..='9' => c - '0'
#| 'a'..='z' => c + (10 - 'a')
#| 'A'..='Z' => c + (10 - 'A')
#| _ => syntax_err()
#| }
#| guard d < num_base else { syntax_err() }
#| if neg {
#| guard acc >= overflow_threshold else { range_err() }
#| let next_acc = acc * num_base.to_int64() - d.to_int64()
#| guard next_acc <= acc else { range_err() }
#| continue (rest, next_acc, true)
#| } else {
#| guard acc < overflow_threshold else { range_err() }
#| let next_acc = acc * num_base.to_int64() + d.to_int64()
#| guard next_acc >= acc else { range_err() }
#| continue (rest, next_acc, true)
#| }
#| }
#| ([], acc, _) => acc
#| }
#|}
#|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()
#|}
#|fn check_underscore(str : @string.View) -> Bool {
#| let rest = match str {
#| ['+' | '-', .. rest] => rest
#| rest => rest
#| }
#| 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)
#| }
#| fn is_digit(c : Char) -> Bool {
#| c is ('0'..='9') || (hex && c is ('a'..='f' | 'A'..='F'))
#| }
#| let follow_underscore = false
#| loop (rest, allow_underscore, follow_underscore) {
#| ([], _, _) => true
#| (['_'], _, _) => false
#| (['_', ..], false, _) => false
#| (['_', .. rest], true, _) => continue (rest, false, true)
#| ([c, .. rest], _, follow_underscore) =>
#| if is_digit(c) {
#| continue (rest, true, false)
#| } else if follow_underscore {
#| false
#| } else {
#| continue (rest, false, false)
#| }
#| }
#|}
#|fn determine_base(s : String) -> Int {
#| match s {
#| ['0', 'x' | 'X', ..] => 16
#| ['0', 'o' | 'O', ..] => 8
#| ['0', 'b' | 'B', ..] => 2
#| _ => 10
#| }
#|}
#|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()
#| }
#|}
#|test "check_underscore" {
#| assert_true(check_underscore("123"))
#| assert_true(check_underscore("0x123"))
#| assert_true(check_underscore("0o123"))
#| assert_true(check_underscore("0b101"))
#| assert_true(check_underscore("1_2_3"))
#| assert_true(check_underscore("0x_1_2_3_A_F"))
#| assert_true(check_underscore("0o_1_2_3"))
#| assert_true(check_underscore("0b_1_0_1"))
#| assert_false(check_underscore("1__2_3"))
#| assert_false(check_underscore("_123"))
#| assert_false(check_underscore("123_"))
#|}
#|test "determine_base" {
#| inspect(determine_base("1234"), content="10")
#| inspect(determine_base("0x1234"), content="16")
#| inspect(determine_base("0X1234"), content="16")
#| inspect(determine_base("0o1234"), content="8")
#| inspect(determine_base("0O1234"), content="8")
#| inspect(determine_base("0b1010"), content="2")
#| inspect(determine_base("0B1010"), content="2")
#|}
#|test "parse_int64" {
#| let tests : Array[(String, Result[Int64, String])] = [
#| ("", Err(syntax_err_str)),
#| ("0", Ok(0L)),
#| ("-0", Ok(0L)),
#| ("+0", Ok(0L)),
#| ("1", Ok(1L)),
#| ("-1", Ok(-1L)),
#| ("+1", Ok(1L)),
#| ("12345", Ok(12345L)),
#| ("-12345", Ok(-12345L)),
#| ("012345", Ok(12345L)),
#| ("-012345", Ok(-12345L)),
#| ("9876543210", Ok(9876543210L)),
#| ("-9876543210", Ok(-9876543210L)),
#| ("9223372036854775807", Ok(9223372036854775807L)),
#| ("-9223372036854775807", Ok(-9223372036854775807L)),
#| ("9223372036854775808", Err(range_err_str)),
#| ("-9223372036854775808", Ok(-9223372036854775808L)),
#| ("9223372036854775809", Err(range_err_str)),
#| ("-9223372036854775809", Err(range_err_str)),
#| ("-1_2_3_4_5", Ok(-12345L)),
#| ("-_12345", Err(syntax_err_str)),
#| ("_12345", Err(syntax_err_str)),
#| ("1__2345", Err(syntax_err_str)),
#| ("12345_", Err(syntax_err_str)),
#| ("12345%", Err(syntax_err_str)),
#| ]
#| for i in 0.. Err(err)
#| },
#| t.1,
#| )
#| }
#|}
#|test "parse_int64_base" {
#| let tests : Array[(String, Int, Result[Int64, String])] = [
#| ("", 0, Err(syntax_err_str)),
#| ("0", 0, Ok(0L)),
#| ("-0", 0, Ok(0L)),
#| ("1", 0, Ok(1L)),
#| ("-1", 0, Ok(-1L)),
#| ("12345", 0, Ok(12345L)),
#| ("-12345", 0, Ok(-12345L)),
#| ("012345", 0, Ok(12345L)),
#| ("-012345", 0, Ok(-12345L)),
#| ("0x12345", 0, Ok(0x12345L)),
#| ("-0x12345", 0, Ok(-0x12345L)),
#| ("9876543210", 0, Ok(9876543210L)),
#| ("-9876543210", 0, Ok(-9876543210L)),
#| ("9223372036854775807", 0, Ok(9223372036854775807L)),
#| ("-9223372036854775807", 0, Ok(-9223372036854775807L)),
#| ("9223372036854775808", 0, Err(range_err_str)),
#| ("12345x", 0, Err(syntax_err_str)),
#| ("-12345x", 0, Err(syntax_err_str)),
#| ("-9223372036854775808", 0, Ok(-9223372036854775808L)),
#| ("9223372036854775809", 0, Err(range_err_str)),
#| ("-9223372036854775809", 0, Err(range_err_str)),
#| ("h", 18, Ok(17L)),
#| ("10", 25, Ok(25L)),
#| (
#| "moonbit",
#| 35,
#| Ok(
#| (
#| ((((22L * 35L + 24L) * 35L + 24L) * 35L + 23L) * 35L + 11L) * 35L +
#| 18L
#| ) *
#| 35L +
#| 29L,
#| ),
#| ),
#| (
#| "moonbit",
#| 36,
#| Ok(
#| (
#| ((((22L * 36L + 24L) * 36L + 24L) * 36L + 23L) * 36L + 11L) * 36L +
#| 18L
#| ) *
#| 36L +
#| 29L,
#| ),
#| ),
#| ("0", 2, Ok(0L)),
#| ("-1", 2, Ok(-1L)),
#| ("1010", 2, Ok(10L)),
#| ("1000000000000000", 2, Ok(1L << 15)),
#| (
#| "111111111111111111111111111111111111111111111111111111111111111",
#| 2,
#| Ok((1L << 63) - 1L),
#| ),
#| (
#| "1000000000000000000000000000000000000000000000000000000000000000",
#| 2,
#| Err(range_err_str),
#| ),
#| (
#| "-1000000000000000000000000000000000000000000000000000000000000000",
#| 2,
#| Ok(-1L << 63),
#| ),
#| (
#| "-1000000000000000000000000000000000000000000000000000000000000001",
#| 2,
#| Err(range_err_str),
#| ),
#| ("-10", 8, Ok(-8L)),
#| ("57635436545", 8, Ok(0o57635436545L)),
#| ("100000000", 8, Ok(1L << 24)),
#| ("10", 16, Ok(16L)),
#| ("-123456789abcdef", 16, Ok(-0x123456789abcdefL)),
#| ("7fffffffffffffff", 16, Ok((1L << 63) - 1L)),
#| ("-0x_1_2_3_4_5", 0, Ok(-0x12345L)),
#| ("0x_1_2_3_4_5", 0, Ok(0x12345L)),
#| ("-_0x12345", 0, Err(syntax_err_str)),
#| ("_-0x12345", 0, Err(syntax_err_str)),
#| ("_0x12345", 0, Err(syntax_err_str)),
#| ("0x__12345", 0, Err(syntax_err_str)),
#| ("0x1__2345", 0, Err(syntax_err_str)),
#| ("0x1234__5", 0, Err(syntax_err_str)),
#| ("0x12345_", 0, Err(syntax_err_str)),
#| ("-0_1_2_3_4_5", 0, Ok(-12345L)),
#| ("0_1_2_3_4_5", 0, Ok(12345L)),
#| ("-_012345", 0, Err(syntax_err_str)),
#| ("_-012345", 0, Err(syntax_err_str)),
#| ("_012345", 0, Err(syntax_err_str)),
#| ("0__12345", 0, Err(syntax_err_str)),
#| ("01234__5", 0, Err(syntax_err_str)),
#| ("012345_", 0, Err(syntax_err_str)),
#| ("+0xf", 0, Ok(0xfL)),
#| ("-0xf", 0, Ok(-0xfL)),
#| ("0x+f", 0, Err(syntax_err_str)),
#| ("0x-f", 0, Err(syntax_err_str)),
#| ]
#| for i in 0.. Err(err)
#| },
#| t.2,
#| )
#| }
#|}
#|test "parse_int" {
#| let tests : Array[(String, Result[Int, String])] = [
#| ("", Err(syntax_err_str)),
#| ("0", Ok(0)),
#| ("-0", Ok(0)),
#| ("1", Ok(1)),
#| ("-1", Ok(-1)),
#| ("12345", Ok(12345)),
#| ("-12345", Ok(-12345)),
#| ("012345", Ok(12345)),
#| ("-012345", Ok(-12345)),
#| ("12345x", Err(syntax_err_str)),
#| ("-12345x", Err(syntax_err_str)),
#| ("987654321", Ok(987654321)),
#| ("-987654321", Ok(-987654321)),
#| ("2147483647", Ok((1 << 31) - 1)),
#| ("-2147483647", Ok(-((1 << 31) - 1))),
#| ("2147483648", Err(range_err_str)),
#| ("-2147483648", Ok(-1 << 31)),
#| ("2147483649", Err(range_err_str)),
#| ("-2147483649", Err(range_err_str)),
#| ("-1_2_3_4_5", Ok(-12345)),
#| ("-_12345", Err(syntax_err_str)),
#| ("_12345", Err(syntax_err_str)),
#| ("1__2345", Err(syntax_err_str)),
#| ("12345_", Err(syntax_err_str)),
#| ("123%45", Err(syntax_err_str)),
#| ]
#| for i in 0.. Err(err)
#| },
#| t.1,
#| )
#| }
#|}
),
"number.mbt": (
#|let min_19digit_int : UInt64 = 100_0000_0000_0000_0000UL
#|priv struct Number {
#| exponent : Int64
#| mantissa : UInt64
#| negative : Bool
#| many_digits : Bool
#|}
#|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()))
#|}
#|fn try_parse_19digits(
#| s : @string.View,
#| x : UInt64,
#|) -> (@string.View, UInt64, Int) {
#| let mut x = x
#| let mut len = 0
#| loop s {
#| ['0'..='9' as ch, .. rest] if x < min_19digit_int => {
#| len += 1
#| x = x * 10UL +
#| UInt64::extend_uint((ch.to_int() - '0').reinterpret_as_uint()) // no overflows here
#| continue rest
#| }
#| ['_', .. rest] => continue rest
#| s => return (s, x, len)
#| }
#|}
#|fn parse_scientific(s : @string.View) -> (@string.View, Int64)? {
#| 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
#| }
#|}
#|fn parse_number(s : @string.View) -> (Number, Int)? {
#| let mut s = s
#| let start = s
#| 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
#| }
#| let (s, mantissa, consumed) = parse_digits(s, 0UL)
#| let mut mantissa = mantissa
#| let mut s = s
#| let mut n_digits = consumed
#| let mut n_after_dot = 0
#| let mut exponent = 0L
#| if s is ['.', .. rest] {
#| s = rest
#| 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
#| }
#| 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()
#| 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 {
#| 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))
#|}
#|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
#| }
#|}
#|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)
#| }
#| if b.clz() == 0 || a.clz() == 0 {
#| return None
#| }
#| let quotient : UInt64 = @uint64.max_value / b
#| if a > quotient {
#| return None
#| }
#| Some(a * b)
#|}
),
"string_view.mbt": (
#|fn @string.View::step(self : Self, step : Int) -> Self? {
#| let mut step = step
#| let mut str = self
#| while str is [ch, .. rest] && step > 0 {
#| if ch != '_' {
#| step -= 1
#| }
#| str = rest
#| }
#| if step == 0 {
#| Some(str)
#| } else {
#| None
#| }
#|}
#|fn[T] @string.View::fold_digits(
#| self : Self,
#| init : T,
#| f : (Int, T) -> T,
#|) -> (Self, T, Int) {
#| let mut ret = init
#| let mut len = 0
#| let mut str = self
#| while str is [ch, .. rest] {
#| if ch is ('0'..='9') {
#| len += 1
#| ret = f(ch.to_int() - '0', ret)
#| } else if ch != '_' {
#| break
#| }
#| str = rest
#| }
#| (str, ret, len)
#|}
),
"traits.mbt": (
#|pub(open) trait FromStr {
#| from_string(String) -> Self raise StrConvError
#|}
#|pub impl FromStr for Bool with from_string(str) {
#| parse_bool(str)
#|}
#|pub impl FromStr for Int with from_string(str) {
#| parse_int(str)
#|}
#|pub impl FromStr for Int64 with from_string(str) {
#| parse_int64(str)
#|}
#|pub impl FromStr for UInt with from_string(str) {
#| parse_uint(str)
#|}
#|pub impl FromStr for UInt64 with from_string(str) {
#| parse_uint64(str)
#|}
#|pub impl FromStr for Double with from_string(str) {
#| parse_double(str)
#|}
#|pub fn[A : FromStr] parse(str : String) -> A raise StrConvError {
#| A::from_string(str)
#|}
#|test "parse" {
#| let b : Bool = parse("true")
#| inspect(b, content="true")
#| let i : Int = parse("12345")
#| inspect(i, content="12345")
#| let i64 : Int64 = parse("9223372036854775807")
#| assert_eq(i64, 9223372036854775807L)
#| let ui : UInt = parse("4294967295")
#| inspect(ui, content="4294967295")
#| let ui64 : UInt64 = parse("18446744073709551615")
#| assert_eq(ui64, 18446744073709551615UL)
#| let d : Double = parse("1234.56789")
#| assert_eq(d, 1234.56789)
#|}
),
"uint.mbt": (
#|const UINT_MAX : UInt = 0xffffffff
#|const UINT64_MAX : UInt64 = 0xffffffffffffffffUL
#|pub fn parse_uint64(
#| str : @string.View,
#| base? : Int = 0,
#|) -> UInt64 raise StrConvError {
#| guard str != "" else { syntax_err() }
#| if str is ['+' | '-', ..] {
#| syntax_err()
#| }
#| let (num_base, rest, allow_underscore) = check_and_consume_base(str, base)
#| let overflow_threshold = match num_base {
#| 10 => UINT64_MAX / 10 + 1
#| 16 => UINT64_MAX / 16 + 1
#| _ => UINT64_MAX / num_base.to_uint64() + 1
#| }
#| let has_digit = rest
#| is (['0'..='9' | 'a'..='z' | 'A'..='Z', ..]
#| | ['_', '0'..='9' | 'a'..='z' | 'A'..='Z', ..])
#| guard has_digit else { syntax_err() }
#| loop (rest, 0UL, allow_underscore) {
#| (['_'], _, _) =>
#| syntax_err()
#| (['_', ..], _, false) => syntax_err()
#| (['_', .. rest], acc, true) => continue (rest, acc, false)
#| ([c, .. rest], acc, _) => {
#| let c = c.to_int()
#| let d = match c {
#| '0'..='9' => c - '0'
#| 'a'..='z' => c + (10 - 'a')
#| 'A'..='Z' => c + (10 - 'A')
#| _ => syntax_err()
#| }
#| guard d < num_base else { syntax_err() }
#| guard acc < overflow_threshold else { range_err() }
#| let next_acc = acc * num_base.to_uint64() + d.to_uint64()
#| guard next_acc >= acc && next_acc <= UINT64_MAX else { range_err() }
#| continue (rest, next_acc, true)
#| }
#| ([], acc, _) => acc
#| }
#|}
#|pub fn parse_uint(
#| str : @string.View,
#| base? : Int = 0,
#|) -> UInt raise StrConvError {
#| let n = parse_uint64(str, base~)
#| if n > UINT_MAX.to_uint64() {
#| range_err()
#| }
#| n.to_uint()
#|}
#|test "parse_uint64" {
#| let tests : Array[(String, Result[UInt64, String])] = [
#| ("", Err(syntax_err_str)),
#| ("0", Ok(0UL)),
#| ("-0", Err(syntax_err_str)),
#| ("+0", Err(syntax_err_str)),
#| ("1", Ok(1UL)),
#| ("-1", Err(syntax_err_str)),
#| ("12345", Ok(12345UL)),
#| ("-12345", Err(syntax_err_str)),
#| ("012345", Ok(12345UL)),
#| ("9876543210", Ok(9876543210UL)),
#| ("18446744073709551615", Ok(18446744073709551615UL)),
#| ("18446744073709551616", Err(range_err_str)),
#| ("1_2_3_4_5", Ok(12345UL)),
#| ("_12345", Err(syntax_err_str)),
#| ("1__2345", Err(syntax_err_str)),
#| ("12345_", Err(syntax_err_str)),
#| ("12345%", Err(syntax_err_str)),
#| ]
#| for i in 0.. Err(err)
#| },
#| t.1,
#| )
#| }
#|}
#|test "parse_uint64_base" {
#| let tests : Array[(String, Int, Result[UInt64, String])] = [
#| ("", 0, Err(syntax_err_str)),
#| ("0", 0, Ok(0UL)),
#| ("1", 0, Ok(1UL)),
#| ("12345", 0, Ok(12345UL)),
#| ("012345", 0, Ok(12345UL)),
#| ("0x12345", 0, Ok(0x12345UL)),
#| ("9876543210", 0, Ok(9876543210UL)),
#| ("18446744073709551615", 0, Ok(UINT64_MAX)),
#| ("0xffffffffffffffff", 0, Ok(UINT64_MAX)),
#| ("18446744073709551616", 0, Err(range_err_str)),
#| ("12345x", 0, Err(syntax_err_str)),
#| ("-12345x", 0, Err(syntax_err_str)),
#| ("h", 18, Ok(17UL)),
#| ("10", 25, Ok(25UL)),
#| (
#| "moonbit",
#| 35,
#| Ok(
#| (
#| ((((22UL * 35UL + 24UL) * 35UL + 24UL) * 35UL + 23UL) * 35UL + 11UL) *
#| 35UL +
#| 18UL
#| ) *
#| 35UL +
#| 29UL,
#| ),
#| ),
#| (
#| "moonbit",
#| 36,
#| Ok(
#| (
#| ((((22UL * 36UL + 24UL) * 36UL + 24UL) * 36UL + 23UL) * 36UL + 11UL) *
#| 36UL +
#| 18UL
#| ) *
#| 36UL +
#| 29UL,
#| ),
#| ),
#| ("0", 2, Ok(0UL)),
#| ("-1", 2, Err(syntax_err_str)),
#| ("1010", 2, Ok(10UL)),
#| ("1000000000000000", 2, Ok(1UL << 15)),
#| (
#| "1111111111111111111111111111111111111111111111111111111111111111",
#| 2,
#| Ok(UINT64_MAX),
#| ),
#| (
#| "1000000000000000000000000000000000000000000000000000000000000000",
#| 2,
#| Ok(1UL << 63),
#| ),
#| ("10", 8, Ok(8UL)),
#| ("57635436545", 8, Ok(0o57635436545UL)),
#| ("100000000", 8, Ok(1UL << 24)),
#| ("10", 16, Ok(16UL)),
#| ("ffffffffffffffff", 16, Ok(UINT64_MAX)),
#| ("0x_1_2_3_4_5", 0, Ok(0x12345UL)),
#| ("-_0x12345", 0, Err(syntax_err_str)),
#| ("_-0x12345", 0, Err(syntax_err_str)),
#| ("_0x12345", 0, Err(syntax_err_str)),
#| ("0x__12345", 0, Err(syntax_err_str)),
#| ("0x1__2345", 0, Err(syntax_err_str)),
#| ("0x1234__5", 0, Err(syntax_err_str)),
#| ("0x12345_", 0, Err(syntax_err_str)),
#| ("0_1_2_3_4_5", 0, Ok(12345UL)),
#| ("-_012345", 0, Err(syntax_err_str)),
#| ("_-012345", 0, Err(syntax_err_str)),
#| ("_012345", 0, Err(syntax_err_str)),
#| ("0__12345", 0, Err(syntax_err_str)),
#| ("01234__5", 0, Err(syntax_err_str)),
#| ("012345_", 0, Err(syntax_err_str)),
#| ("0xf", 0, Ok(0xfUL)),
#| ("-0xf", 0, Err(syntax_err_str)),
#| ("0x+f", 0, Err(syntax_err_str)),
#| ("0x-f", 0, Err(syntax_err_str)),
#| ]
#| for i in 0.. Err(err)
#| },
#| t.2,
#| )
#| }
#|}
#|test "parse_uint" {
#| let tests : Array[(String, Result[UInt, String])] = [
#| ("", Err(syntax_err_str)),
#| ("0", Ok(0)),
#| ("-0", Err(syntax_err_str)),
#| ("+0", Err(syntax_err_str)),
#| ("1", Ok(1)),
#| ("-1", Err(syntax_err_str)),
#| ("12345", Ok(12345)),
#| ("012345", Ok(12345)),
#| ("12345x", Err(syntax_err_str)),
#| ("-12345x", Err(syntax_err_str)),
#| ("987654321", Ok(987654321)),
#| ("4294967295", Ok(UINT_MAX)),
#| ("0xffffffff", Ok(UINT_MAX)),
#| ("4294967296", Err(range_err_str)),
#| ("1_2_3_4_5", Ok(12345)),
#| ("-_12345", Err(syntax_err_str)),
#| ("_12345", Err(syntax_err_str)),
#| ("1__2345", Err(syntax_err_str)),
#| ("12345_", Err(syntax_err_str)),
#| ("123%45", Err(syntax_err_str)),
#| ]
#| for i in 0.. Err(err)
#| },
#| t.1,
#| )
#| }
#|}
#|test "parse_uint64 uppercase hex and invalid base" {
#| inspect(try? parse_uint64("ABCD", base=16), content="Ok(43981)")
#| inspect(try? parse_uint64("1234", base=37), content="Err(invalid base)")
#|}
),
},
)
///|
let moonbitlang_core_string_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/string",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/char": moonbitlang_core_char_module,
},
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin", "moonbitlang/core/char"],
#| "test-import": [
#| "moonbitlang/core/list",
#| "moonbitlang/core/json",
#| "moonbitlang/core/quickcheck"
#| ],
#| "targets": {
#| "panic_test.mbt": ["not", "native", "llvm"]
#| }
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `@string.concat` instead")
#|pub fn String::concat(self : Array[String], separator? : String = "") -> String {
#| concat(self, separator~)
#|}
#|#deprecated("Use `Array::join` instead.")
#|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()
#| }
#| }
#|}
#|#deprecated("Use `s.find(substr)` instead. If the optional argument `from` is not 0, take view from the string first. Please do not use an invalid `from` argument.")
#|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
#| }
#|}
#|#deprecated("Use `s.rev_find(substr)` instead. If the optional argument `from` is not 0, take view from the string first. Please do not use an invalid `from` argument.")
#|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
#| }
#|}
#|#deprecated("Use `s[i]` instead")
#|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)
#|}
#|#deprecated("Use `s.get_char(i).unwrap()` instead")
#|pub fn View::char_at(self : View, index : Int) -> Char {
#| self.get_char(index).unwrap()
#|}
#|#deprecated("Use `s.get_char(i).unwrap()` instead")
#|pub fn String::char_at(self : String, offset : Int) -> Char {
#| match self.get_char(offset) {
#| Some(c) => c
#| None => '�'
#| }
#|}
),
"methods.mbt": (
#|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)
#| }
#|}
#|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 {
#| while i <= forward_len && haystack.unsafe_charcode_at(i) != needle_first {
#| i += 1
#| }
#| if i <= forward_len {
#| 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 }
#| 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] {
#| 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
#|}
#|test "boyer_moore_horspool_find edge cases" {
#| inspect(boyer_moore_horspool_find("abc"[:], ""[:]), content="Some(0)")
#| inspect(boyer_moore_horspool_find("ab"[:], "abcd"[:]), content="None")
#|}
#|test "boyer_moore_horspool_rev_find edge cases" {
#| inspect(boyer_moore_horspool_rev_find("abc"[:], ""[:]), content="Some(3)")
#| inspect(boyer_moore_horspool_rev_find("ab"[:], "abcd"[:]), content="None")
#|}
#|pub fn String::find(self : String, str : View) -> Int? {
#| self[:].find(str)
#|}
#|test "find" {
#| inspect("hello".find("o"), content="Some(4)")
#| inspect("hello".find("l"), content="Some(2)")
#| inspect("hello".find("hello"), content="Some(0)")
#| inspect("hello".find("h"), content="Some(0)")
#| inspect("hello".find(""), content="Some(0)")
#| inspect("hello".find("world"), content="None")
#| inspect("".find(""), content="Some(0)")
#| inspect("".find("a"), content="None")
#| inspect("hello hello".find("hello"), content="Some(0)")
#| inspect("aaa".find("aa"), content="Some(0)")
#| inspect("😀😀".find("😀"), content="Some(0)")
#| inspect(
#| ("😀😀aa".repeat(20) + "😀😀😀😀").find("😀😀😀😀"),
#| content="Some(120)",
#| )
#| inspect(
#| ("😀😀😀😀" + "😀😀aa".repeat(20)).find("😀😀😀😀"),
#| content="Some(0)",
#| )
#|}
#|pub fn View::find_by(self : View, pred : (Char) -> Bool) -> Int? {
#| for i, c in self {
#| if pred(c) {
#| return Some(i)
#| }
#| }
#| None
#|}
#|pub fn String::find_by(self : String, pred : (Char) -> Bool) -> Int? {
#| self[:].find_by(pred)
#|}
#|test "find_by" {
#| inspect("hello".find_by(c => c == 'o'), content="Some(4)")
#| inspect("hello".find_by(c => c == 'l'), content="Some(2)")
#| inspect("hello".find_by(c => c == 'z'), content="None")
#| inspect("".find_by(c => c == 'a'), content="None")
#| inspect("hello".find_by(c => c is ('0'..='9')), content="None")
#| inspect("hello123".find_by(c => c is ('0'..='9')), content="Some(5)")
#| inspect("hello".find_by(c => c is ('A'..='Z')), content="None")
#| inspect("Hello".find_by(c => c is ('A'..='Z')), content="Some(0)")
#| inspect("αβγ".find_by(c => c == 'β'), content="Some(1)")
#| inspect("😀😁😂".find_by(c => c == '😂'), content="Some(2)")
#|}
#|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)
#| }
#|}
#|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 {
#| while i >= 0 && haystack.unsafe_charcode_at(i) != needle_first {
#| i -= 1
#| }
#| if i >= 0 {
#| 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] {
#| for j in 0.. Int? {
#| self[:].rev_find(str)
#|}
#|test "rev_find" {
#| inspect("hello".rev_find("o"), content="Some(4)")
#| inspect("hello".rev_find("l"), content="Some(3)")
#| inspect("hello".rev_find("hello"), content="Some(0)")
#| inspect("hello".rev_find("h"), content="Some(0)")
#| inspect("hello".rev_find(""), content="Some(5)")
#| inspect("hello".rev_find("world"), content="None")
#| inspect("".rev_find(""), content="Some(0)")
#| inspect("".rev_find("a"), content="None")
#| inspect("hello hello".rev_find("hello"), content="Some(6)")
#| inspect("aaa".rev_find("aa"), content="Some(1)")
#| inspect("😀😀".rev_find("😀"), content="Some(2)")
#| inspect(
#| ("😀😀aa".repeat(20) + "😀😀😀😀").rev_find("😀😀😀😀"),
#| content="Some(120)",
#| )
#| inspect(
#| ("😀😀😀😀" + "😀😀aa".repeat(20)).rev_find("😀😀😀😀"),
#| content="Some(4)",
#| )
#|}
#|pub fn View::has_suffix(self : View, str : View) -> Bool {
#| self.rev_find(str) is Some(i) && i == self.length() - str.length()
#|}
#|pub fn String::has_suffix(self : String, str : View) -> Bool {
#| self[:].has_suffix(str)
#|}
#|test "has_suffix" {
#| inspect("hello".has_suffix("lo"), content="true")
#| inspect("hello".has_suffix("hello"), content="true")
#| inspect("hello".has_suffix(""), content="true")
#| inspect("hello".has_suffix("world"), content="false")
#| inspect("hello".has_suffix("hel"), content="false")
#| inspect("".has_suffix(""), content="true")
#| inspect("".has_suffix("a"), content="false")
#| inspect("hello world".has_suffix("world"), content="true")
#| inspect("😀😀".has_suffix("😀"), content="true")
#| inspect("😀😀".has_suffix("😀😀"), content="true")
#|}
#|pub fn View::has_prefix(self : View, str : View) -> Bool {
#| self.find(str) is Some(i) && i == 0
#|}
#|pub fn String::has_prefix(self : String, str : View) -> Bool {
#| self[:].has_prefix(str)
#|}
#|test "has_prefix" {
#| inspect("hello".has_prefix("h"), content="true")
#| inspect("hello".has_prefix("he"), content="true")
#| inspect("hello".has_prefix(""), content="true")
#| inspect("hello".has_prefix("world"), content="false")
#| inspect("hello".has_prefix("lo"), content="false")
#| inspect("".has_prefix(""), content="true")
#| inspect("".has_prefix("a"), content="false")
#| inspect("😀hello".has_prefix("😀"), content="true")
#| inspect("😀😃hello".has_prefix("😀😃"), content="true")
#| inspect("😀hello".has_prefix("😃"), content="false")
#| inspect("hello😀".has_prefix("😀"), content="false")
#|}
#|#alias(ends_with, deprecated)
#|pub fn strip_suffix(self : String, suffix : View) -> View? {
#| if self.has_suffix(suffix) {
#| Some(self.charcodes(end=self.length() - suffix.length()))
#| } else {
#| None
#| }
#|}
#|test "strip_prefix" {
#| inspect("hello world".strip_prefix("hello "), content="Some(\"world\")")
#| inspect("hello world".strip_prefix("hi "), content="None")
#| inspect("hello".strip_prefix("hello"), content="Some(\"\")")
#| inspect("".strip_prefix(""), content="Some(\"\")")
#| inspect("".strip_prefix("a"), content="None")
#| inspect("abc".strip_prefix(""), content="Some(\"abc\")")
#| inspect("😀hello".strip_prefix("😀"), content="Some(\"hello\")")
#| inspect("😀😃hello".strip_prefix("😀😃"), content="Some(\"hello\")")
#|}
#|test "strip_suffix" {
#| inspect("hello world".strip_suffix(" world"), content="Some(\"hello\")")
#| inspect("hello world".strip_suffix(" moon"), content="None")
#| inspect("hello".strip_suffix("hello"), content="Some(\"\")")
#| inspect("".strip_suffix(""), content="Some(\"\")")
#| inspect("".strip_suffix("a"), content="None")
#| inspect("abc".strip_suffix(""), content="Some(\"abc\")")
#| inspect("hello😀".strip_suffix("😀"), content="Some(\"hello\")")
#| inspect("hello😀😃".strip_suffix("😀😃"), content="Some(\"hello\")")
#|}
#|#alias(starts_with, deprecated)
#|pub fn strip_prefix(self : String, prefix : View) -> View? {
#| if self.has_prefix(prefix) {
#| Some(self.charcodes(start=prefix.length()))
#| } else {
#| None
#| }
#|}
#|pub fn View::strip_prefix(self : View, prefix : View) -> View? {
#| if self.has_prefix(prefix) {
#| Some(self.view(start_offset=prefix.length()))
#| } else {
#| None
#| }
#|}
#|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
#| }
#|}
#|pub fn View::to_array(self : View) -> Array[Char] {
#| self
#| .iter()
#| .fold(init=Array::new(capacity=self.length()), (rv, c) => {
#| rv.push(c)
#| rv
#| })
#|}
#|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
#|}
#|test "View::strip_prefix" {
#| let view = "hello world"[:]
#| inspect(view.strip_prefix("hello "), content="Some(\"world\")")
#| inspect(view.strip_prefix("hi "), content="None")
#| inspect(view.strip_prefix("hello world"), content="Some(\"\")")
#| inspect(view.strip_prefix(""), content="Some(\"hello world\")")
#| let empty_view = ""[:]
#| inspect(empty_view.strip_prefix(""), content="Some(\"\")")
#| inspect(empty_view.strip_prefix("a"), content="None")
#| let unicode_view = "😀hello😃"[:]
#| inspect(unicode_view.strip_prefix("😀"), content="Some(\"hello😃\")")
#| inspect(unicode_view.strip_prefix("😃"), content="None")
#|}
#|test "View::strip_suffix" {
#| let view = "hello world"[:]
#| inspect(view.strip_suffix(" world"), content="Some(\"hello\")")
#| inspect(view.strip_suffix(" moon"), content="None")
#| inspect(view.strip_suffix("hello world"), content="Some(\"\")")
#| inspect(view.strip_suffix(""), content="Some(\"hello world\")")
#| let empty_view = ""[:]
#| inspect(empty_view.strip_suffix(""), content="Some(\"\")")
#| inspect(empty_view.strip_suffix("a"), content="None")
#| let unicode_view = "😀hello😃"[:]
#| inspect(unicode_view.strip_suffix("😃"), content="Some(\"😀hello\")")
#| inspect(unicode_view.strip_suffix("😀"), content="None")
#|}
#|test "View::to_array" {
#| let view = "Hello🤣"[:]
#| let chars = view.to_array()
#| assert_eq(chars, ['H', 'e', 'l', 'l', 'o', '🤣'])
#| let empty_view = ""[:]
#| let empty_chars = empty_view.to_array()
#| assert_eq(empty_chars, [])
#| let sub_view = "Hello World"[6:11] // "World"
#| let sub_chars = sub_view.to_array()
#| assert_eq(sub_chars, ['W', 'o', 'r', 'l', 'd'])
#|}
#|test "View::to_bytes" {
#| let view = "Hello"[:]
#| let bytes = view.to_bytes()
#| assert_eq(bytes.to_unchecked_string(), "Hello")
#| let unicode_view = "🤣🤔"[:]
#| let unicode_bytes = unicode_view.to_bytes()
#| assert_eq(unicode_bytes.to_unchecked_string(), "🤣🤔")
#| let sub_view = "Hello World"[0:5] // "Hello"
#| let sub_bytes = sub_view.to_bytes()
#| assert_eq(sub_bytes.to_unchecked_string(), "Hello")
#|}
#|pub fn View::contains(self : View, str : View) -> Bool {
#| self.find(str) is Some(_)
#|}
#|pub fn contains(self : String, str : View) -> Bool {
#| self[:].contains(str)
#|}
#|test "contains" {
#| inspect("hello".contains("o"), content="true")
#| inspect("hello".contains("l"), content="true")
#| inspect("hello".contains("hello"), content="true")
#| inspect("hello".contains("h"), content="true")
#| inspect("hello".contains(""), content="true")
#| inspect("hello".contains("world"), content="false")
#| inspect("".contains(""), content="true")
#| inspect("".contains("a"), content="false")
#| inspect("hello hello".contains("hello"), content="true")
#| inspect("aaa".contains("aa"), content="true")
#| inspect("😀😀".contains("😀"), content="true")
#|}
#|pub fn View::contains_char(self : View, c : Char) -> Bool {
#| let len = self.length()
#| guard len > 0 else { return false }
#| let c = c.to_int()
#| if c <= 0xFFFF {
#| for i in 0..= 2 else { return false }
#| let adj = c - 0x10000
#| let high = 0xD800 + (adj >> 10)
#| let low = 0xDC00 + (adj & 0x3FF)
#| 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
#|}
#|pub fn contains_char(self : String, c : Char) -> Bool {
#| self[:].contains_char(c)
#|}
#|test "contains_char" {
#| inspect("hello".contains_char('h'), content="true")
#| inspect("hello".contains_char('e'), content="true")
#| inspect("hello".contains_char('l'), content="true")
#| inspect("hello".contains_char('o'), content="true")
#| inspect("hello".contains_char('x'), content="false")
#| inspect("".contains_char('a'), content="false")
#| inspect("hello world".contains_char(' '), content="true")
#| inspect("hello world".contains_char('w'), content="true")
#| inspect("😀😀".contains_char('😀'), content="true")
#| inspect("😀😀".contains_char('😃'), content="false")
#| inspect("hello".contains_char((104).unsafe_to_char()), content="true") // 'h' is 104 in ASCII
#|}
#|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
#| }
#| }
#|}
#|pub fn trim_start(self : String, char_set : View) -> View {
#| self[:].trim_start(char_set)
#|}
#|test "trim_start" {
#| inspect("hello".trim_start("h"), content="ello")
#| inspect("hello".trim_start("he"), content="llo")
#| inspect("hello".trim_start("eh"), content="llo")
#| inspect("hello".trim_start("x"), content="hello")
#| inspect("hello".trim_start(""), content="hello")
#| inspect("".trim_start("a"), content="")
#| inspect(" hello".trim_start(" "), content="hello")
#| inspect("hello world".trim_start("helo"), content=" world")
#| inspect("😀😀hello".trim_start("😀"), content="hello")
#| inspect("😀😃hello".trim_start("😀😃"), content="hello")
#| inspect("aaaabc".trim_start("a"), content="bc")
#| inspect("aaaa".trim_start("a"), content="")
#|}
#|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
#| }
#| }
#|}
#|pub fn trim_end(self : String, char_set : View) -> View {
#| self[:].trim_end(char_set)
#|}
#|test "trim_end" {
#| inspect("hello".trim_end("o"), content="hell")
#| inspect("hello".trim_end("lo"), content="he")
#| inspect("hello".trim_end("x"), content="hello")
#| inspect("hello".trim_end(""), content="hello")
#| inspect("".trim_end("a"), content="")
#| inspect("hello ".trim_end(" "), content="hello")
#| inspect("hello world".trim_end("dlrow "), content="he")
#| inspect("hello😀😀".trim_end("😀"), content="hello")
#| inspect("hello😀😃".trim_end("😀😃"), content="hello")
#| inspect("abcccc".trim_end("c"), content="ab")
#| inspect("cccc".trim_end("c"), content="")
#|}
#|pub fn View::trim(self : View, char_set : View) -> View {
#| self.trim_start(char_set).trim_end(char_set)
#|}
#|pub fn trim(self : String, char_set : View) -> View {
#| self[:].trim(char_set)
#|}
#|test "trim" {
#| inspect("hello".trim("h"), content="ello")
#| inspect("hello".trim("o"), content="hell")
#| inspect("hello".trim("ho"), content="ell")
#| inspect("hello".trim("oh"), content="ell")
#| inspect("hello".trim("x"), content="hello")
#| inspect("hello".trim(""), content="hello")
#| inspect("".trim("a"), content="")
#| inspect(" hello ".trim(" "), content="hello")
#| inspect("hello world".trim("hd"), content="ello worl")
#| inspect("😀hello😀".trim("😀"), content="hello")
#| inspect("😀😃hello😀😃".trim("😀😃"), content="hello")
#| inspect("aaaabcaaa".trim("a"), content="bc")
#| inspect("aaaa".trim("a"), content="")
#| inspect(" hello world ".trim(" "), content="hello world")
#| inspect("abcabc".trim("abc"), content="")
#|}
#|pub fn View::trim_space(self : View) -> View {
#| self.trim(" \n\r\t")
#|}
#|pub fn trim_space(self : String) -> View {
#| self[:].trim_space()
#|}
#|test "trim_space" {
#| inspect("hello".trim_space(), content="hello")
#| inspect(" hello ".trim_space(), content="hello")
#| inspect("hello ".trim_space(), content="hello")
#| inspect(" hello".trim_space(), content="hello")
#| inspect("\t\nhello\r\n".trim_space(), content="hello")
#| inspect(" hello world ".trim_space(), content="hello world")
#| inspect(" ".trim_space(), content="")
#| inspect("\n\r\t".trim_space(), content="")
#| inspect("".trim_space(), content="")
#| inspect(" hello\nworld\t".trim_space(), content="hello\nworld")
#|}
#|pub fn View::is_empty(self : View) -> Bool {
#| self.length() == 0
#|}
#|pub fn is_empty(self : String) -> Bool {
#| self == ""
#|}
#|test "is_empty" {
#| inspect("".is_empty(), content="true")
#| inspect("hello".is_empty(), content="false")
#| inspect(" ".is_empty(), content="false")
#| inspect("\n".is_empty(), content="false")
#| inspect("\t".is_empty(), content="false")
#| inspect(" ".is_empty(), content="false")
#| let s = "hello"
#| let empty_view = s[0:0]
#| let non_empty_view = s[0:3]
#| inspect(empty_view.is_empty(), content="true")
#| inspect(non_empty_view.is_empty(), content="false")
#|}
#|pub fn View::is_blank(self : View) -> Bool {
#| self.trim_space().is_empty()
#|}
#|pub fn is_blank(self : String) -> Bool {
#| self[:].is_blank()
#|}
#|test "is_blank" {
#| inspect("".is_blank(), content="true")
#| inspect("hello".is_blank(), content="false")
#| inspect(" ".is_blank(), content="true")
#| inspect("\n".is_blank(), content="true")
#| inspect("\t".is_blank(), content="true")
#| inspect(" ".is_blank(), content="true")
#| inspect(" \n\t\r ".is_blank(), content="true")
#| inspect("hello world".is_blank(), content="false")
#| inspect(" hello ".is_blank(), content="false")
#| let s = " hello "
#| let blank_view = s[0:3] // " "
#| let non_blank_view = s[3:8] // "hello"
#| inspect(blank_view.is_blank(), content="true")
#| inspect(non_blank_view.is_blank(), content="false")
#|}
#|pub fn View::pad_start(
#| self : View,
#| total_width : Int,
#| padding_char : Char,
#|) -> String {
#| let len = self.length()
#| guard len < total_width else { return self.to_string() }
#| let padding = String::make(total_width - len, padding_char)
#| [..padding, ..self]
#|}
#|pub fn pad_start(
#| self : String,
#| total_width : Int,
#| padding_char : Char,
#|) -> String {
#| let len = self.length()
#| guard len < total_width else { return self }
#| let padding = String::make(total_width - len, padding_char)
#| [..padding, ..self]
#|}
#|test "pad_start" {
#| inspect("2".pad_start(3, '0'), content="002")
#| inspect("abc".pad_start(5, 'x'), content="xxabc")
#| inspect("hello".pad_start(4, ' '), content="hello") // No padding needed
#| inspect("".pad_start(3, '-'), content="---")
#| inspect("test".pad_start(8, '*'), content="****test")
#| inspect("123".pad_start(6, '0'), content="000123")
#| let s = "hello"
#| let view = s[2:5] // "llo"
#| inspect(view.pad_start(5, 'x'), content="xxllo")
#| inspect("🌟".pad_start(3, '✨'), content="✨🌟")
#| inspect("abc".pad_start(0, 'x'), content="abc") // width less than string length
#| inspect("abc".pad_start(3, 'x'), content="abc") // width equal to string length
#|}
#|pub fn View::pad_end(
#| self : View,
#| total_width : Int,
#| padding_char : Char,
#|) -> String {
#| let len = self.length()
#| guard len < total_width else { return self.to_string() }
#| let padding = String::make(total_width - len, padding_char)
#| [..self, ..padding]
#|}
#|pub fn String::pad_end(
#| self : String,
#| total_width : Int,
#| padding_char : Char,
#|) -> String {
#| let len = self.length()
#| guard len < total_width else { return self }
#| let padding = String::make(total_width - len, padding_char)
#| [..self, ..padding]
#|}
#|test "pad_end" {
#| inspect("2".pad_end(3, '0'), content="200")
#| inspect("abc".pad_end(5, 'x'), content="abcxx")
#| inspect("hello".pad_end(4, ' '), content="hello") // No padding needed
#| inspect("".pad_end(3, '-'), content="---")
#| inspect("test".pad_end(8, '*'), content="test****")
#| inspect("123".pad_end(6, '0'), content="123000")
#| let s = "hello"
#| let view = s[2:5] // "llo"
#| inspect(view.pad_end(5, 'x'), content="lloxx")
#| inspect("🌟".pad_end(3, '✨'), content="🌟✨")
#| inspect("abc".pad_end(0, 'x'), content="abc") // width less than string length
#| inspect("abc".pad_end(3, 'x'), content="abc") // width equal to string length
#|}
#|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()
#|}
#|pub fn rev(self : String) -> String {
#| self[:].rev()
#|}
#|test "rev" {
#| inspect("hello".rev(), content="olleh")
#| inspect("".rev(), content="")
#| inspect("abc".rev(), content="cba")
#| inspect("😀😃".rev(), content="😃😀")
#|}
#|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)
#| }
#| })
#|}
#|pub fn split(self : String, sep : View) -> Iter[View] {
#| self[:].split(sep)
#|}
#|test "split" {
#| assert_eq("a,b,c".split(",").map(View::to_string).collect(), ["a", "b", "c"])
#| assert_eq("a,b,c".split("").map(View::to_string).collect(), [
#| "a", ",", "b", ",", "c",
#| ])
#| assert_eq(
#| "apple::orange::banana".split("::").map(View::to_string).collect(),
#| ["apple", "orange", "banana"],
#| )
#| assert_eq("abc".split("").map(View::to_string).collect(), ["a", "b", "c"])
#| assert_eq("hello".split(",").map(View::to_string).collect(), ["hello"])
#| assert_eq(",a,b,c".split(",").map(View::to_string).collect(), [
#| "", "a", "b", "c",
#| ])
#| assert_eq("a,b,c,".split(",").map(View::to_string).collect(), [
#| "a", "b", "c", "",
#| ])
#| assert_eq("a,b,c".split("").map(View::to_string).collect(), [
#| "a", ",", "b", ",", "c",
#| ])
#| assert_eq("".split("").map(View::to_string).collect(), [])
#| assert_eq("".split(",").map(View::to_string).collect(), [""])
#| assert_eq("😀,😃,😄".split(",").map(View::to_string).collect(), [
#| "😀", "😃", "😄",
#| ])
#| assert_eq("a😀b😀c".split("😀").map(View::to_string).collect(), [
#| "a", "b", "c",
#| ])
#|}
#|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
#| }
#|}
#|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
#| }
#|}
#|test "replace" {
#| inspect("hello".replace(old="o", new="a"), content="hella")
#| inspect("hello".replace(old="l", new="a"), content="healo")
#| inspect("hello".replace(old="hello", new="a"), content="a")
#| inspect("hello".replace(old="h", new="a"), content="aello")
#| inspect("hello".replace(old="", new="a"), content="ahello")
#| inspect("hello".replace(old="world", new="a"), content="hello")
#| inspect("".replace(old="", new="a"), content="a")
#|}
#|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()
#| 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)
#| 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
#| }
#| }
#|}
#|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()
#| 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)
#| 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
#| }
#| }
#|}
#|test "replace_all" {
#| assert_eq("hello".replace_all(old="o", new="a"), "hella")
#| assert_eq("hello".replace_all(old="l", new="a"), "heaao")
#| assert_eq("hello".replace_all(old="ll", new="rr"), "herro")
#| assert_eq("hello".replace_all(old="hello", new="world"), "world")
#| assert_eq("hello hello hello".replace_all(old="hello", new="hi"), "hi hi hi")
#| assert_eq(
#| "hello hello helloi".replace_all(old="hello", new="hi"),
#| "hi hi hii",
#| )
#| assert_eq(
#| "hi hi hii".replace_all(old="hi", new="hello"),
#| "hello hello helloi",
#| )
#| assert_eq("hello".replace_all(old="", new="a"), "ahaealalaoa")
#| assert_eq("hello".replace_all(old="world", new="a"), "hello")
#| assert_eq("".replace_all(old="", new="a"), "a")
#| assert_eq("aaa".replace_all(old="a", new="b"), "bbb")
#| assert_eq("aaa".replace_all(old="a", new="bb"), "bbbbbb")
#| assert_eq("aaa".replace_all(old="aa", new="b"), "ba")
#| assert_eq("🤣🤣🤣".replace_all(old="🤣", new="😊"), "😊😊😊")
#| assert_eq("abc123abc".replace_all(old="abc", new="xyz"), "xyz123xyz")
#| assert_eq("abcabcabc".replace_all(old="abc", new=""), "")
#| assert_eq("abc".replace_all(old="abc", new=""), "")
#| assert_eq("abc".replace_all(old="", new="x"), "xaxbxcx")
#|}
#|test "String::replace_all boundary cases" {
#| assert_eq("helloworld".replace_all(old="world", new="X"), "helloX")
#| assert_eq("abcdef".replace_all(old="def", new="XYZ"), "abcXYZ")
#| assert_eq("abcabc".replace_all(old="abc", new="X"), "XX")
#| assert_eq("test".replace_all(old="test", new="done"), "done")
#| assert_eq("remove_me".replace_all(old="_me", new=""), "remove")
#|}
#|test "View::replace_all" {
#| assert_eq("hello"[:].replace_all(old="o", new="a"), "hella")
#| assert_eq("hello"[:].replace_all(old="l", new="a"), "heaao")
#| assert_eq("hello"[:].replace_all(old="ll", new="rr"), "herro")
#| assert_eq("hello"[:].replace_all(old="hello", new="world"), "world")
#| assert_eq(
#| "hello hello hello"[:].replace_all(old="hello", new="hi"),
#| "hi hi hi",
#| )
#| assert_eq(
#| "hello hello helloi"[:].replace_all(old="hello", new="hi"),
#| "hi hi hii",
#| )
#| assert_eq(
#| "hi hi hii"[:].replace_all(old="hi", new="hello"),
#| "hello hello helloi",
#| )
#| assert_eq("hello"[:].replace_all(old="", new="a"), "ahaealalaoa")
#| assert_eq("hello"[:].replace_all(old="world", new="a"), "hello")
#| assert_eq(""[:].replace_all(old="", new="a"), "a")
#| assert_eq("aaa"[:].replace_all(old="a", new="b"), "bbb")
#| assert_eq("aaa"[:].replace_all(old="a", new="bb"), "bbbbbb")
#| assert_eq("aaa"[:].replace_all(old="aa", new="b"), "ba")
#| assert_eq(
#| "🤣🤣🤣"[:].replace_all(old="🤣", new="😊"),
#| "😊😊😊",
#| )
#| assert_eq("abc123abc"[:].replace_all(old="abc", new="xyz"), "xyz123xyz")
#| assert_eq("abcabcabc"[:].replace_all(old="abc", new=""), "")
#| assert_eq("abc"[:].replace_all(old="abc", new=""), "")
#| assert_eq("abc"[:].replace_all(old="", new="x"), "xaxbxcx")
#|}
#|test "View::replace_all boundary cases" {
#| assert_eq("abcabc"[:].replace_all(old="abc", new="X"), "XX")
#| assert_eq("aaaa"[:].replace_all(old="aa", new="b"), "bb")
#| assert_eq("hello"[:].replace_all(old="lo", new="X"), "helX")
#| assert_eq("a"[:].replace_all(old="a", new=""), "")
#| inspect("Testing boundary condition", content="Testing boundary condition")
#|}
#|pub fn View::to_lower(self : View) -> View {
#| 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() {
#| buf.write_char((c.to_int() + 32).unsafe_to_char())
#| } else {
#| buf.write_char(c)
#| }
#| }
#| buf.to_string()
#|}
#|pub fn to_lower(self : String) -> String {
#| 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() {
#| buf.write_char((c.to_int() + 32).unsafe_to_char())
#| } else {
#| buf.write_char(c)
#| }
#| }
#| buf.to_string()
#|}
#|test "to_lower" {
#| assert_eq("Hello".to_lower(), "hello")
#| assert_eq("HELLO".to_lower(), "hello")
#| assert_eq("Hello, World!".to_lower(), "hello, world!")
#|}
#|test "View::to_lower" {
#| assert_eq("Hello"[:].to_lower(), "hello")
#| assert_eq("HELLO"[:].to_lower(), "hello")
#| assert_eq("Hello, World!"[:].to_lower(), "hello, world!")
#|}
#|pub fn View::to_upper(self : View) -> View {
#| 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()
#|}
#|pub fn to_upper(self : String) -> String {
#| 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()
#|}
#|test "to_upper" {
#| assert_eq("hello".to_upper(), "HELLO")
#| assert_eq("HELLO".to_upper(), "HELLO")
#| assert_eq("Hello, World!".to_upper(), "HELLO, WORLD!")
#|}
#|test "View::to_upper" {
#| assert_eq("hello"[:].to_upper(), "HELLO")
#| assert_eq("HELLO"[:].to_upper(), "HELLO")
#| assert_eq("Hello, World!"[:].to_upper(), "HELLO, WORLD!")
#|}
#|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
#|}
#|pub fn[A] fold(self : String, init~ : A, f : (A, Char) -> A) -> A {
#| self[:].fold(init~, f)
#|}
#|test "fold" {
#| assert_eq(
#| "hello".fold(init=[], (acc, c) => {
#| acc.push(c)
#| acc
#| }),
#| ['h', 'e', 'l', 'l', 'o'],
#| )
#| assert_eq(
#| "hello".fold(init=0, (acc, c) => acc + c.to_int()),
#| 104 + 101 + 108 + 108 + 111,
#| )
#|}
#|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
#|}
#|pub fn[A] rev_fold(self : String, init~ : A, f : (A, Char) -> A) -> A {
#| self[:].rev_fold(init~, f)
#|}
#|test "rev_fold" {
#| assert_eq(
#| "hello".rev_fold(init=[], (acc, c) => {
#| acc.push(c)
#| acc
#| }),
#| ['o', 'l', 'l', 'e', 'h'],
#| )
#| assert_eq(
#| "hello".rev_fold(init=0, (acc, c) => acc + c.to_int()),
#| 111 + 108 + 108 + 101 + 104,
#| )
#|}
#|pub fn String::get(self : String, idx : Int) -> Int? {
#| guard idx >= 0 && idx < self.length() else { return None }
#| Some(self.unsafe_charcode_at(idx))
#|}
#|pub fn View::get(self : View, idx : Int) -> Int? {
#| guard idx >= 0 && idx < self.length() else { return None }
#| Some(self.unsafe_charcode_at(idx))
#|}
#|test "String::get supports emoji (surrogate pair)" {
#| let s = "hello"
#| inspect(s.get(0), content="Some(104)")
#| inspect(s.get(4), content="Some(111)")
#| inspect(s.get(5), content="None")
#| inspect(s.get(-1), content="None")
#| let s = "a🤣b"
#| inspect(s.get(0), content="Some(97)")
#| inspect(s.get(1), content="Some(55358)")
#| inspect(s.get(2), content="Some(56611)")
#| inspect(s.get(3), content="Some(98)")
#| inspect(s.get(4), content="None")
#|}
#|test "View::get basic cases" {
#| let v = "hello"[1:-1]
#| inspect(v.get(0), content="Some(101)")
#| inspect(v.get(2), content="Some(108)")
#| inspect(v.get(3), content="None")
#| inspect(v.get(-1), content="None")
#| let v = "ab🤣cd"[1:-1]
#| inspect(v.get(0), content="Some(98)")
#| inspect(v.get(1), content="Some(55358)")
#| inspect(v.get(2), content="Some(56611)")
#|}
#|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())
#| }
#|}
#|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())
#| }
#|}
#|test "String::get_char basic cases" {
#| let s = "hello"
#| inspect(s.get_char(0), content="Some('h')")
#| inspect(s.get_char(1), content="Some('e')")
#| inspect(s.get_char(4), content="Some('o')")
#| inspect(s.get_char(5), content="None")
#| inspect(s.get_char(-1), content="None")
#| let s = "a🤣b"
#| inspect(s.get_char(0), content="Some('a')")
#| inspect(s.get_char(1), content="Some('🤣')")
#| inspect(s.get_char(2), content="None") // Second half of surrogate pair is not a valid char
#| inspect(s.get_char(3), content="Some('b')")
#| inspect(s.get_char(4), content="None")
#|}
#|test "View::get_char basic cases" {
#| let s = "a🤣b"
#| let v = s[0:-1]
#| inspect(v.get_char(0), content="Some('a')")
#| inspect(v.get_char(1), content="Some('🤣')")
#| inspect(v.get_char(2), content="None")
#| inspect(v.get_char(3), content="None")
#| inspect(v.get_char(4), content="None")
#| let v2 = s[1:3] // Only contains the emoji surrogate pair
#| inspect(v2.get_char(0), content="Some('🤣')")
#| inspect(v2.get_char(1), content="None")
#| inspect(v2.get_char(2), content="None")
#|}
),
"string.mbt": (
#|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()
#|}
#|pub fn from_array(chars : Array[Char]) -> String {
#| String::from_array(chars)
#|}
#|pub fn String::from_iter(iter : Iter[Char]) -> String {
#| let chars = iter.collect()
#| String::from_array(chars)
#|}
#|pub fn from_iter(iter : Iter[Char]) -> String {
#| let chars = iter.collect()
#| String::from_array(chars)
#|}
#|pub impl Compare for String with compare(self, other) {
#| let len = self.length()
#| match len.compare(other.length()) {
#| 0 => {
#| for i in 0.. order
#| }
#|}
#|pub impl Default for String with default() {
#| ""
#|}
#|pub fn default() -> String {
#| ""
#|}
#|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
#|}
#|fn unsafe_to_bytes(array : FixedArray[Byte]) -> Bytes = "%identity"
#|pub fn to_array(self : String) -> Array[Char] {
#| self
#| .iter()
#| .fold(init=Array::new(capacity=self.length()), (rv, c) => {
#| rv.push(c)
#| rv
#| })
#|}
#|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
#| }
#| }
#| guard yield_(n, c1.unsafe_to_char()) is IterContinue else {
#| break IterEnd
#| }
#| } else {
#| IterContinue
#| }
#| })
#|}
#|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
#| }
#| }
#| guard yield_(c1.unsafe_to_char()) is IterContinue else { break IterEnd }
#| } else {
#| IterContinue
#| }
#| })
#|}
#|fn String::offset_of_nth_char_forward(
#| self : String,
#| n : Int,
#| start_offset~ : Int,
#| end_offset~ : Int,
#|) -> Int? {
#| guard start_offset >= 0 && start_offset <= end_offset else {
#| abort("Invalid start index")
#| }
#| let mut utf16_offset = start_offset
#| let mut char_count = 0
#| while utf16_offset < end_offset && char_count < n {
#| let c = self.unsafe_charcode_at(utf16_offset)
#| if c.is_leading_surrogate() {
#| utf16_offset = utf16_offset + 2
#| } else {
#| utf16_offset = utf16_offset + 1
#| }
#| char_count = char_count + 1
#| }
#| if char_count < n || utf16_offset >= end_offset {
#| None
#| } else {
#| Some(utf16_offset)
#| }
#|}
#|fn String::offset_of_nth_char_backward(
#| self : String,
#| n : Int,
#| start_offset~ : Int,
#| end_offset~ : Int,
#|) -> Int? {
#| let mut char_count = 0
#| let mut utf16_offset = end_offset
#| while utf16_offset - 1 >= start_offset && char_count < n {
#| let c = self.unsafe_charcode_at(utf16_offset - 1)
#| if c.is_trailing_surrogate() {
#| utf16_offset = utf16_offset - 2
#| } else {
#| utf16_offset = utf16_offset - 1
#| }
#| char_count = char_count + 1
#| }
#| if char_count < n || utf16_offset < start_offset {
#| None
#| } else {
#| Some(utf16_offset)
#| }
#|}
#|pub fn String::offset_of_nth_char(
#| self : String,
#| i : Int,
#| start_offset? : Int = 0,
#| end_offset? : Int,
#|) -> Int? {
#| let end_offset = if end_offset is Some(o) { o } else { self.length() }
#| if i >= 0 {
#| self.offset_of_nth_char_forward(i, start_offset~, end_offset~)
#| } else {
#| self.offset_of_nth_char_backward(-i, start_offset~, end_offset~)
#| }
#|}
#|pub fn String::char_length_eq(
#| self : String,
#| len : Int,
#| start_offset? : Int = 0,
#| end_offset? : Int,
#|) -> Bool {
#| let end_offset = if end_offset is Some(o) { o } else { self.length() }
#| for index = start_offset, count = 0
#| index < end_offset && count < len
#| index = index + 1, count = count + 1 {
#| let c1 = self.unsafe_charcode_at(index)
#| if c1.is_leading_surrogate() && index + 1 < end_offset {
#| let c2 = self.unsafe_charcode_at(index + 1)
#| if c2.is_trailing_surrogate() {
#| continue index + 2, count + 1
#| } else {
#| abort("invalid surrogate pair")
#| }
#| }
#| } else {
#| count == len && index == end_offset
#| }
#|}
#|pub fn String::char_length_ge(
#| self : String,
#| len : Int,
#| start_offset? : Int = 0,
#| end_offset? : Int,
#|) -> Bool {
#| let end_offset = if end_offset is Some(o) { o } else { self.length() }
#| for index = start_offset, count = 0
#| index < end_offset && count < len
#| index = index + 1, count = count + 1 {
#| let c1 = self.unsafe_charcode_at(index)
#| if c1.is_leading_surrogate() && index + 1 < end_offset {
#| let c2 = self.unsafe_charcode_at(index + 1)
#| if c2.is_trailing_surrogate() {
#| continue index + 2, count + 1
#| } else {
#| abort("invalid surrogate pair")
#| }
#| }
#| } else {
#| count >= len
#| }
#|}
),
"string_like.mbt": (
#|pub trait ToStringView {
#| to_string_view(Self) -> View
#|}
#|pub impl ToStringView for String with to_string_view(self) -> View {
#| self[:]
#|}
#|pub impl ToStringView for View with to_string_view(self) -> View {
#| self
#|}
),
"utils.mbt": (
#|fn code_point_of_surrogate_pair(leading : Int, trailing : Int) -> Char {
#| ((leading - 0xD800) * 0x400 + trailing - 0xDC00 + 0x10000).unsafe_to_char()
#|}
#|test "code_point_of_surrogate_pair" {
#| let s = "😀"
#| let leading = s.charcode_at(0)
#| let trailing = s.charcode_at(1)
#| inspect(code_point_of_surrogate_pair(leading, trailing), content="😀")
#|}
#|test "is_leading_surrogate" {
#| inspect("🤣".charcode_at(0).is_leading_surrogate(), content="true")
#| inspect("🤣".charcode_at(1).is_leading_surrogate(), content="false")
#|}
#|test "is_trailing_surrogate" {
#| inspect("🤣".charcode_at(0).is_trailing_surrogate(), content="false")
#| inspect("🤣".charcode_at(1).is_trailing_surrogate(), content="true")
#|}
#|test "is_surrogate" {
#| inspect((0xD800).is_surrogate(), content="true") // Leading surrogate
#| inspect((0xDBFF).is_surrogate(), content="true") // Leading surrogate
#| inspect((0xDC00).is_surrogate(), content="true") // Trailing surrogate
#| inspect((0xDFFF).is_surrogate(), content="true") // Trailing surrogate
#| inspect((0xD7FF).is_surrogate(), content="false") // Just before surrogates
#| inspect((0xE000).is_surrogate(), content="false") // Just after surrogates
#| inspect((0x41).is_surrogate(), content="false") // Regular ASCII 'A'
#|}
),
"view.mbt": (
#|#builtin.valtype
#|type View
#|fn View::str(self : View) -> String = "%stringview.str"
#|fn View::start(self : View) -> Int = "%stringview.start"
#|fn View::end(self : View) -> Int = "%stringview.end"
#|fn View::make_view(str : String, start : Int, end : Int) -> View = "%stringview.make"
#|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)
#|}
#|pub fn data(self : View) -> String {
#| self.str()
#|}
#|pub fn start_offset(self : View) -> Int {
#| self.start()
#|}
#|pub fn length(self : View) -> Int {
#| self.end() - self.start()
#|}
#|pub fn String::view(
#| self : String,
#| start_offset? : Int = 0,
#| end_offset? : Int,
#|) -> View {
#| let end_offset = if end_offset is Some(o) { o } else { self.length() }
#| guard start_offset >= 0 &&
#| start_offset <= end_offset &&
#| end_offset <= self.length() else {
#| abort("Invalid index for View")
#| }
#| View::make_view(self, start_offset, end_offset)
#|}
#|pub fn View::view(
#| self : View,
#| start_offset? : Int = 0,
#| end_offset? : Int,
#|) -> View {
#| let end_offset = if end_offset is Some(o) { o } else { self.length() }
#| guard start_offset >= 0 &&
#| start_offset <= end_offset &&
#| end_offset <= self.length() else {
#| abort("Invalid index for View")
#| }
#| View::make_view(
#| self.str(),
#| self.start() + start_offset,
#| self.start() + end_offset,
#| )
#|}
#|#deprecated("use view instead")
#|pub fn String::charcodes(self : String, start? : Int = 0, end? : Int) -> View {
#| self.view(start_offset=start, end_offset?=end)
#|}
#|#deprecated("use view instead")
#|pub fn View::charcodes(self : View, start? : Int = 0, end? : Int) -> View {
#| self.view(start_offset=start, end_offset?=end)
#|}
#|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
#| }
#|}
#|pub fn View::unsafe_charcode_at(self : View, index : Int) -> Int {
#| self.str().unsafe_charcode_at(self.start() + index)
#|}
#|pub fn View::char_length(self : View) -> Int {
#| self.str().char_length(start_offset=self.start(), end_offset=self.end())
#|}
#|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())
#|}
#|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())
#|}
#|pub impl Show for View with output(self, logger) {
#| let substr = self.str().substring(start=self.start(), end=self.end())
#| String::output(substr, logger)
#|}
#|pub impl Show for View with to_string(self) {
#| self.str().substring(start=self.start(), end=self.end())
#|}
#|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
#| }
#| })
#|}
#|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
#| })
#|}
#|pub impl Eq for View with equal(self, other) {
#| let len = self.length()
#| guard len == other.length() else { return false }
#| if physical_equal(self.str(), other.str()) && self.start() == other.start() {
#| return true
#| }
#| for i in 0.. View {
#| let s = String::from_array(chars)
#| View::make_view(s, 0, s.length())
#|}
#|pub fn View::from_iter(iter : Iter[Char]) -> View {
#| let s = String::from_iter(iter)
#| View::make_view(s, 0, s.length())
#|}
#|pub fn View::make(length : Int, value : Char) -> View {
#| String::make(length, value).view()
#|}
#|pub impl ToJson for View with to_json(self) {
#| String::to_json(self.to_string())
#|}
#|pub impl Hash for View with hash_combine(self : View, hasher : Hasher) -> Unit {
#| for i in 0.. View raise CreatingViewError {
#| 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 { raise IndexOutOfBounds }
#| if start < len && self.unsafe_charcode_at(start).is_trailing_surrogate() {
#| raise InvalidIndex
#| }
#| if end < len && self.unsafe_charcode_at(end).is_trailing_surrogate() {
#| raise InvalidIndex
#| }
#| View::make_view(self, start, end)
#|}
#|pub fn View::op_as_view(
#| self : View,
#| start? : Int = 0,
#| end? : Int,
#|) -> View raise CreatingViewError {
#| let str_len = self.str().length()
#| let abs_end = match end {
#| None => self.end()
#| Some(end) => if end < 0 { self.end() + end } else { self.start() + end }
#| }
#| let abs_start = if start < 0 {
#| self.end() + start
#| } else {
#| self.start() + start
#| }
#| guard abs_start >= self.start() &&
#| abs_start <= abs_end &&
#| abs_end <= self.end() else {
#| raise IndexOutOfBounds
#| }
#| if abs_start < str_len &&
#| self.str().unsafe_charcode_at(abs_start).is_trailing_surrogate() {
#| raise InvalidIndex
#| }
#| if abs_end < str_len &&
#| self.str().unsafe_charcode_at(abs_end).is_trailing_surrogate() {
#| raise InvalidIndex
#| }
#| View::make_view(self.str(), abs_start, abs_end)
#|}
#|pub impl Add for View with add(self, other) {
#| [..self, ..other]
#|}
),
},
)
///|
let moonbitlang_core_test_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/bench",
#| "moonbitlang/core/json"
#| ]
#|}
),
"deprecated.mbt": (
#|#callsite(autofill(loc))
#|#deprecated("Use built-in `assert_eq` instead")
#|#coverage.skip
#|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~)
#| }
#|}
#|#callsite(autofill(loc))
#|#deprecated("Use built-in `assert_not_eq` instead")
#|#coverage.skip
#|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~)
#| }
#|}
#|#callsite(autofill(loc))
#|#deprecated("Use built-in `assert_true` instead")
#|#coverage.skip
#|pub fn is_true(x : Bool, loc~ : SourceLoc) -> Unit raise {
#| if !x {
#| let x = debug_string(x)
#| fail("`\{x}` is not true", loc~)
#| }
#|}
#|#callsite(autofill(loc))
#|#deprecated("Use built-in `assert_false` instead")
#|#coverage.skip
#|pub fn is_false(x : Bool, loc~ : SourceLoc) -> Unit raise {
#| if x {
#| let x = debug_string(x)
#| fail("`\{x}` is not false", loc~)
#| }
#|}
#|#deprecated("Use `@bench.single_bench` instead")
#|pub fn bench(
#| self : T,
#| f : () -> Unit,
#| count? : UInt = 10,
#|) -> Unit raise BenchError {
#| ignore(self)
#| let summary = @bench.single_bench(f, count~)
#| raise BenchError("@BENCH \{summary.to_json().stringify()}\n")
#|}
),
"test.mbt": (
#|fn[T : Show] debug_string(t : T) -> String {
#| let buf = StringBuilder::new(size_hint=50)
#| t.output(buf)
#| buf.to_string()
#|}
#|#callsite(autofill(loc))
#|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~)
#| }
#|}
#|#callsite(autofill(loc))
#|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~)
#| }
#|}
#|#callsite(autofill(loc))
#|pub fn[T] fail(msg : String, loc~ : SourceLoc) -> T raise {
#| @builtin.fail(msg, loc~)
#|}
#|pub fn write(self : T, obj : &Show) -> Unit {
#| self.buffer.write_string(obj.to_string())
#|}
#|pub fn writeln(self : T, obj : &Show) -> Unit {
#| self.write(obj)
#| self.buffer.write_char('\n')
#|}
#|#callsite(autofill(args_loc, loc))
#|pub fn snapshot(
#| self : T,
#| filename~ : String,
#| loc~ : SourceLoc,
#| args_loc~ : ArgsLoc,
#|) -> Unit raise SnapshotError {
#| let loc = loc.to_string().escape()
#| let args_loc = args_loc.to_json().escape()
#| let actual = self.buffer.to_string().escape()
#| let expect = filename.escape()
#| raise SnapshotError(
#| "@SNAPSHOT_TESTING {\"loc\": \{loc}, \"args_loc\": \{args_loc}, \"expect\": \{expect}, \"actual\": \{actual}, \"snapshot\": true}",
#| )
#|}
),
"types.mbt": (
#|#visibility(change_to="abstract")
#|pub(all) struct T {
#| name : String
#| buffer : StringBuilder
#|}
#|pub fn new(name : String) -> T {
#| { name, buffer: StringBuilder::new() }
#|}
),
},
)
///|
let moonbitlang_core_tuple_module : RuntimePackage = RuntimePackage::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,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/quickcheck",
#| "moonbitlang/core/quickcheck/splitmix"
#| ],
#| "test-import": [
#| "moonbitlang/core/char"
#| ]
#|}
),
"deprecated.mbt": (
#|#deprecated
#|#coverage.skip
#|pub fn[T, U] pair(x : T, y : U) -> (T, U) {
#| (x, y)
#|}
#|#deprecated("use `tuple.0` instead")
#|#coverage.skip
#|pub fn[T, U] fst(tuple : (T, U)) -> T {
#| tuple.0
#|}
#|#deprecated("use `tuple.1` instead")
#|#coverage.skip
#|pub fn[T, U] snd(tuple : (T, U)) -> U {
#| tuple.1
#|}
#|#deprecated("use `{ let (a,b) = tuple; (f(a),b) }` instead")
#|#coverage.skip
#|pub fn[T, U, V] map_fst(f : (T) -> U, tuple : (T, V)) -> (U, V) {
#| (f(tuple.0), tuple.1)
#|}
#|#deprecated("use `{ let (a,b) = tuple; (a,f(b)) }` instead")
#|#coverage.skip
#|pub fn[T, U, V] map_snd(f : (T) -> U, tuple : (V, T)) -> (V, U) {
#| (tuple.0, f(tuple.1))
#|}
#|#deprecated("use `{ let (a,b) = tuple; (f(a),f(b)) }` instead")
#|#coverage.skip
#|pub fn[T, U, V, W] map_both(
#| f : (T) -> U,
#| g : (V) -> W,
#| tuple : (T, V),
#|) -> (U, W) {
#| (f(tuple.0), g(tuple.1))
#|}
#|#deprecated
#|#coverage.skip
#|pub fn[T, U] swap(tuple : (T, U)) -> (U, T) {
#| (tuple.1, tuple.0)
#|}
#|#deprecated
#|#coverage.skip
#|pub fn[T, U, V] curry(f : (T, U) -> V) -> (T) -> (U) -> V {
#| (x : T) => (y : U) => f(x, y)
#|}
#|#deprecated
#|#coverage.skip
#|pub fn[T, U, V] uncurry(f : (T) -> (U) -> V) -> (T, U) -> V {
#| (x : T, y : U) => f(x)(y)
#|}
),
"tuple.mbt": "",
"tuple_arbitrary.mbt": (
#|traitalias @quickcheck.Arbitrary
#|pub impl[A : Arbitrary, B : Arbitrary] Arbitrary for (A, B) with arbitrary(
#| size,
#| r0,
#|) {
#| let r1 = r0.split()
#| (Arbitrary::arbitrary(size, r0), Arbitrary::arbitrary(size, r1))
#|}
#|pub impl[A : Arbitrary, B : Arbitrary, C : Arbitrary] Arbitrary for (A, B, C) with arbitrary(
#| size,
#| r0,
#|) {
#| let r1 = r0.split()
#| let (v1, v2) = Arbitrary::arbitrary(size, r1)
#| (Arbitrary::arbitrary(size, r0), v1, v2)
#|}
#|pub impl[A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary] Arbitrary for (
#| A,
#| B,
#| C,
#| D,
#|) with arbitrary(size, r0) {
#| let r1 = r0.split()
#| let (v1, v2, v3) = Arbitrary::arbitrary(size, r1)
#| (Arbitrary::arbitrary(size, r0), v1, v2, v3)
#|}
#|pub impl[
#| A : Arbitrary,
#| B : Arbitrary,
#| C : Arbitrary,
#| D : Arbitrary,
#| E : Arbitrary,
#|] Arbitrary for (A, B, C, D, E) with arbitrary(size, r0) {
#| let r1 = r0.split()
#| let (v1, v2, v3, v4) = Arbitrary::arbitrary(size, r1)
#| (Arbitrary::arbitrary(size, r0), v1, v2, v3, v4)
#|}
#|pub impl[
#| A : Arbitrary,
#| B : Arbitrary,
#| C : Arbitrary,
#| D : Arbitrary,
#| E : Arbitrary,
#| F : Arbitrary,
#|] Arbitrary for (A, B, C, D, E, F) with arbitrary(size, r0) {
#| let r1 = r0.split()
#| let (v1, v2, v3, v4, v5) = Arbitrary::arbitrary(size, r1)
#| (Arbitrary::arbitrary(size, r0), v1, v2, v3, v4, v5)
#|}
#|pub impl[
#| A : Arbitrary,
#| B : Arbitrary,
#| C : Arbitrary,
#| D : Arbitrary,
#| E : Arbitrary,
#| F : Arbitrary,
#| G : Arbitrary,
#|] Arbitrary for (A, B, C, D, E, F, G) with arbitrary(size, r0) {
#| let r1 = r0.split()
#| let (v1, v2, v3, v4, v5, v6) = Arbitrary::arbitrary(size, r1)
#| (Arbitrary::arbitrary(size, r0), v1, v2, v3, v4, v5, v6)
#|}
),
"tuple_default.mbt": (
#|pub impl[A : Default, B : Default] Default for (A, B) with default() {
#| (Default::default(), Default::default())
#|}
#|pub impl[A : Default, B : Default, C : Default] Default for (A, B, C) with default() {
#| (Default::default(), Default::default(), Default::default())
#|}
#|pub impl[A : Default, B : Default, C : Default, D : Default] Default for (
#| A,
#| B,
#| C,
#| D,
#|) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
#|pub impl[A : Default, B : Default, C : Default, D : Default, E : Default] Default for (
#| A,
#| B,
#| C,
#| D,
#| E,
#|) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
#|pub impl[
#| A : Default,
#| B : Default,
#| C : Default,
#| D : Default,
#| E : Default,
#| F : Default,
#|] Default for (A, B, C, D, E, F) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
#|pub impl[
#| A : Default,
#| B : Default,
#| C : Default,
#| D : Default,
#| E : Default,
#| F : Default,
#| G : Default,
#|] Default for (A, B, C, D, E, F, G) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
#|pub impl[
#| A : Default,
#| B : Default,
#| C : Default,
#| D : Default,
#| E : Default,
#| F : Default,
#| G : Default,
#| H : Default,
#|] Default for (A, B, C, D, E, F, G, H) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
#|pub impl[
#| A : Default,
#| B : Default,
#| C : Default,
#| D : Default,
#| E : Default,
#| F : Default,
#| G : Default,
#| H : Default,
#| I : Default,
#|] Default for (A, B, C, D, E, F, G, H, I) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
#|pub impl[
#| A : Default,
#| B : Default,
#| C : Default,
#| D : Default,
#| E : Default,
#| F : Default,
#| G : Default,
#| H : Default,
#| I : Default,
#| J : Default,
#|] Default for (A, B, C, D, E, F, G, H, I, J) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
#|pub impl[
#| A : Default,
#| B : Default,
#| C : Default,
#| D : Default,
#| E : Default,
#| F : Default,
#| G : Default,
#| H : Default,
#| I : Default,
#| J : Default,
#| K : Default,
#|] Default for (A, B, C, D, E, F, G, H, I, J, K) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
#|pub impl[
#| A : Default,
#| B : Default,
#| C : Default,
#| D : Default,
#| E : Default,
#| F : Default,
#| G : Default,
#| H : Default,
#| I : Default,
#| J : Default,
#| K : Default,
#| L : Default,
#|] Default for (A, B, C, D, E, F, G, H, I, J, K, L) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
#|pub impl[
#| A : Default,
#| B : Default,
#| C : Default,
#| D : Default,
#| E : Default,
#| F : Default,
#| G : Default,
#| H : Default,
#| I : Default,
#| J : Default,
#| K : Default,
#| L : Default,
#| M : Default,
#|] Default for (A, B, C, D, E, F, G, H, I, J, K, L, M) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
#|pub impl[
#| A : Default,
#| B : Default,
#| C : Default,
#| D : Default,
#| E : Default,
#| F : Default,
#| G : Default,
#| H : Default,
#| I : Default,
#| J : Default,
#| K : Default,
#| L : Default,
#| M : Default,
#| N : Default,
#|] Default for (A, B, C, D, E, F, G, H, I, J, K, L, M, N) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
#|pub impl[
#| A : Default,
#| B : Default,
#| C : Default,
#| D : Default,
#| E : Default,
#| F : Default,
#| G : Default,
#| H : Default,
#| I : Default,
#| J : Default,
#| K : Default,
#| L : Default,
#| M : Default,
#| N : Default,
#| O : Default,
#|] Default for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
#|pub impl[
#| A : Default,
#| B : Default,
#| C : Default,
#| D : Default,
#| E : Default,
#| F : Default,
#| G : Default,
#| H : Default,
#| I : Default,
#| J : Default,
#| K : Default,
#| L : Default,
#| M : Default,
#| N : Default,
#| O : Default,
#| P : Default,
#|] Default for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) with default() {
#| (
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| Default::default(),
#| )
#|}
),
},
)
///|
let moonbitlang_core_uint_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/uint",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin"]
#|}
),
"uint.mbt": (
#|pub let min_value : UInt = 0U
#|pub let max_value : UInt = 4294967295U
#|pub fn to_int64(self : UInt) -> Int64 {
#| self.to_uint64().reinterpret_as_int64()
#|}
#|pub impl Default for UInt with default() {
#| 0
#|}
#|pub fn default() -> UInt {
#| 0
#|}
#|pub fn to_be_bytes(self : UInt) -> Bytes {
#| [
#| (self >> 24).to_byte(),
#| (self >> 16).to_byte(),
#| (self >> 8).to_byte(),
#| self.to_byte(),
#| ]
#|}
#|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 : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/uint16",
deps={
"moonbitlang/core/builtin": moonbitlang_core_builtin_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
},
files={
"moon.pkg.json": (
#|{
#| "import": [
#| "moonbitlang/core/builtin",
#| "moonbitlang/core/json"
#| ]
#|}
),
"uint16.mbt": (
#|pub let max_value : UInt16 = 65535
#|pub let min_value : UInt16 = 0
#|pub impl Add for UInt16 with add(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() + that.to_int()).to_uint16()
#|}
#|pub impl Add for UInt16 with op_add(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() + that.to_int()).to_uint16()
#|}
#|pub impl Sub for UInt16 with sub(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() - that.to_int()).to_uint16()
#|}
#|pub impl Sub for UInt16 with op_sub(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() - that.to_int()).to_uint16()
#|}
#|pub impl Mul for UInt16 with mul(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() * that.to_int()).to_uint16()
#|}
#|pub impl Mul for UInt16 with op_mul(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() * that.to_int()).to_uint16()
#|}
#|pub impl Div for UInt16 with div(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() / that.to_int()).to_uint16()
#|}
#|pub impl Div for UInt16 with op_div(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() / that.to_int()).to_uint16()
#|}
#|pub impl Mod for UInt16 with mod(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() % that.to_int()).to_uint16()
#|}
#|pub impl Mod for UInt16 with op_mod(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() % that.to_int()).to_uint16()
#|}
#|pub impl Eq for UInt16 with equal(self, that) {
#| self.to_int() == that.to_int()
#|}
#|pub impl Eq for UInt16 with op_equal(self, that) {
#| self.to_int() == that.to_int()
#|}
#|pub impl Compare for UInt16 with compare(self, that) {
#| self.to_int().compare(that.to_int())
#|}
#|pub impl Hash for UInt16 with hash(self) {
#| self.to_int()
#|}
#|pub impl Hash for UInt16 with hash_combine(self, hasher) {
#| hasher.combine_int(self.to_int())
#|}
#|pub impl Shl for UInt16 with shl(self : UInt16, that : Int) -> UInt16 {
#| (self.to_int() << that).to_uint16()
#|}
#|pub impl Shr for UInt16 with shr(self : UInt16, that : Int) -> UInt16 {
#| (self.to_int() >> that).to_uint16()
#|}
#|pub impl BitOr for UInt16 with lor(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() | that.to_int()).to_uint16()
#|}
#|pub impl BitAnd for UInt16 with land(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() & that.to_int()).to_uint16()
#|}
#|pub impl BitXOr for UInt16 with lxor(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() ^ that.to_int()).to_uint16()
#|}
#|pub impl Default for UInt16 with default() {
#| 0
#|}
#|pub impl ToJson for UInt16 with to_json(self : UInt16) -> Json {
#| Json::number(self.to_int().to_double())
#|}
#|pub fn UInt16::to_uint(self : UInt16) -> UInt {
#| self.to_int().reinterpret_as_uint()
#|}
#|pub fn UInt16::to_uint64(self : UInt16) -> UInt64 {
#| self.to_int().to_uint64()
#|}
),
},
)
///|
let moonbitlang_core_uint64_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/uint64",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin"],
#| "test-import": ["moonbitlang/core/double"]
#|}
),
"uint64.mbt": (
#|pub let min_value : UInt64 = 0UL
#|pub let max_value : UInt64 = 18446744073709551615UL
#|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(),
#| ]
#|}
#|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(),
#| ]
#|}
#|test "to_be_bytes" {
#| inspect(
#| max_value.to_be_bytes(),
#| content=(
#| #|b"\xff\xff\xff\xff\xff\xff\xff\xff"
#| ),
#| )
#| inspect(
#| min_value.to_be_bytes(),
#| content=(
#| #|b"\x00\x00\x00\x00\x00\x00\x00\x00"
#| ),
#| )
#| inspect(
#| 0x123456789ABCDEF0UL.to_be_bytes(),
#| content=(
#| #|b"\x12\x34\x56\x78\x9a\xbc\xde\xf0"
#| ),
#| )
#|}
#|test "to_le_bytes" {
#| inspect(
#| max_value.to_le_bytes(),
#| content=(
#| #|b"\xff\xff\xff\xff\xff\xff\xff\xff"
#| ),
#| )
#| inspect(
#| min_value.to_le_bytes(),
#| content=(
#| #|b"\x00\x00\x00\x00\x00\x00\x00\x00"
#| ),
#| )
#| inspect(
#| 0x123456789ABCDEF0UL.to_le_bytes(),
#| content=(
#| #|b"\xf0\xde\xbc\x9a\x78\x56\x34\x12"
#| ),
#| )
#|}
),
},
)
///|
let moonbitlang_core_unit_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/unit",
deps={ "moonbitlang/core/builtin": moonbitlang_core_builtin_module },
files={
"moon.pkg.json": (
#|{
#| "import": ["moonbitlang/core/builtin"]
#|}
),
"unit.mbt": (
#|pub fn Unit::to_string(_ : Self) -> String {
#| "()"
#|}
#|pub impl Hash for Unit with hash(_) -> Int {
#| 0
#|}
#|pub impl Hash for Unit with hash_combine(_, hasher) -> Unit {
#| hasher.combine_unit()
#|}
#|pub impl Default for Unit with default() -> Unit {
#| ()
#|}
#|pub fn default() -> Unit {
#| ()
#|}
#|pub impl Compare for Unit with compare(_, _) {
#| 0
#|}
),
},
)
|