///|
/// 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,
"argparse": moonbitlang_core_argparse_module,
"moonbitlang/core/argparse": moonbitlang_core_argparse_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,
"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,
"debug": moonbitlang_core_debug_module,
"moonbitlang/core/debug": moonbitlang_core_debug_module,
"deque": moonbitlang_core_deque_module,
"moonbitlang/core/deque": moonbitlang_core_deque_module,
"diff": moonbitlang_core_diff_module,
"moonbitlang/core/diff": moonbitlang_core_diff_module,
"double": moonbitlang_core_double_module,
"moonbitlang/core/double": moonbitlang_core_double_module,
"encoding/ascii": moonbitlang_core_encoding_ascii_module,
"moonbitlang/core/encoding/ascii": moonbitlang_core_encoding_ascii_module,
"encoding/base64": moonbitlang_core_encoding_base64_module,
"moonbitlang/core/encoding/base64": moonbitlang_core_encoding_base64_module,
"encoding/hex": moonbitlang_core_encoding_hex_module,
"moonbitlang/core/encoding/hex": moonbitlang_core_encoding_hex_module,
"encoding/percent": moonbitlang_core_encoding_percent_module,
"moonbitlang/core/encoding/percent": moonbitlang_core_encoding_percent_module,
"encoding/utf16": moonbitlang_core_encoding_utf16_module,
"moonbitlang/core/encoding/utf16": moonbitlang_core_encoding_utf16_module,
"encoding/utf8": moonbitlang_core_encoding_utf8_module,
"moonbitlang/core/encoding/utf8": moonbitlang_core_encoding_utf8_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/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/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,
"immut/vector": moonbitlang_core_immut_vector_module,
"moonbitlang/core/immut/vector": moonbitlang_core_immut_vector_module,
"immut/vector_map": moonbitlang_core_immut_vector_map_module,
"moonbitlang/core/immut/vector_map": moonbitlang_core_immut_vector_map_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,
"internal/edit_distance": moonbitlang_core_internal_edit_distance_module,
"moonbitlang/core/internal/edit_distance": moonbitlang_core_internal_edit_distance_module,
"internal/os_string": moonbitlang_core_internal_os_string_module,
"moonbitlang/core/internal/os_string": moonbitlang_core_internal_os_string_module,
"internal/regex_engine/automata": moonbitlang_core_internal_regex_engine_automata_module,
"moonbitlang/core/internal/regex_engine/automata": moonbitlang_core_internal_regex_engine_automata_module,
"internal/regex_engine/shared_types": moonbitlang_core_internal_regex_engine_shared_types_module,
"moonbitlang/core/internal/regex_engine/shared_types": moonbitlang_core_internal_regex_engine_shared_types_module,
"internal/regex_engine/shared_types/rechar_set": moonbitlang_core_internal_regex_engine_shared_types_rechar_set_module,
"moonbitlang/core/internal/regex_engine/shared_types/rechar_set": moonbitlang_core_internal_regex_engine_shared_types_rechar_set_module,
"internal/strconv": moonbitlang_core_internal_strconv_module,
"moonbitlang/core/internal/strconv": moonbitlang_core_internal_strconv_module,
"json": moonbitlang_core_json_module,
"moonbitlang/core/json": moonbitlang_core_json_module,
"lazy": moonbitlang_core_lazy_module,
"moonbitlang/core/lazy": moonbitlang_core_lazy_module,
"lazy_list": moonbitlang_core_lazy_list_module,
"moonbitlang/core/lazy_list": moonbitlang_core_lazy_list_module,
"lexbuf": moonbitlang_core_lexbuf_module,
"moonbitlang/core/lexbuf": moonbitlang_core_lexbuf_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/shrink": moonbitlang_core_quickcheck_shrink_module,
"moonbitlang/core/quickcheck/shrink": moonbitlang_core_quickcheck_shrink_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,
"range": moonbitlang_core_range_module,
"moonbitlang/core/range": moonbitlang_core_range_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,
"string": moonbitlang_core_string_module,
"moonbitlang/core/string": moonbitlang_core_string_module,
"string/internal/regex_engine": moonbitlang_core_string_internal_regex_engine_module,
"moonbitlang/core/string/internal/regex_engine": moonbitlang_core_string_internal_regex_engine_module,
"string/internal/regex_engine/ast": moonbitlang_core_string_internal_regex_engine_ast_module,
"moonbitlang/core/string/internal/regex_engine/ast": moonbitlang_core_string_internal_regex_engine_ast_module,
"string/internal/regex_engine/symbol_map": moonbitlang_core_string_internal_regex_engine_symbol_map_module,
"moonbitlang/core/string/internal/regex_engine/symbol_map": moonbitlang_core_string_internal_regex_engine_symbol_map_module,
"string/internal/regex_parser": moonbitlang_core_string_internal_regex_parser_module,
"moonbitlang/core/string/internal/regex_parser": moonbitlang_core_string_internal_regex_parser_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,
"v128": moonbitlang_core_v128_module,
"moonbitlang/core/v128": moonbitlang_core_v128_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={
"abort.mbt": (
#|#cfg(not(target="native"))
#|pub fn[T] abort(msg : String) -> T {
#| let _ = msg
#| panic_impl()
#|}
#|#cfg(target="native")
#|fn println(s : String) -> Unit = "%println"
#|#cfg(target="native")
#|pub fn[T] abort(msg : String) -> T {
#| println(msg)
#| panic_impl()
#|}
#|fn[T] panic_impl() -> T = "%panic"
),
},
)
///|
let moonbitlang_core_argparse_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/argparse",
deps={},
files={
"arg_action.mbt": (
#|fn arg_min_max_for_validate(arg : Arg) -> (Int, Int?) raise ArgBuildError {
#| if arg.info is PositionalInfo(num_args=Some(range), ..) {
#| if range.lower < 0 {
#| raise Unsupported("min values must be >= 0")
#| }
#| if range.upper is Some(max_value) {
#| if max_value < 0 {
#| raise Unsupported("max values must be >= 0")
#| }
#| if max_value < range.lower {
#| raise Unsupported("max values must be >= min values")
#| }
#| if range.lower == 0 && max_value == 0 {
#| raise Unsupported("empty value range (0..0) is unsupported")
#| }
#| }
#| (range.lower, range.upper)
#| } else {
#| (0, None)
#| }
#|}
#|fn arg_min_max(arg : Arg) -> (Int, Int?) {
#| match arg.info {
#| PositionalInfo(num_args=Some(range), ..) => (range.lower, range.upper)
#| _ => (0, None)
#| }
#|}
),
"arg_group.mbt": (
#|struct ArgGroup {
#| name : String
#| required : Bool
#| multiple : Bool
#| args : Array[String]
#| requires : Array[String]
#| conflicts_with : Array[String]
#|} derive(@debug.Debug)
#|#alias(new, deprecated="Use `ArgGroup()` instead")
#|pub fn ArgGroup::ArgGroup(
#| name : StringView,
#| required? : Bool = false,
#| multiple? : Bool = true,
#| args? : ArrayView[String] = [],
#| requires? : ArrayView[String] = [],
#| conflicts_with? : ArrayView[String] = [],
#|) -> ArgGroup {
#| {
#| name: name.to_owned(),
#| required,
#| multiple,
#| args: args.to_owned(),
#| requires: requires.to_owned(),
#| conflicts_with: conflicts_with.to_owned(),
#| }
#|}
),
"arg_spec.mbt": (
#|pub(all) enum FlagAction {
#| SetTrue
#| SetFalse
#| Count
#| Help
#| Version
#|} derive(Eq, @debug.Debug)
#|pub(all) enum OptionAction {
#| Set
#| Append
#|} derive(Eq, @debug.Debug)
#|priv struct Arg {
#| name : String
#| about : String?
#| env : String?
#| requires : Array[String]
#| conflicts_with : Array[String]
#| required : Bool
#| global : Bool
#| hidden : Bool
#| info : ArgInfo
#| multiple : Bool
#|} derive(@debug.Debug)
#|priv enum ArgInfo {
#| FlagInfo(
#| short~ : Char?,
#| long~ : String?,
#| action~ : FlagAction,
#| negatable~ : Bool
#| )
#| OptionInfo(
#| short~ : Char?,
#| long~ : String?,
#| action~ : OptionAction,
#| default_values~ : Array[String]?,
#| allow_hyphen_values~ : Bool
#| )
#| PositionalInfo(
#| num_args~ : ValueRange?,
#| default_values~ : Array[String]?,
#| allow_hyphen_values~ : Bool
#| )
#|} derive(@debug.Debug)
#|pub struct FlagArg {
#| priv arg : Arg
#|} derive(@debug.Debug)
#|#alias(new, deprecated="Use `FlagArg()` instead")
#|pub fn FlagArg::FlagArg(
#| name : StringView,
#| short? : Char,
#| long? : StringView = name,
#| about? : StringView,
#| action? : FlagAction = SetTrue,
#| env? : StringView,
#| requires? : ArrayView[String] = [],
#| conflicts_with? : ArrayView[String] = [],
#| required? : Bool = false,
#| global? : Bool = false,
#| negatable? : Bool = false,
#| hidden? : Bool = false,
#|) -> FlagArg {
#| let name = name.to_owned()
#| let long = if long == "" { None } else { Some(long.to_owned()) }
#| let about = about.map(v => v.to_owned())
#| let env = env.map(v => v.to_owned())
#| {
#| arg: {
#| name,
#| about,
#| env,
#| global,
#| hidden,
#| requires: requires.to_owned(),
#| conflicts_with: conflicts_with.to_owned(),
#| required,
#| info: FlagInfo(short~, long~, action~, negatable~),
#| multiple: false,
#| },
#| }
#|}
#|pub struct OptionArg {
#| priv arg : Arg
#|} derive(@debug.Debug)
#|#alias(new, deprecated="Use `OptionArg()` instead")
#|pub fn OptionArg::OptionArg(
#| name : StringView,
#| short? : Char,
#| long? : StringView = name,
#| about? : StringView,
#| action? : OptionAction = Set,
#| env? : StringView,
#| default_values? : ArrayView[String],
#| allow_hyphen_values? : Bool = false,
#| requires? : ArrayView[String] = [],
#| conflicts_with? : ArrayView[String] = [],
#| required? : Bool = false,
#| global? : Bool = false,
#| hidden? : Bool = false,
#|) -> OptionArg {
#| let name = name.to_owned()
#| let long = if long == "" { None } else { Some(long.to_owned()) }
#| let about = about.map(v => v.to_owned())
#| let env = env.map(v => v.to_owned())
#| {
#| arg: {
#| name,
#| about,
#| env,
#| requires: requires.to_owned(),
#| conflicts_with: conflicts_with.to_owned(),
#| required,
#| global,
#| hidden,
#| info: OptionInfo(
#| short~,
#| long~,
#| action~,
#| default_values=default_values.map(values => values.to_owned()),
#| allow_hyphen_values~,
#| ),
#| multiple: action is Append,
#| },
#| }
#|}
#|pub struct PositionArg {
#| priv arg : Arg
#|} derive(@debug.Debug)
#|#alias(new, deprecated="Use `PositionArg()` instead")
#|pub fn PositionArg::PositionArg(
#| name : StringView,
#| about? : StringView,
#| env? : StringView,
#| default_values? : ArrayView[String],
#| num_args? : ValueRange,
#| allow_hyphen_values? : Bool = false,
#| requires? : ArrayView[String] = [],
#| conflicts_with? : ArrayView[String] = [],
#| global? : Bool = false,
#| hidden? : Bool = false,
#|) -> PositionArg {
#| let name = name.to_owned()
#| let about = about.map(v => v.to_owned())
#| let env = env.map(v => v.to_owned())
#| {
#| arg: {
#| name,
#| about,
#| env,
#| requires: requires.to_owned(),
#| conflicts_with: conflicts_with.to_owned(),
#| required: false,
#| global,
#| hidden,
#| info: PositionalInfo(
#| num_args~,
#| default_values=default_values.map(values => values.to_owned()),
#| allow_hyphen_values~,
#| ),
#| multiple: range_allows_multiple(num_args),
#| },
#| }
#|}
#|fn range_allows_multiple(range : ValueRange?) -> Bool {
#| range is Some(r) &&
#| (match r.upper {
#| Some(upper) => upper > 1
#| None => true
#| })
#|}
#|impl Show for FlagAction with fn to_string(self) {
#| match self {
#| SetTrue => "SetTrue"
#| SetFalse => "SetFalse"
#| Count => "Count"
#| Help => "Help"
#| Version => "Version"
#| }
#|}
#|impl Show for OptionAction with fn to_string(self) {
#| match self {
#| Set => "Set"
#| Append => "Append"
#| }
#|}
),
"command.mbt": (
#|pub struct Command {
#| priv name : String
#| priv args : Array[Arg]
#| priv groups : Array[ArgGroup]
#| priv subcommands : Array[Command]
#| priv about : String?
#| priv version : String?
#| priv disable_help_flag : Bool
#| priv disable_version_flag : Bool
#| priv disable_help_subcommand : Bool
#| priv arg_required_else_help : Bool
#| priv subcommand_required : Bool
#| priv default_subcommand : String?
#| priv hidden : Bool
#| priv mut build_error : ArgBuildError?
#|} derive(@debug.Debug)
#|#alias(new, deprecated="Use `Command()` instead")
#|pub fn Command::Command(
#| name : StringView,
#| flags? : ArrayView[FlagArg] = [],
#| options? : ArrayView[OptionArg] = [],
#| positionals? : ArrayView[PositionArg] = [],
#| subcommands? : ArrayView[Command] = [],
#| about? : StringView,
#| version? : StringView,
#| disable_help_flag? : Bool = false,
#| disable_version_flag? : Bool = false,
#| disable_help_subcommand? : Bool = false,
#| arg_required_else_help? : Bool = false,
#| subcommand_required? : Bool = false,
#| hidden? : Bool = false,
#| groups? : ArrayView[ArgGroup] = [],
#| default_subcommand? : StringView,
#|) -> Command {
#| let (parsed_args, arg_error) = collect_args(flags, options, positionals)
#| let groups = groups.to_owned()
#| let cmd = Command::{
#| name: name.to_owned(),
#| args: parsed_args,
#| groups,
#| subcommands: subcommands.to_owned(),
#| about: about.map(v => v.to_owned()),
#| version: version.map(v => v.to_owned()),
#| disable_help_flag,
#| disable_version_flag,
#| disable_help_subcommand,
#| arg_required_else_help,
#| subcommand_required,
#| default_subcommand: default_subcommand.map(v => v.to_owned()),
#| hidden,
#| build_error: arg_error,
#| }
#| if cmd.build_error is None {
#| validate_command(cmd, parsed_args, groups, []) catch {
#| err => cmd.build_error = Some(err)
#| }
#| }
#| cmd
#|}
#|pub fn Command::render_help(self : Command) -> String {
#| render_help(self)
#|}
#|#as_free_fn
#|pub fn Command::parse(
#| self : Command,
#| argv? : ArrayView[String] = default_argv(),
#| env? : Map[String, String] = Map([]),
#|) -> Matches raise {
#| try {
#| let raw = parse_command(self, argv, env, [], Map([]), Map([]), self.name)
#| build_matches(self, raw, [])
#| } catch {
#| DisplayHelp::Message(text) => print_and_exit_success(text)
#| DisplayVersion::Message(text) => print_and_exit_success(text)
#| ArgError::Message(_) as err => raise err
#| err => {
#| println(err.to_string())
#| panic()
#| }
#| }
#|}
#|fn build_matches(
#| cmd : Command,
#| raw : Matches,
#| inherited_globals : Array[Arg],
#|) -> Matches {
#| let flags = Map([])
#| let values = Map([])
#| let flag_counts = Map([])
#| let sources = Map([])
#| let specs = inherited_globals + cmd.args
#| for spec in specs {
#| let name = spec.name
#| if raw.values.get(name) is Some(vs) {
#| values[name] = vs.copy()
#| }
#| let count = raw.counts.get_or_default(name, 0)
#| if count > 0 {
#| flag_counts[name] = count
#| }
#| let source = match raw.flag_sources.get(name) {
#| Some(v) => Some(v)
#| None => raw.value_sources.get(name)
#| }
#| if source is Some(source) {
#| sources[name] = source
#| if spec.info is FlagInfo(action~, ..) {
#| if action is Count {
#| flags[name] = count > 0
#| } else {
#| flags[name] = raw.flags.get(name).unwrap_or(false)
#| }
#| }
#| }
#| }
#| let child_globals = merge_global_defs(
#| inherited_globals,
#| collect_globals(cmd.args),
#| )
#| let subcommand = match raw.parsed_subcommand {
#| Some((name, sub_raw)) =>
#| if find_decl_subcommand(cmd.subcommands, name) is Some(sub_spec) {
#| Some((name, build_matches(sub_spec, sub_raw, child_globals)))
#| } else {
#| Some(
#| (
#| name,
#| {
#| flags: Map([]),
#| values: Map([]),
#| flag_counts: Map([]),
#| sources: Map([]),
#| subcommand: None,
#| counts: Map([]),
#| flag_sources: Map([]),
#| value_sources: Map([]),
#| parsed_subcommand: None,
#| },
#| ),
#| )
#| }
#| None => None
#| }
#| {
#| flags,
#| values,
#| flag_counts,
#| sources,
#| subcommand,
#| counts: Map([]),
#| flag_sources: Map([]),
#| value_sources: Map([]),
#| parsed_subcommand: None,
#| }
#|}
#|fn find_decl_subcommand(subs : Array[Command], name : String) -> Command? {
#| for sub in subs {
#| if sub.name == name {
#| return Some(sub)
#| }
#| }
#| None
#|}
#|fn collect_args(
#| flags : ArrayView[FlagArg],
#| options : ArrayView[OptionArg],
#| positionals : ArrayView[PositionArg],
#|) -> (Array[Arg], ArgBuildError?) {
#| let args : Array[Arg] = []
#| for flag in flags {
#| args.push(flag.arg)
#| }
#| for option in options {
#| args.push(option.arg)
#| }
#| for positional in positionals {
#| args.push(positional.arg)
#| }
#| let ctx = ValidationCtx::new()
#| let first_error : ArgBuildError? = for
#| flag in flags
#| first_error = (None : ArgBuildError?) {
#| validate_flag_arg(flag.arg, ctx) catch {
#| err => if first_error is None { continue Some(err) }
#| }
#| continue first_error
#| } nobreak {
#| first_error
#| }
#| let first_error : ArgBuildError? = for
#| option in options
#| first_error = first_error {
#| validate_option_arg(option.arg, ctx) catch {
#| err => if first_error is None { continue Some(err) }
#| }
#| continue first_error
#| } nobreak {
#| first_error
#| }
#| let first_error : ArgBuildError? = for
#| positional in positionals
#| first_error = first_error {
#| validate_positional_arg(positional.arg, ctx) catch {
#| err => if first_error is None { continue Some(err) }
#| }
#| continue first_error
#| } nobreak {
#| first_error
#| }
#| let first_error = if first_error is None {
#| try {
#| ctx.finalize()
#| None
#| } catch {
#| err => Some(err)
#| }
#| } else {
#| first_error
#| }
#| (args, first_error)
#|}
),
"error.mbt": (
#|priv suberror ArgError {
#| Message(String)
#|}
#|impl Show for ArgError with fn output(self : ArgError, logger) {
#| match self {
#| Message(msg) => logger.write_string(msg)
#| }
#|}
#|impl @debug.Debug for ArgError with fn to_repr(self) {
#| match self {
#| Message(msg) => @debug.Repr::literal(msg)
#| }
#|}
#|test "ArgError debug keeps display text" {
#| let err : Error = ArgError::Message(
#| (
#| $|error: unexpected argument '--bad' found
#| $|
#| $|Usage: demo [options]
#| ),
#| )
#| inspect(
#| err.to_string(),
#| content=(
#| #|error: unexpected argument '--bad' found
#| #|
#| #|Usage: demo [options]
#| ),
#| )
#|}
#|priv suberror ArgParseError {
#| UnknownArgument(String, String?)
#| InvalidArgument(String)
#| MissingValue(String)
#| MissingRequired(String, String?)
#| TooFewValues(String, Int, Int)
#| TooManyValues(String, Int, Int)
#| TooManyPositionals(String, String?)
#| InvalidValue(String)
#| MissingGroup(String)
#| GroupConflict(String)
#|}
#|fn ArgParseError::arg_parse_error_message(self : ArgParseError) -> String {
#| match self {
#| UnknownArgument(arg, Some(hint)) =>
#| (
#| $|error: unexpected argument '\{arg}' found
#| $|
#| $| tip: a similar argument exists: '\{hint}'
#| )
#| UnknownArgument(arg, None) => "error: unexpected argument '\{arg}' found"
#| InvalidArgument(arg) =>
#| if arg.has_prefix("-") {
#| "error: unexpected argument '\{arg}' found"
#| } else {
#| "error: \{arg}"
#| }
#| MissingValue(arg) =>
#| "error: a value is required for '\{arg}' but none was supplied"
#| MissingRequired(name, by) =>
#| if by is Some(source) {
#| "error: the following required argument was not provided: '\{name}' (required by '\{source}')"
#| } else {
#| "error: the following required argument was not provided: '\{name}'"
#| }
#| TooFewValues(name, got, min) =>
#| "error: '\{name}' requires at least \{min} values but only \{got} were provided"
#| TooManyValues(name, got, max) =>
#| "error: '\{name}' allows at most \{max} values but \{got} were provided"
#| TooManyPositionals(value, Some(arg)) =>
#| "error: unexpected value '\{value}' for '\{arg}' found; no more were expected"
#| TooManyPositionals(value, None) =>
#| "error: unexpected value '\{value}' found; no more were expected"
#| InvalidValue(msg) => "error: \{msg}"
#| MissingGroup(name) =>
#| "error: the following required argument group was not provided: '\{name}'"
#| GroupConflict(name) => "error: group conflict \{name}"
#| }
#|}
#|priv suberror ArgBuildError {
#| Unsupported(String)
#|} derive(@debug.Debug)
#|priv suberror DisplayHelp {
#| Message(String)
#|}
#|priv suberror DisplayVersion {
#| Message(String)
#|}
),
"extends.mbt": (
#|pub extend FlagAction with Eq::{equal}
#|pub extend FlagAction with Show::{to_string}
#|pub extend OptionAction with Eq::{equal}
#|pub extend OptionAction with Show::{to_string}
#|pub extend ValueRange with Eq::{equal}
#|pub extend ValueRange with Show::{to_string}
#|pub extend ValueSource with Eq::{equal}
#|pub extend ValueSource with Show::{to_string}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ArgGroup with @debug.Debug::{to_repr}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Command with @debug.Debug::{to_repr}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend FlagAction with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend FlagAction with Eq::{not_equal}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend FlagAction with Show::{output}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend FlagArg with @debug.Debug::{to_repr}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Matches with @debug.Debug::{to_repr}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend OptionAction with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend OptionAction with Eq::{not_equal}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend OptionAction with Show::{output}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend OptionArg with @debug.Debug::{to_repr}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend PositionArg with @debug.Debug::{to_repr}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ValueRange with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ValueRange with Eq::{not_equal}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ValueRange with Show::{output}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ValueSource with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ValueSource with Eq::{not_equal}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ValueSource with Show::{output}
),
"help_render.mbt": (
#|fn render_help(cmd : Command) -> String {
#| render_help_with_usage_override(cmd, None)
#|}
#|fn render_help_with_usage_override(
#| cmd : Command,
#| usage_line : String?,
#|) -> String {
#| let usage_line = usage_line.unwrap_or("Usage: \{cmd.name}\{usage_tail(cmd)}")
#| let about = cmd.about.unwrap_or("")
#| let about_section = if about == "" {
#| ""
#| } else {
#| (
#| $|
#| $|
#| $|\{about}
#| )
#| }
#| let commands_section = render_section("Commands:", subcommand_entries(cmd))
#| let arguments_section = render_section("Arguments:", positional_entries(cmd))
#| let options_section = render_section(
#| "Options:",
#| option_entries(cmd),
#| keep_empty=true,
#| )
#| let groups_section = render_section("Groups:", group_entries(cmd))
#| (
#| $|\{usage_line}\{about_section}\{commands_section}\{arguments_section}\{options_section}\{groups_section}
#| $|
#| )
#|}
#|fn usage_tail(cmd : Command) -> String {
#| let parts = [
#| required_option_usage(cmd),
#| if has_options(cmd) {
#| "[options]"
#| } else {
#| ""
#| },
#| positional_usage(cmd),
#| subcommand_usage(cmd),
#| ].filter(p => p != "")
#| if parts.is_empty() {
#| ""
#| } else {
#| " " + parts.join(" ")
#| }
#|}
#|fn subcommand_usage(cmd : Command) -> String {
#| if !has_subcommands_for_help(cmd) {
#| return ""
#| }
#| if cmd.subcommand_required {
#| ""
#| } else {
#| "[command]"
#| }
#|}
#|fn has_options(cmd : Command) -> Bool {
#| cmd.args.any(arg => {
#| !arg.hidden &&
#| arg.info is (OptionInfo(long~, short~, ..) | FlagInfo(long~, short~, ..)) &&
#| (long is Some(_) || short is Some(_)) &&
#| !is_required_arg(arg)
#| })
#|}
#|fn required_option_usage(cmd : Command) -> String {
#| [
#| for arg in cmd.args if !(arg.hidden ||
#| !is_required_arg(arg) ||
#| arg.info is PositionalInfo(_)) &&
#| required_option_token(arg) is Some(token) => token
#| ].join(" ")
#|}
#|fn required_option_token(arg : Arg) -> String? {
#| let prefix = match arg.info {
#| OptionInfo(long~, short~, ..) | FlagInfo(long~, short~, ..) =>
#| if long is Some(long) {
#| Some("--\{long}")
#| } else if short is Some(short) {
#| Some("-\{short}")
#| } else {
#| None
#| }
#| PositionalInfo(_) => None
#| }
#| match prefix {
#| Some(prefix) =>
#| if arg.info is OptionInfo(_) {
#| Some("\{prefix} <\{arg.name}>")
#| } else {
#| Some(prefix)
#| }
#| None => None
#| }
#|}
#|fn positional_usage(cmd : Command) -> String {
#| let parts = Array(capacity=cmd.args.length())
#| for arg in positional_args(cmd.args) {
#| if arg.hidden {
#| continue
#| }
#| let required = is_required_arg(arg)
#| if arg.multiple {
#| if required {
#| parts.push("<\{arg.name}...>")
#| } else {
#| parts.push("[\{arg.name}...]")
#| }
#| } else if required {
#| parts.push("<\{arg.name}>")
#| } else {
#| parts.push("[\{arg.name}]")
#| }
#| }
#| parts.join(" ")
#|}
#|fn option_entries(cmd : Command) -> Array[String] {
#| let args = cmd.args
#| let display = Array(capacity=args.length() + 2)
#| let builtin_help_short = help_flag_enabled(cmd) &&
#| !has_short_option(args, 'h')
#| let builtin_help_long = help_flag_enabled(cmd) &&
#| !has_long_option(args, "help")
#| let builtin_version_short = version_flag_enabled(cmd) &&
#| !has_short_option(args, 'V')
#| let builtin_version_long = version_flag_enabled(cmd) &&
#| !has_long_option(args, "version")
#| let builtin_help_label = builtin_option_label(
#| builtin_help_short, builtin_help_long, "-h", "--help",
#| )
#| if builtin_help_label is Some(label) {
#| display.push((label, "Show help information."))
#| }
#| let builtin_version_label = builtin_option_label(
#| builtin_version_short, builtin_version_long, "-V", "--version",
#| )
#| if builtin_version_label is Some(label) {
#| display.push((label, "Show version information."))
#| }
#| for arg in args {
#| guard arg.info
#| is (OptionInfo(long~, short~, ..) | FlagInfo(long~, short~, ..)) &&
#| (long is Some(_) || short is Some(_)) else {
#| continue
#| }
#| if arg.hidden {
#| continue
#| }
#| let name = if arg.info is OptionInfo(_) {
#| "\{arg_display(arg)} <\{arg.name}>"
#| } else {
#| arg_display(arg)
#| }
#| display.push((name, arg_doc(arg)))
#| }
#| format_entries(display)
#|}
#|fn has_long_option(args : Array[Arg], name : String) -> Bool {
#| args.any(arg => {
#| arg.info is (OptionInfo(long~, ..) | FlagInfo(long~, ..)) &&
#| long is Some(long) &&
#| long == name
#| })
#|}
#|fn has_short_option(args : Array[Arg], value : Char) -> Bool {
#| args.any(arg => {
#| arg.info is (OptionInfo(short~, ..) | FlagInfo(short~, ..)) &&
#| short is Some(short) &&
#| short == value
#| })
#|}
#|fn builtin_option_label(
#| has_short : Bool,
#| has_long : Bool,
#| short_label : String,
#| long_label : String,
#|) -> String? {
#| if has_short && has_long {
#| Some("\{short_label}, \{long_label}")
#| } else if has_short {
#| Some(short_label)
#| } else if has_long {
#| Some(long_label)
#| } else {
#| None
#| }
#|}
#|fn positional_entries(cmd : Command) -> Array[String] {
#| format_entries(
#| [
#| for arg in positional_args(cmd.args) if !arg.hidden => {
#| (positional_display(arg), arg_doc(arg))
#| }
#| ],
#| )
#|}
#|fn subcommand_entries(cmd : Command) -> Array[String] {
#| let display = [
#| for sub in cmd.subcommands if !sub.hidden => {
#| let doc = sub.about.unwrap_or("")
#| let doc = if cmd.default_subcommand is Some(name) && name == sub.name {
#| if doc == "" {
#| "(default)"
#| } else {
#| "\{doc} (default)"
#| }
#| } else {
#| doc
#| }
#| (sub.name, doc)
#| }
#| ]
#| if help_subcommand_enabled(cmd) {
#| display.push(("help", "Print help for the subcommand(s)."))
#| }
#| format_entries(display)
#|}
#|fn group_entries(cmd : Command) -> Array[String] {
#| let display = Array(capacity=cmd.groups.length())
#| for group in cmd.groups {
#| let members = group_members(cmd, group)
#| if members == "" {
#| continue
#| }
#| display.push((group_label(group), members))
#| }
#| format_entries(display)
#|}
#|fn render_section(
#| header : String,
#| lines : Array[String],
#| keep_empty? : Bool = false,
#|) -> String {
#| if lines.is_empty() {
#| if keep_empty {
#| (
#| $|
#| $|
#| $|\{header}
#| )
#| } else {
#| ""
#| }
#| } else {
#| let body = lines.join("\n")
#| (
#| $|
#| $|
#| $|\{header}
#| $|\{body}
#| )
#| }
#|}
#|fn format_entries(display : Array[(String, String)]) -> Array[String] {
#| let max_len = display.fold(init=0, (acc, item) => acc.max(item.0.length()))
#| fn fmt(name : String, doc : String) -> String {
#| let padding = " ".repeat(max_len - name.length() + 2)
#| " \{name}\{padding}\{doc}"
#| }
#| [
#| for item in display => fmt(item.0, item.1)
#| ]
#|}
#|fn arg_display(arg : Arg) -> String {
#| let parts = Array(capacity=2)
#| let (short, long) = match arg.info {
#| OptionInfo(short~, long~, ..)
#| | FlagInfo(short~, long~, ..)
#| | (PositionalInfo(_) with short = None, long = None) => (short, long)
#| }
#| if short is Some(short) {
#| parts.push("-\{short}")
#| }
#| if long is Some(long) {
#| if arg.info is FlagInfo(negatable=true, ..) {
#| parts.push("--[no-]\{long}")
#| } else {
#| parts.push("--\{long}")
#| }
#| }
#| if parts.is_empty() {
#| arg.name
#| } else {
#| parts.join(", ")
#| }
#|}
#|fn positional_display(arg : Arg) -> String {
#| if arg.multiple {
#| "\{arg.name}..."
#| } else {
#| arg.name
#| }
#|}
#|fn arg_doc(arg : Arg) -> String {
#| let notes = []
#| if arg.env is Some(env_name) {
#| notes.push("[env: \{env_name}]")
#| }
#| if arg.info
#| is (OptionInfo(default_values~, ..) | PositionalInfo(default_values~, ..)) &&
#| default_values is Some(values) {
#| if !values.is_empty() {
#| let defaults = values.join(", ")
#| notes.push("[default: \{defaults}]")
#| }
#| }
#| let help = arg.about.unwrap_or("")
#| if help == "" {
#| notes.join(" ")
#| } else if !notes.is_empty() {
#| let notes_text = notes.join(" ")
#| "\{help} \{notes_text}"
#| } else {
#| help
#| }
#|}
#|fn has_subcommands_for_help(cmd : Command) -> Bool {
#| help_subcommand_enabled(cmd) || cmd.subcommands.any(sub => !sub.hidden)
#|}
#|fn is_required_arg(arg : Arg) -> Bool {
#| if arg.required {
#| true
#| } else {
#| let (min, _) = arg_min_max(arg)
#| min > 0
#| }
#|}
#|fn group_label(group : ArgGroup) -> String {
#| let tags = []
#| if group.required {
#| tags.push("[required]")
#| }
#| if !group.multiple {
#| tags.push("[exclusive]")
#| }
#| if tags.is_empty() {
#| group.name
#| } else {
#| let tags_text = tags.join(" ")
#| "\{group.name} \{tags_text}"
#| }
#|}
#|fn group_members(cmd : Command, group : ArgGroup) -> String {
#| [
#| for arg in cmd.args if !arg.hidden && arg_in_group(arg, group) => {
#| group_member_display(arg)
#| }
#| ].join(", ")
#|}
#|fn group_member_display(arg : Arg) -> String {
#| let base = arg_display(arg)
#| match arg.info {
#| FlagInfo(_) => base
#| OptionInfo(_) => "\{base} <\{arg.name}>"
#| PositionalInfo(_) => base
#| }
#|}
),
"matches.mbt": (
#|#warnings("-deprecated_syntax")
#|pub enum ValueSource {
#| Argv
#| Env
#| Default
#|} derive(Eq, Show, @debug.Debug)
#|pub struct Matches {
#| flags : Map[String, Bool]
#| values : Map[String, Array[String]]
#| flag_counts : Map[String, Int]
#| sources : Map[String, ValueSource]
#| subcommand : (String, Matches)?
#| priv counts : Map[String, Int]
#| priv flag_sources : Map[String, ValueSource]
#| priv value_sources : Map[String, ValueSource]
#| priv mut parsed_subcommand : (String, Matches)?
#|} derive(@debug.Debug)
#|fn new_matches_parse_state() -> Matches {
#| {
#| flags: Map([]),
#| values: Map([]),
#| flag_counts: Map([]),
#| sources: Map([]),
#| subcommand: None,
#| counts: Map([]),
#| flag_sources: Map([]),
#| value_sources: Map([]),
#| parsed_subcommand: None,
#| }
#|}
),
"parser.mbt": (
#|fn raise_help(text : String) -> Unit raise DisplayHelp {
#| raise Message(text)
#|}
#|fn raise_version(text : String) -> Unit raise DisplayVersion {
#| raise Message(text)
#|}
#|fn[T] raise_unknown_long(
#| name : StringView,
#| long_index : Map[String, Arg],
#|) -> T raise ArgParseError {
#| let hint = suggest_long(name, long_index)
#| raise UnknownArgument("--\{name}", hint)
#|}
#|fn[T] raise_unknown_short(
#| short : Char,
#| short_index : Map[Char, Arg],
#|) -> T raise ArgParseError {
#| let hint = suggest_short(short, short_index)
#| raise UnknownArgument("-\{short}", hint)
#|}
#|fn[T] raise_subcommand_conflict(name : String) -> T raise ArgParseError {
#| raise InvalidArgument(
#| "subcommand '\{name}' cannot be used with positional arguments",
#| )
#|}
#|fn help_context_command(
#| cmd : Command,
#| inherited_globals : Array[Arg],
#| command_path : String,
#|) -> Command {
#| let help_name = if command_path == "" { cmd.name } else { command_path }
#| { ..cmd, args: inherited_globals + cmd.args, name: help_name, }
#|}
#|fn render_help_for_context(
#| cmd : Command,
#| inherited_globals : Array[Arg],
#| command_path : String,
#|) -> String {
#| let help_cmd = help_context_command(cmd, inherited_globals, command_path)
#| render_help(help_cmd)
#|}
#|fn raise_context_help(
#| cmd : Command,
#| inherited_globals : Array[Arg],
#| command_path : String,
#|) -> Unit raise DisplayHelp {
#| raise_help(render_help_for_context(cmd, inherited_globals, command_path))
#|}
#|#cfg(target="js")
#|fn default_argv() -> ArrayView[String] {
#| match @env.args() {
#| [_, _, .. rest] => rest
#| _ => []
#| }
#|}
#|#cfg(not(target="js"))
#|fn default_argv() -> ArrayView[String] {
#| let args = @env.args()
#| match args {
#| [_, .. rest] => rest
#| [] => []
#| }
#|}
#|fn merge_global_defs(
#| inherited_globals : Array[Arg],
#| globals_here : Array[Arg],
#|) -> Array[Arg] {
#| let merged = inherited_globals.copy()
#| for global in globals_here {
#| match merged.search_by(arg => arg.name == global.name) {
#| Some(idx) => merged[idx] = global
#| None => merged.push(global)
#| }
#| }
#| merged
#|}
#|fn env_resolution_args(
#| inherited_globals : Array[Arg],
#| args : Array[Arg],
#|) -> Array[Arg] {
#| let merged_globals = merge_global_defs(
#| inherited_globals,
#| collect_globals(args),
#| )
#| let local_only = args.filter(arg => {
#| !(arg.global && arg.info is (FlagInfo(_) | OptionInfo(_)))
#| })
#| merged_globals + local_only
#|}
#|fn format_error_with_help(
#| msg : String,
#| cmd : Command,
#| inherited_globals : Array[Arg],
#| command_path : String,
#|) -> String {
#| (
#| $|\{msg}
#| $|
#| $|\{render_help_for_context(cmd, inherited_globals, command_path)}
#| )
#|}
#|fn arg_usage_token_for_group(arg : Arg) -> String {
#| let base = match arg.info {
#| OptionInfo(long~, short~, ..) | FlagInfo(long~, short~, ..) =>
#| if long is Some(long) {
#| "--\{long}"
#| } else if short is Some(short) {
#| "-\{short}"
#| } else {
#| arg.name
#| }
#| PositionalInfo(_) =>
#| if arg.multiple {
#| "<\{arg.name}...>"
#| } else {
#| "<\{arg.name}>"
#| }
#| }
#| if arg.info is OptionInfo(_) {
#| "\{base} <\{arg.name}>"
#| } else {
#| base
#| }
#|}
#|fn group_usage_expr(
#| groups : Array[ArgGroup],
#| args : Array[Arg],
#| name : String,
#|) -> String? {
#| for group in groups {
#| if group.name != name {
#| continue
#| }
#| let members = [
#| for member_name in group.args if args.search_by(arg => {
#| arg.name == member_name
#| })
#| is Some(idx) &&
#| !args[idx].hidden => arg_usage_token_for_group(args[idx])
#| ]
#| if members.is_empty() {
#| return None
#| }
#| let joined = members.join("|")
#| return Some("<\{joined}>")
#| }
#| None
#|}
#|fn missing_group_error_message(
#| cmd : Command,
#| inherited_globals : Array[Arg],
#| command_path : String,
#| group_name : String,
#|) -> String {
#| let help_cmd = help_context_command(cmd, inherited_globals, command_path)
#| if group_usage_expr(help_cmd.groups, help_cmd.args, group_name) is Some(expr) {
#| (
#| $|error: the following required arguments were not provided:
#| $| \{expr}
#| )
#| } else {
#| MissingGroup(group_name).arg_parse_error_message()
#| }
#|}
#|fn arg_error_for_parse_failure(
#| err : ArgParseError,
#| cmd : Command,
#| inherited_globals : Array[Arg],
#| command_path : String,
#|) -> ArgError {
#| let message = match err {
#| MissingGroup(name) =>
#| missing_group_error_message(cmd, inherited_globals, command_path, name)
#| TooManyPositionals(value, _) => {
#| let candidates = [ for sub in cmd.subcommands => sub.name ]
#| if help_subcommand_enabled(cmd) {
#| candidates.push("help")
#| }
#| if suggest_name(value, candidates) is Some(best) {
#| (
#| $|\{err.arg_parse_error_message()}
#| $|
#| $| tip: a similar subcommand exists: '\{best}'
#| )
#| } else {
#| err.arg_parse_error_message()
#| }
#| }
#| _ => err.arg_parse_error_message()
#| }
#| Message(format_error_with_help(message, cmd, inherited_globals, command_path))
#|}
#|fn parse_command(
#| cmd : Command,
#| argv : ArrayView[String],
#| env : Map[String, String],
#| inherited_globals : Array[Arg],
#| inherited_version_long : Map[String, String],
#| inherited_version_short : Map[Char, String],
#| command_path : String,
#| seed_matches? : Matches = new_matches_parse_state(),
#|) -> Matches raise {
#| parse_command_impl(
#| cmd, argv, env, inherited_globals, inherited_version_long, inherited_version_short,
#| command_path, seed_matches,
#| ) catch {
#| UnknownArgument(arg, hint) =>
#| raise arg_error_for_parse_failure(
#| UnknownArgument(arg, hint),
#| cmd,
#| inherited_globals,
#| command_path,
#| )
#| InvalidArgument(msg) =>
#| raise arg_error_for_parse_failure(
#| InvalidArgument(msg),
#| cmd,
#| inherited_globals,
#| command_path,
#| )
#| MissingValue(name) =>
#| raise arg_error_for_parse_failure(
#| MissingValue(name),
#| cmd,
#| inherited_globals,
#| command_path,
#| )
#| MissingRequired(name, by) =>
#| raise arg_error_for_parse_failure(
#| MissingRequired(name, by),
#| cmd,
#| inherited_globals,
#| command_path,
#| )
#| TooFewValues(name, got, min) =>
#| raise arg_error_for_parse_failure(
#| TooFewValues(name, got, min),
#| cmd,
#| inherited_globals,
#| command_path,
#| )
#| TooManyValues(name, got, max) =>
#| raise arg_error_for_parse_failure(
#| TooManyValues(name, got, max),
#| cmd,
#| inherited_globals,
#| command_path,
#| )
#| TooManyPositionals(value, arg) =>
#| raise arg_error_for_parse_failure(
#| TooManyPositionals(value, arg),
#| cmd,
#| inherited_globals,
#| command_path,
#| )
#| InvalidValue(msg) =>
#| raise arg_error_for_parse_failure(
#| InvalidValue(msg),
#| cmd,
#| inherited_globals,
#| command_path,
#| )
#| MissingGroup(name) =>
#| raise arg_error_for_parse_failure(
#| MissingGroup(name),
#| cmd,
#| inherited_globals,
#| command_path,
#| )
#| GroupConflict(name) =>
#| raise arg_error_for_parse_failure(
#| GroupConflict(name),
#| cmd,
#| inherited_globals,
#| command_path,
#| )
#| Unsupported(msg) =>
#| raise ArgError::Message(
#| "error: command definition validation failed: \{msg}",
#| )
#| err => raise err
#| }
#|}
#|fn parse_command_impl(
#| cmd : Command,
#| argv : ArrayView[String],
#| env : Map[String, String],
#| inherited_globals : Array[Arg],
#| inherited_version_long : Map[String, String],
#| inherited_version_short : Map[Char, String],
#| command_path : String,
#| seed_matches : Matches,
#|) -> Matches raise {
#| if cmd.build_error is Some(err) {
#| raise err
#| }
#| let args = cmd.args
#| let groups = cmd.groups
#| let subcommands = cmd.subcommands
#| if cmd.arg_required_else_help && argv.is_empty() {
#| raise_context_help(cmd, inherited_globals, command_path)
#| }
#| let matches = seed_matches
#| let globals_here = collect_globals(args)
#| let child_globals = merge_global_defs(inherited_globals, globals_here)
#| let child_version_long = inherited_version_long.copy()
#| let child_version_short = inherited_version_short.copy()
#| for global in globals_here {
#| if global.info is FlagInfo(long~, short~, action=Version, ..) {
#| if long is Some(name) {
#| child_version_long[name] = command_version(cmd)
#| }
#| if short is Some(short) {
#| child_version_short[short] = command_version(cmd)
#| }
#| }
#| }
#| let long_index = build_long_index(inherited_globals, args)
#| let short_index = build_short_index(inherited_globals, args)
#| let builtin_help_short = help_flag_enabled(cmd) &&
#| short_index.get('h') is None
#| let builtin_help_long = help_flag_enabled(cmd) &&
#| long_index.get("help") is None
#| let builtin_version_short = version_flag_enabled(cmd) &&
#| short_index.get('V') is None
#| let builtin_version_long = version_flag_enabled(cmd) &&
#| long_index.get("version") is None
#| let positionals = positional_args(args)
#| let positional_values = []
#| let mut i = 0
#| let mut positional_arg_found = false
#| let default_subcommand = match cmd.default_subcommand {
#| Some(default_name) =>
#| subcommands
#| .iter()
#| .find_first(sub => sub.name == default_name && !sub.hidden)
#| None => None
#| }
#| fn dispatch_subcommand(
#| sub : Command,
#| rest : ArrayView[String],
#| ) -> Matches raise _ {
#| let sub_path = if command_path == "" {
#| sub.name
#| } else {
#| "\{command_path} \{sub.name}"
#| }
#| let child_local_non_globals = collect_non_global_names(sub.args)
#| let child_seed = seed_child_globals_from_parent(
#| matches, child_globals, child_local_non_globals,
#| )
#| let sub_matches = parse_command(
#| sub,
#| rest,
#| env,
#| child_globals,
#| child_version_long,
#| child_version_short,
#| sub_path,
#| seed_matches=child_seed,
#| )
#| matches.parsed_subcommand = Some((sub.name, sub_matches))
#| merge_globals_from_child(
#| matches, sub_matches, child_globals, child_local_non_globals,
#| )
#| let env_args = env_resolution_args(inherited_globals, args)
#| let parent_matches = finalize_matches(
#| cmd, args, groups, matches, positionals, positional_values, env_args, env,
#| )
#| validate_relationships(parent_matches, args)
#| if parent_matches.parsed_subcommand is Some((sub_name, sub_m)) {
#| propagate_globals_to_child(
#| parent_matches, sub_m, child_globals, child_local_non_globals,
#| )
#| parent_matches.parsed_subcommand = Some((sub_name, sub_m))
#| }
#| parent_matches
#| }
#| while i < argv.length() {
#| let arg = argv[i]
#| if arg == "--" {
#| if default_subcommand is Some(sub) {
#| return dispatch_subcommand(sub, argv[i:])
#| }
#| if i + 1 < argv.length() {
#| positional_arg_found = true
#| }
#| for rest in argv[i + 1:] {
#| positional_values.push(rest)
#| }
#| break
#| }
#| if builtin_help_short && arg == "-h" {
#| raise_context_help(cmd, inherited_globals, command_path)
#| }
#| if builtin_help_long && arg == "--help" {
#| raise_context_help(cmd, inherited_globals, command_path)
#| }
#| if builtin_version_short && arg == "-V" {
#| raise_version(command_version(cmd))
#| }
#| if builtin_version_long && arg == "--version" {
#| raise_version(command_version(cmd))
#| }
#| if should_parse_as_positional(
#| arg, positionals, positional_values, long_index, short_index,
#| ) {
#| positional_values.push(arg)
#| positional_arg_found = true
#| i += 1
#| continue
#| }
#| if arg.has_prefix("--") {
#| let (name, inline) = split_long(arg)
#| if builtin_help_long && name == "help" {
#| if inline is Some(_) {
#| raise ArgParseError::InvalidArgument(arg)
#| }
#| raise_context_help(cmd, inherited_globals, command_path)
#| }
#| if builtin_version_long && name == "version" {
#| if inline is Some(_) {
#| raise ArgParseError::InvalidArgument(arg)
#| }
#| raise_version(command_version(cmd))
#| }
#| match long_index.get_from_string(name) {
#| None =>
#| if name is [.. "no-", .. target] &&
#| long_index.get_from_string(target)
#| is Some({ info: FlagInfo(negatable=true, action~, ..), .. } as spec) {
#| if inline is Some(_) {
#| raise ArgParseError::InvalidArgument(arg)
#| }
#| let value = match action {
#| SetFalse => true
#| _ => false
#| }
#| if action is Count {
#| matches.counts[spec.name] = 0
#| }
#| matches.flags[spec.name] = value
#| matches.flag_sources[spec.name] = Argv
#| } else if default_subcommand is Some(sub) {
#| return dispatch_subcommand(sub, argv[i:])
#| } else {
#| raise_unknown_long(name, long_index)
#| }
#| Some(spec) =>
#| if spec.info is (OptionInfo(_) | PositionalInfo(_)) {
#| check_duplicate_set_occurrence(matches, spec)
#| if inline is Some(v) {
#| assign_value(matches, spec, v, Argv)
#| } else {
#| let can_take_next = i + 1 < argv.length() &&
#| !should_stop_option_value(argv[i + 1], spec)
#| if can_take_next {
#| i += 1
#| assign_value(matches, spec, argv[i], Argv)
#| } else {
#| raise ArgParseError::MissingValue("--\{name}")
#| }
#| }
#| } else {
#| if inline is Some(_) {
#| raise ArgParseError::InvalidArgument(arg)
#| }
#| match spec.info {
#| FlagInfo(action=Help, ..) =>
#| raise_context_help(cmd, inherited_globals, command_path)
#| FlagInfo(action=Version, ..) =>
#| raise_version(
#| version_text_for_long_action(
#| cmd, name, inherited_version_long,
#| ),
#| )
#| _ => apply_flag(matches, spec, Argv)
#| }
#| }
#| }
#| i += 1
#| continue
#| }
#| if arg.has_prefix("-") && arg != "-" {
#| let chars = arg.iter()
#| ignore(chars.next())
#| let mut consumed_next = false
#| while chars.next() is Some(short) {
#| if short == 'h' && builtin_help_short {
#| raise_context_help(cmd, inherited_globals, command_path)
#| }
#| if short == 'V' && builtin_version_short {
#| raise_version(command_version(cmd))
#| }
#| let spec = match short_index.get(short) {
#| Some(v) => v
#| None =>
#| if default_subcommand is Some(sub) {
#| let remaining = Array(capacity=argv.length() - i)
#| remaining.push("-\{short}\{String::from_iter(chars)}")
#| for rest in argv[i + 1:] {
#| remaining.push(rest)
#| }
#| return dispatch_subcommand(sub, remaining)
#| } else {
#| raise_unknown_short(short, short_index)
#| }
#| }
#| if spec.info is (OptionInfo(_) | PositionalInfo(_)) {
#| check_duplicate_set_occurrence(matches, spec)
#| let rest = String::from_iter(chars)
#| if rest != "" {
#| let inline = match rest.strip_prefix("=") {
#| Some(view) => view.to_owned()
#| None => rest
#| }
#| assign_value(matches, spec, inline, Argv)
#| } else {
#| let can_take_next = i + 1 < argv.length() &&
#| !should_stop_option_value(argv[i + 1], spec)
#| if can_take_next {
#| consumed_next = true
#| assign_value(matches, spec, argv[i + 1], Argv)
#| } else {
#| raise ArgParseError::MissingValue("-\{short}")
#| }
#| }
#| break
#| } else {
#| match spec.info {
#| FlagInfo(action=Help, ..) =>
#| raise_context_help(cmd, inherited_globals, command_path)
#| FlagInfo(action=Version, ..) =>
#| raise_version(
#| version_text_for_short_action(
#| cmd, short, inherited_version_short,
#| ),
#| )
#| _ => apply_flag(matches, spec, Argv)
#| }
#| }
#| }
#| i += 1 + (if consumed_next { 1 } else { 0 })
#| continue
#| }
#| if help_subcommand_enabled(cmd) && arg == "help" {
#| if positional_arg_found {
#| raise_subcommand_conflict("help")
#| }
#| let rest = argv[i + 1:]
#| let (target, target_globals, target_path) = resolve_help_target(
#| cmd, rest, builtin_help_short, builtin_help_long, inherited_globals, command_path,
#| )
#| let text = render_help_for_context(target, target_globals, target_path)
#| raise_help(text)
#| }
#| if subcommands.iter().find_first(sub => sub.name == arg) is Some(sub) {
#| if positional_arg_found {
#| raise_subcommand_conflict(sub.name)
#| }
#| return dispatch_subcommand(sub, argv[i + 1:])
#| }
#| if default_subcommand is Some(sub) {
#| return dispatch_subcommand(sub, argv[i:])
#| }
#| positional_values.push(arg)
#| positional_arg_found = true
#| i += 1
#| }
#| if default_subcommand is Some(sub) {
#| return dispatch_subcommand(sub, [])
#| }
#| let env_args = env_resolution_args(inherited_globals, args)
#| let final_matches = finalize_matches(
#| cmd, args, groups, matches, positionals, positional_values, env_args, env,
#| )
#| validate_relationships(final_matches, args)
#| final_matches
#|}
#|fn finalize_matches(
#| cmd : Command,
#| args : Array[Arg],
#| groups : Array[ArgGroup],
#| matches : Matches,
#| positionals : Array[Arg],
#| positional_values : Array[String],
#| env_args : Array[Arg],
#| env : Map[String, String],
#|) -> Matches raise ArgParseError {
#| assign_positionals(matches, positionals, positional_values)
#| apply_env(matches, env_args, env)
#| apply_defaults(matches, env_args)
#| validate_values(args, matches)
#| validate_groups(args, groups, matches)
#| validate_command_policies(cmd, matches)
#| matches
#|}
#|fn help_subcommand_enabled(cmd : Command) -> Bool {
#| !cmd.disable_help_subcommand && !cmd.subcommands.is_empty()
#|}
#|fn help_flag_enabled(cmd : Command) -> Bool {
#| !cmd.disable_help_flag
#|}
#|fn version_flag_enabled(cmd : Command) -> Bool {
#| !cmd.disable_version_flag && cmd.version is Some(_)
#|}
#|fn command_version(cmd : Command) -> String {
#| cmd.version.unwrap_or("")
#|}
#|fn version_text_for_long_action(
#| cmd : Command,
#| long : StringView,
#| inherited_version_long : Map[String, String],
#|) -> String {
#| for arg in cmd.args {
#| if arg.info is FlagInfo(long=Some(name), action=Version, ..) &&
#| name[:] == long {
#| return command_version(cmd)
#| }
#| }
#| inherited_version_long.get_from_string(long).unwrap_or(command_version(cmd))
#|}
#|fn version_text_for_short_action(
#| cmd : Command,
#| short : Char,
#| inherited_version_short : Map[Char, String],
#|) -> String {
#| for arg in cmd.args {
#| if arg.info is FlagInfo(short=Some(value), action=Version, ..) &&
#| value == short {
#| return command_version(cmd)
#| }
#| }
#| inherited_version_short.get(short).unwrap_or(command_version(cmd))
#|}
),
"parser_globals_merge.mbt": (
#|fn source_priority(source : ValueSource?) -> Int {
#| match source {
#| Some(Argv) => 3
#| Some(Env) => 2
#| Some(Default) => 1
#| None => 0
#| }
#|}
#|fn prefer_child_source(
#| parent_source : ValueSource?,
#| child_source : ValueSource?,
#|) -> Bool {
#| let parent_priority = source_priority(parent_source)
#| let child_priority = source_priority(child_source)
#| if child_priority > parent_priority {
#| true
#| } else if child_priority < parent_priority {
#| false
#| } else {
#| child_source is Some(Argv)
#| }
#|}
#|fn strongest_source(
#| parent_source : ValueSource?,
#| child_source : ValueSource?,
#|) -> ValueSource? {
#| if prefer_child_source(parent_source, child_source) {
#| child_source
#| } else if parent_source is Some(_) {
#| parent_source
#| } else {
#| child_source
#| }
#|}
#|fn merge_global_value_from_child(
#| parent : Matches,
#| child : Matches,
#| arg : Arg,
#| name : String,
#|) -> Unit raise ArgParseError {
#| let parent_vals = parent.values.get(name)
#| let child_vals = child.values.get(name)
#| let parent_source = parent.value_sources.get(name)
#| let child_source = child.value_sources.get(name)
#| let has_parent = parent_vals is Some(pv) && !pv.is_empty()
#| let has_child = child_vals is Some(cv) && !cv.is_empty()
#| if !has_parent && !has_child {
#| return
#| }
#| if arg.multiple || arg.info is OptionInfo(action=Append, ..) {
#| let both_argv = parent_source is Some(Argv) && child_source is Some(Argv)
#| if both_argv {
#| let merged = []
#| if parent_vals is Some(pv) {
#| for v in pv {
#| merged.push(v)
#| }
#| }
#| if child_vals is Some(cv) {
#| for v in cv {
#| merged.push(v)
#| }
#| }
#| if !merged.is_empty() {
#| parent.values[name] = merged
#| parent.value_sources[name] = Argv
#| }
#| return
#| }
#| } else if has_parent &&
#| has_child &&
#| parent_source is Some(Argv) &&
#| child_source is Some(Argv) &&
#| arg.info is OptionInfo(action=Set, ..) {
#| raise InvalidArgument(
#| "argument '\{option_conflict_label(arg)}' cannot be used multiple times",
#| )
#| }
#| let choose_child = has_child &&
#| (!has_parent || prefer_child_source(parent_source, child_source))
#| if choose_child {
#| if child_vals is Some(cv) && !cv.is_empty() {
#| parent.values[name] = cv.copy()
#| }
#| if child_source is Some(src) {
#| parent.value_sources[name] = src
#| }
#| } else if parent_vals is Some(pv) && !pv.is_empty() {
#| parent.values[name] = pv.copy()
#| if parent_source is Some(src) {
#| parent.value_sources[name] = src
#| }
#| }
#|}
#|fn merge_global_flag_from_child(
#| parent : Matches,
#| child : Matches,
#| arg : Arg,
#| name : String,
#|) -> Unit {
#| guard child.flags.get(name) is Some(v) else { return }
#| if arg.info is FlagInfo(action=Count, ..) {
#| let has_parent = parent.flags.get(name) is Some(_)
#| let parent_source = parent.flag_sources.get(name)
#| let child_source = child.flag_sources.get(name)
#| let both_argv = parent_source is Some(Argv) && child_source is Some(Argv)
#| if both_argv {
#| let parent_count = parent.counts.get(name).unwrap_or(0)
#| let child_count = child.counts.get(name).unwrap_or(0)
#| if child_count == 0 && !v {
#| parent.counts[name] = 0
#| parent.flags[name] = false
#| } else {
#| let total = parent_count + child_count
#| parent.counts[name] = total
#| parent.flags[name] = total > 0
#| }
#| if strongest_source(parent_source, child_source) is Some(src) {
#| parent.flag_sources[name] = src
#| }
#| } else {
#| let choose_child = !has_parent ||
#| prefer_child_source(parent_source, child_source)
#| if choose_child {
#| let child_count = child.counts.get(name).unwrap_or(0)
#| parent.counts[name] = child_count
#| parent.flags[name] = child_count > 0
#| if child_source is Some(src) {
#| parent.flag_sources[name] = src
#| }
#| }
#| }
#| } else {
#| let has_parent = parent.flags.get(name) is Some(_)
#| let parent_source = parent.flag_sources.get(name)
#| let child_source = child.flag_sources.get(name)
#| let choose_child = !has_parent ||
#| prefer_child_source(parent_source, child_source)
#| if choose_child {
#| parent.flags[name] = v
#| if child_source is Some(src) {
#| parent.flag_sources[name] = src
#| }
#| }
#| }
#|}
#|fn seed_child_globals_from_parent(
#| parent : Matches,
#| globals : Array[Arg],
#| child_local_non_globals : @set.Set[String],
#|) -> Matches {
#| let seed = new_matches_parse_state()
#| let seen : @set.Set[String] = Set([])
#| for arg in globals {
#| let name = arg.name
#| if child_local_non_globals.contains(name) || !seen.add_and_check(name) {
#| continue
#| }
#| if arg.info is (OptionInfo(_) | PositionalInfo(_)) {
#| if parent.values.get(name) is Some(_) &&
#| parent.value_sources.get(name) is Some(Argv) {
#| seed.values[name] = []
#| seed.value_sources[name] = Argv
#| }
#| continue
#| }
#| if parent.flags.get(name) is Some(v) &&
#| parent.flag_sources.get(name) is Some(Argv) {
#| seed.flags[name] = v
#| seed.flag_sources[name] = Argv
#| if arg.info is FlagInfo(action=Count, ..) {
#| seed.counts[name] = 0
#| }
#| }
#| }
#| seed
#|}
#|fn merge_globals_from_child(
#| parent : Matches,
#| child : Matches,
#| globals : Array[Arg],
#| child_local_non_globals : @set.Set[String],
#|) -> Unit raise ArgParseError {
#| for arg in globals {
#| let name = arg.name
#| if child_local_non_globals.contains(name) {
#| continue
#| }
#| match arg.info {
#| OptionInfo(_) | PositionalInfo(_) =>
#| merge_global_value_from_child(parent, child, arg, name)
#| FlagInfo(_) => merge_global_flag_from_child(parent, child, arg, name)
#| }
#| }
#|}
#|fn propagate_globals_to_child(
#| parent : Matches,
#| child : Matches,
#| globals : Array[Arg],
#| child_local_non_globals : @set.Set[String],
#|) -> Unit {
#| for arg in globals {
#| let name = arg.name
#| if child_local_non_globals.contains(name) {
#| continue
#| }
#| if arg.info is (OptionInfo(_) | PositionalInfo(_)) {
#| if parent.values.get(name) is Some(values) {
#| child.values[name] = values.copy()
#| if parent.value_sources.get(name) is Some(src) {
#| child.value_sources[name] = src
#| }
#| }
#| } else if parent.flags.get(name) is Some(v) {
#| child.flags[name] = v
#| if parent.flag_sources.get(name) is Some(src) {
#| child.flag_sources[name] = src
#| }
#| if arg.info is FlagInfo(action=Count, ..) &&
#| parent.counts.get(name) is Some(c) {
#| child.counts[name] = c
#| }
#| }
#| }
#| if child.parsed_subcommand is Some((sub_name, sub_m)) {
#| propagate_globals_to_child(parent, sub_m, globals, Set([]))
#| child.parsed_subcommand = Some((sub_name, sub_m))
#| }
#|}
),
"parser_lookup.mbt": (
#|fn build_long_index(
#| globals : Array[Arg],
#| args : Array[Arg],
#|) -> Map[String, Arg] {
#| Map(
#| [
#| for arg in [..globals, ..args] if arg.info
#| is (FlagInfo(long~, ..) | OptionInfo(long~, ..)) &&
#| long is Some(name) => (name, arg)
#| ],
#| )
#|}
#|fn build_short_index(globals : Array[Arg], args : Array[Arg]) -> Map[Char, Arg] {
#| Map(
#| [
#| for arg in [..globals, ..args] if arg.info
#| is (FlagInfo(short~, ..) | OptionInfo(short~, ..)) &&
#| short is Some(value) => (value, arg)
#| ],
#| )
#|}
#|fn collect_globals(args : Array[Arg]) -> Array[Arg] {
#| args.filter(arg => arg.global && arg.info is (FlagInfo(_) | OptionInfo(_)))
#|}
#|fn collect_non_global_names(args : Array[Arg]) -> @set.Set[String] {
#| Set([ for arg in args if !arg.global => arg.name ])
#|}
#|fn resolve_help_target(
#| cmd : Command,
#| argv : ArrayView[String],
#| builtin_help_short : Bool,
#| builtin_help_long : Bool,
#| inherited_globals : Array[Arg],
#| command_path : String,
#|) -> (Command, Array[Arg], String) raise ArgParseError {
#| let targets = match argv {
#| [.. pre, "-h"] if builtin_help_short => pre
#| [.. pre, "--help"] if builtin_help_long => pre
#| _ => argv
#| }
#| for
#| name in targets
#| current = cmd,
#| current_path = command_path,
#| current_globals = inherited_globals,
#| subs = cmd.subcommands {
#| if name.has_prefix("-") {
#| raise InvalidArgument("unexpected help argument: \{name}")
#| }
#| guard subs.iter().find_first(sub => sub.name == name) is Some(sub) else {
#| let message = if suggest_name(
#| name,
#| [
#| for sub in subs if !sub.hidden => sub.name
#| ],
#| )
#| is Some(best) {
#| (
#| $|unknown subcommand: \{name}
#| $|
#| $| tip: a similar subcommand exists: '\{best}'
#| )
#| } else {
#| "unknown subcommand: \{name}"
#| }
#| raise InvalidArgument(message)
#| }
#| let current_globals = merge_global_defs(
#| current_globals,
#| collect_globals(current.args),
#| )
#| let current_path = if current_path == "" {
#| sub.name
#| } else {
#| "\{current_path} \{sub.name}"
#| }
#| continue sub, current_path, current_globals, sub.subcommands
#| } nobreak {
#| (current, current_globals, current_path)
#| }
#|}
#|fn split_long(arg : String) -> (StringView, String?) {
#| let body = arg.strip_prefix("--").unwrap_or(arg)
#| match body.split_once("=") {
#| Some((name, value)) => (name, Some(value.to_owned()))
#| None => (body, None)
#| }
#|}
),
"parser_positionals.mbt": (
#|fn positional_args(args : Array[Arg]) -> Array[Arg] {
#| [
#| for arg in args if arg.info is PositionalInfo(_) => arg
#| ]
#|}
#|fn next_positional(positionals : Array[Arg], collected : Array[String]) -> Arg? {
#| let target = collected.length()
#| let total = target + 1
#| for idx, arg in positionals; cursor = 0 {
#| if cursor >= total {
#| break None
#| }
#| let remaining = total - cursor
#| let take = if arg.multiple {
#| let (min, max) = arg_min_max(arg)
#| let reserve = remaining_positional_min(positionals, idx + 1)
#| let mut take = remaining - reserve
#| if take < 0 {
#| take = 0
#| }
#| match max {
#| Some(max_count) if take > max_count => take = max_count
#| _ => ()
#| }
#| if take < min {
#| take = min
#| }
#| if take > remaining {
#| take = remaining
#| }
#| take
#| } else if remaining > 0 {
#| 1
#| } else {
#| 0
#| }
#| if take > 0 && target < cursor + take {
#| break Some(arg)
#| }
#| continue cursor + take
#| } nobreak {
#| None
#| }
#|}
#|fn should_parse_as_positional(
#| arg : String,
#| positionals : Array[Arg],
#| collected : Array[String],
#| long_index : Map[String, Arg],
#| short_index : Map[Char, Arg],
#|) -> Bool {
#| if !arg.has_prefix("-") || arg == "-" {
#| return false
#| }
#| guard next_positional(positionals, collected) is Some(next) else {
#| return false
#| }
#| let next_allow = match next.info {
#| FlagInfo(_) => false
#| OptionInfo(allow_hyphen_values~, ..)
#| | PositionalInfo(allow_hyphen_values~, ..) => allow_hyphen_values
#| }
#| let allow = next_allow || is_negative_number(arg)
#| if !allow {
#| return false
#| }
#| if arg.has_prefix("--") {
#| let (name, _) = split_long(arg)
#| return long_index.get_from_string(name) is None
#| }
#| match arg {
#| ['-', second, ..] => short_index.get(second) is None
#| _ => true
#| }
#|}
#|fn is_negative_number(arg : String) -> Bool {
#| match arg {
#| ['-', '0'..='9', .. rest] => rest.all(c => c is ('0'..='9'))
#| _ => false
#| }
#|}
),
"parser_suggest.mbt": (
#|fn suggest_long(name : StringView, long_index : Map[String, Arg]) -> String? {
#| let candidates = long_index.keys().collect()
#| if suggest_name(name, candidates) is Some(best) {
#| Some("--\{best}")
#| } else {
#| None
#| }
#|}
#|fn suggest_short(short : Char, short_index : Map[Char, Arg]) -> String? {
#| let candidates = short_index.keys().map(c => c.to_string()).collect()
#| let input = short.to_string()
#| if suggest_name(input, candidates) is Some(best) {
#| Some("-\{best}")
#| } else {
#| None
#| }
#|}
#|fn suggest_name(input : StringView, candidates : Array[String]) -> String? {
#| let max_dist = suggestion_threshold(input.length())
#| for cand in candidates; best = (None : String?), best_dist = 0 {
#| match
#| @edit_distance.edit_distance_str_within(
#| input,
#| cand,
#| max_distance=max_dist,
#| ) {
#| Some(dist) if best is None || dist < best_dist =>
#| continue Some(cand), dist
#| _ => continue best, best_dist
#| }
#| } nobreak {
#| best
#| }
#|}
#|fn suggestion_threshold(len : Int) -> Int {
#| if len <= 4 {
#| 1
#| } else if len <= 8 {
#| 2
#| } else {
#| 3
#| }
#|}
),
"parser_validate.mbt": (
#|priv struct ValidationCtx {
#| inherited_global_names : @set.Set[String]
#| seen_names : @set.Set[String]
#| seen_long : @set.Set[String]
#| seen_short : @set.Set[Char]
#| args : Array[Arg]
#|}
#|fn ValidationCtx::new(
#| inherited_global_names? : @set.Set[String] = Set([]),
#|) -> ValidationCtx {
#| {
#| inherited_global_names: inherited_global_names.copy(),
#| seen_names: Set([]),
#| seen_long: Set([]),
#| seen_short: Set([]),
#| args: [],
#| }
#|}
#|fn ValidationCtx::record_arg(
#| self : ValidationCtx,
#| arg : Arg,
#|) -> Unit raise ArgBuildError {
#| if !self.seen_names.add_and_check(arg.name) {
#| raise Unsupported("duplicate arg name: \{arg.name}")
#| }
#| if !arg.global && self.inherited_global_names.contains(arg.name) {
#| raise Unsupported(
#| "arg '\{arg.name}' shadows an inherited global; rename the arg or mark it global",
#| )
#| }
#| fn check_long(name) raise _ {
#| if !self.seen_long.add_and_check(name) {
#| raise ArgBuildError::Unsupported("duplicate long option: --\{name}")
#| }
#| }
#| fn check_short(short) raise _ {
#| if !self.seen_short.add_and_check(short) {
#| raise ArgBuildError::Unsupported("duplicate short option: -\{short}")
#| }
#| }
#| match arg.info {
#| FlagInfo(long~, short~, negatable~, ..) => {
#| if long is Some(name) {
#| check_long(name)
#| if negatable {
#| check_long("no-\{name}")
#| }
#| }
#| if short is Some(short) {
#| check_short(short)
#| }
#| }
#| OptionInfo(long~, short~, ..) => {
#| if long is Some(name) {
#| check_long(name)
#| }
#| if short is Some(short) {
#| check_short(short)
#| }
#| }
#| PositionalInfo(_) => ()
#| }
#| self.args.push(arg)
#|}
#|fn ValidationCtx::finalize(self : ValidationCtx) -> Unit raise ArgBuildError {
#| validate_requires_conflicts_targets(self.args, self.seen_names)
#|}
#|fn validate_command(
#| cmd : Command,
#| args : Array[Arg],
#| groups : Array[ArgGroup],
#| inherited_globals : Array[Arg],
#|) -> Unit raise ArgBuildError {
#| if cmd.build_error is Some(err) {
#| raise err
#| }
#| validate_inherited_global_shadowing(args, inherited_globals)
#| validate_group_defs(args, groups)
#| validate_group_refs(args, groups)
#| validate_subcommand_defs(cmd.subcommands)
#| validate_subcommand_required_policy(cmd)
#| validate_default_subcommand_policy(cmd)
#| validate_help_subcommand(cmd)
#| validate_version_actions(cmd)
#| let child_inherited_globals = merge_inherited_globals(
#| inherited_globals,
#| collect_globals(args),
#| )
#| for sub in cmd.subcommands {
#| validate_command(sub, sub.args, sub.groups, child_inherited_globals)
#| }
#|}
#|fn validate_inherited_global_shadowing(
#| args : Array[Arg],
#| inherited_globals : Array[Arg],
#|) -> Unit raise ArgBuildError {
#| for arg in args {
#| if inherited_globals.iter().find_first(g => g.name == arg.name)
#| is Some(inherited_arg) {
#| if !arg.global {
#| raise Unsupported(
#| "arg '\{arg.name}' shadows an inherited global; rename the arg or mark it global",
#| )
#| }
#| if !global_override_compatible(inherited_arg, arg) {
#| raise Unsupported(
#| "global arg '\{arg.name}' is incompatible with inherited global definition",
#| )
#| }
#| }
#| match arg.info {
#| FlagInfo(long~, short~, negatable~, ..) => {
#| if long is Some(name) {
#| validate_inherited_global_long_collision(arg, name, inherited_globals)
#| if negatable {
#| validate_inherited_global_long_collision(
#| arg,
#| "no-\{name}",
#| inherited_globals,
#| )
#| }
#| }
#| if short is Some(value) {
#| validate_inherited_global_short_collision(
#| arg, value, inherited_globals,
#| )
#| }
#| }
#| OptionInfo(long~, short~, ..) => {
#| if long is Some(name) {
#| validate_inherited_global_long_collision(arg, name, inherited_globals)
#| }
#| if short is Some(value) {
#| validate_inherited_global_short_collision(
#| arg, value, inherited_globals,
#| )
#| }
#| }
#| PositionalInfo(_) => ()
#| }
#| }
#|}
#|fn merge_inherited_globals(
#| inherited_globals : Array[Arg],
#| globals_here : Array[Arg],
#|) -> Array[Arg] {
#| let merged = inherited_globals.copy()
#| for global in globals_here {
#| match merged.search_by(arg => arg.name == global.name) {
#| Some(idx) => merged[idx] = global
#| None => merged.push(global)
#| }
#| }
#| merged
#|}
#|fn global_override_compatible(inherited_arg : Arg, arg : Arg) -> Bool {
#| match inherited_arg.info {
#| FlagInfo(action=inherited_action, negatable=inherited_negatable, ..) =>
#| match arg.info {
#| FlagInfo(action~, negatable~, ..) =>
#| inherited_action == action && inherited_negatable == negatable
#| _ => false
#| }
#| OptionInfo(action=inherited_action, ..) =>
#| match arg.info {
#| OptionInfo(action~, ..) => inherited_action == action
#| _ => false
#| }
#| PositionalInfo(_) => false
#| }
#|}
#|fn validate_inherited_global_long_collision(
#| arg : Arg,
#| long : String,
#| inherited_globals : Array[Arg],
#|) -> Unit raise ArgBuildError {
#| if inherited_global_long_owner(arg.name, long, inherited_globals)
#| is Some(owner) {
#| raise Unsupported(
#| "arg '\{arg.name}' long option --\{long} conflicts with inherited global '\{owner}'",
#| )
#| }
#|}
#|fn validate_inherited_global_short_collision(
#| arg : Arg,
#| short : Char,
#| inherited_globals : Array[Arg],
#|) -> Unit raise ArgBuildError {
#| if inherited_global_short_owner(arg.name, short, inherited_globals)
#| is Some(owner) {
#| raise Unsupported(
#| "arg '\{arg.name}' short option -\{short} conflicts with inherited global '\{owner}'",
#| )
#| }
#|}
#|fn inherited_global_long_owner(
#| current_name : String,
#| long : String,
#| inherited_globals : Array[Arg],
#|) -> String? {
#| for inherited in inherited_globals {
#| if inherited.name == current_name {
#| continue
#| }
#| match inherited.info {
#| FlagInfo(long=inherited_long, negatable~, ..) =>
#| if inherited_long is Some(name) &&
#| (name == long || (negatable && "no-\{name}" == long)) {
#| return Some(inherited.name)
#| }
#| OptionInfo(long=inherited_long, ..) =>
#| if inherited_long is Some(name) && name == long {
#| return Some(inherited.name)
#| }
#| PositionalInfo(_) => ()
#| }
#| }
#| None
#|}
#|fn inherited_global_short_owner(
#| current_name : String,
#| short : Char,
#| inherited_globals : Array[Arg],
#|) -> String? {
#| for inherited in inherited_globals {
#| if inherited.name == current_name {
#| continue
#| }
#| match inherited.info {
#| FlagInfo(short=inherited_short, ..)
#| | OptionInfo(short=inherited_short, ..) =>
#| if inherited_short is Some(value) && value == short {
#| return Some(inherited.name)
#| }
#| PositionalInfo(_) => ()
#| }
#| }
#| None
#|}
#|fn validate_flag_arg(
#| arg : Arg,
#| ctx : ValidationCtx,
#|) -> Unit raise ArgBuildError {
#| validate_named_option_arg(arg)
#| guard! arg.info is FlagInfo(action~, negatable~, ..)
#| if action is (Help | Version) {
#| guard !negatable else {
#| raise Unsupported("help/version actions do not support negatable")
#| }
#| guard arg.env is None else {
#| raise Unsupported("help/version actions do not support env/defaults")
#| }
#| guard !arg.multiple else {
#| raise Unsupported("help/version actions do not support multiple values")
#| }
#| }
#| ctx.record_arg(arg)
#|}
#|fn validate_option_arg(
#| arg : Arg,
#| ctx : ValidationCtx,
#|) -> Unit raise ArgBuildError {
#| validate_named_option_arg(arg)
#| validate_default_values(arg)
#| ctx.record_arg(arg)
#|}
#|fn validate_positional_arg(
#| arg : Arg,
#| ctx : ValidationCtx,
#|) -> Unit raise ArgBuildError {
#| let (min, max) = arg_min_max_for_validate(arg)
#| if (min > 1 || (max is Some(m) && m > 1)) && !arg.multiple {
#| raise Unsupported(
#| "multiple values require action=Append or num_args allowing >1",
#| )
#| }
#| validate_default_values(arg)
#| ctx.record_arg(arg)
#|}
#|fn validate_named_option_arg(arg : Arg) -> Unit raise ArgBuildError {
#| guard! arg.info
#| is (FlagInfo(long~, short~, ..) | OptionInfo(long~, short~, ..))
#| guard long is Some(_) || short is Some(_) || arg.env is Some(_) else {
#| raise Unsupported("flag/option args require short/long/env")
#| }
#|}
#|fn validate_default_values(arg : Arg) -> Unit raise ArgBuildError {
#| if arg.info
#| is (OptionInfo(default_values~, ..) | PositionalInfo(default_values~, ..)) &&
#| default_values is Some(values) &&
#| values.length() > 1 &&
#| !arg.multiple &&
#| !(arg.info is OptionInfo(action=Append, ..)) {
#| raise Unsupported(
#| "default_values with multiple entries require action=Append",
#| )
#| }
#|}
#|fn validate_group_defs(
#| args : Array[Arg],
#| groups : Array[ArgGroup],
#|) -> Unit raise ArgBuildError {
#| let seen : @set.Set[String] = Set([])
#| let arg_seen : @set.Set[String] = Set([])
#| for arg in args {
#| arg_seen.add(arg.name)
#| }
#| for group in groups {
#| if !seen.add_and_check(group.name) {
#| raise Unsupported("duplicate group: \{group.name}")
#| }
#| }
#| for group in groups {
#| for required in group.requires {
#| if required == group.name {
#| raise Unsupported("group cannot require itself: \{group.name}")
#| }
#| if !seen.contains(required) && !arg_seen.contains(required) {
#| raise Unsupported(
#| "unknown group requires target: \{group.name} -> \{required}",
#| )
#| }
#| }
#| for conflict in group.conflicts_with {
#| if conflict == group.name {
#| raise Unsupported("group cannot conflict with itself: \{group.name}")
#| }
#| if !seen.contains(conflict) && !arg_seen.contains(conflict) {
#| raise Unsupported(
#| "unknown group conflicts_with target: \{group.name} -> \{conflict}",
#| )
#| }
#| }
#| }
#|}
#|fn validate_group_refs(
#| args : Array[Arg],
#| groups : Array[ArgGroup],
#|) -> Unit raise ArgBuildError {
#| if groups.is_empty() {
#| return
#| }
#| let arg_index : @set.Set[String] = Set([])
#| for arg in args {
#| arg_index.add(arg.name)
#| }
#| for group in groups {
#| for name in group.args {
#| if !arg_index.contains(name) {
#| raise Unsupported("unknown group arg: \{group.name} -> \{name}")
#| }
#| }
#| }
#|}
#|fn validate_requires_conflicts_targets(
#| args : Array[Arg],
#| seen_names : @set.Set[String],
#|) -> Unit raise ArgBuildError {
#| for arg in args {
#| for required in arg.requires {
#| if required == arg.name {
#| raise Unsupported("arg cannot require itself: \{arg.name}")
#| }
#| if !seen_names.contains(required) {
#| raise Unsupported("unknown requires target: \{arg.name} -> \{required}")
#| }
#| }
#| for conflict in arg.conflicts_with {
#| if conflict == arg.name {
#| raise Unsupported("arg cannot conflict with itself: \{arg.name}")
#| }
#| if !seen_names.contains(conflict) {
#| raise Unsupported(
#| "unknown conflicts_with target: \{arg.name} -> \{conflict}",
#| )
#| }
#| }
#| }
#|}
#|fn validate_subcommand_defs(subs : Array[Command]) -> Unit raise ArgBuildError {
#| if subs.is_empty() {
#| return
#| }
#| let seen : @set.Set[String] = Set([])
#| for sub in subs {
#| if !seen.add_and_check(sub.name) {
#| raise Unsupported("duplicate subcommand: \{sub.name}")
#| }
#| }
#|}
#|fn validate_subcommand_required_policy(
#| cmd : Command,
#|) -> Unit raise ArgBuildError {
#| if cmd.subcommand_required && cmd.subcommands.is_empty() {
#| raise Unsupported("subcommand_required requires at least one subcommand")
#| }
#|}
#|fn validate_default_subcommand_policy(
#| cmd : Command,
#|) -> Unit raise ArgBuildError {
#| guard cmd.default_subcommand is Some(name) else { return }
#| if cmd.subcommand_required {
#| raise Unsupported(
#| "default_subcommand cannot be used with subcommand_required",
#| )
#| }
#| if cmd.arg_required_else_help {
#| raise Unsupported(
#| "default_subcommand cannot be used with arg_required_else_help",
#| )
#| }
#| if cmd.subcommands.iter().find_first(sub => sub.name == name && !sub.hidden)
#| is None {
#| raise Unsupported(
#| "default_subcommand must name a visible subcommand: \{name}",
#| )
#| }
#| if !cmd.groups.is_empty() {
#| raise Unsupported("default_subcommand does not support root groups")
#| }
#| for arg in cmd.args {
#| if !(arg.global && arg.info is (FlagInfo(_) | OptionInfo(_))) {
#| raise Unsupported(
#| "default_subcommand only supports global root flags/options",
#| )
#| }
#| }
#|}
#|fn validate_help_subcommand(cmd : Command) -> Unit raise ArgBuildError {
#| if help_subcommand_enabled(cmd) &&
#| cmd.subcommands.any(cmd => cmd.name == "help") {
#| raise Unsupported(
#| "subcommand name reserved for built-in help: help (disable with disable_help_subcommand)",
#| )
#| }
#|}
#|fn validate_version_actions(cmd : Command) -> Unit raise ArgBuildError {
#| if cmd.version is None &&
#| cmd.args.any(arg => arg.info is FlagInfo(action=Version, ..)) {
#| raise Unsupported("version action requires command version text")
#| }
#|}
#|fn validate_command_policies(
#| cmd : Command,
#| matches : Matches,
#|) -> Unit raise ArgParseError {
#| if cmd.subcommand_required &&
#| !cmd.subcommands.is_empty() &&
#| matches.parsed_subcommand is None {
#| raise MissingRequired("subcommand", None)
#| }
#|}
#|fn validate_groups(
#| args : Array[Arg],
#| groups : Array[ArgGroup],
#| matches : Matches,
#|) -> Unit raise ArgParseError {
#| if groups.is_empty() {
#| return
#| }
#| let group_presence = Map([])
#| let group_seen : @set.Set[String] = Set([])
#| let arg_seen : @set.Set[String] = Set([])
#| for group in groups {
#| group_seen.add(group.name)
#| }
#| for arg in args {
#| arg_seen.add(arg.name)
#| }
#| for group in groups {
#| let count = for arg in args; count = 0 {
#| if !arg_in_group(arg, group) {
#| continue count
#| }
#| if matches_has_value_or_flag(matches, arg.name) {
#| continue count + 1
#| } else {
#| continue count
#| }
#| } nobreak {
#| count
#| }
#| group_presence[group.name] = count
#| if group.required && count == 0 {
#| raise MissingGroup(group.name)
#| }
#| if !group.multiple && count > 1 {
#| raise GroupConflict(group.name)
#| }
#| }
#| for group in groups {
#| let count = group_presence[group.name]
#| if count == 0 {
#| continue
#| }
#| for required in group.requires {
#| if group_seen.contains(required) {
#| if group_presence.get(required).unwrap_or(0) == 0 {
#| raise MissingGroup(required)
#| }
#| } else if arg_seen.contains(required) {
#| if !matches_has_value_or_flag(matches, required) {
#| raise MissingRequired(required, None)
#| }
#| }
#| }
#| for conflict in group.conflicts_with {
#| if group_seen.contains(conflict) {
#| if group_presence.get(conflict).unwrap_or(0) > 0 {
#| raise GroupConflict("\{group.name} conflicts with \{conflict}")
#| }
#| } else if arg_seen.contains(conflict) {
#| if matches_has_value_or_flag(matches, conflict) {
#| raise GroupConflict("\{group.name} conflicts with \{conflict}")
#| }
#| }
#| }
#| }
#|}
#|fn arg_in_group(arg : Arg, group : ArgGroup) -> Bool {
#| group.args.contains(arg.name)
#|}
#|fn validate_values(
#| args : Array[Arg],
#| matches : Matches,
#|) -> Unit raise ArgParseError {
#| for arg in args {
#| let present = matches_has_value_or_flag(matches, arg.name)
#| if arg.required && !present {
#| raise MissingRequired(arg.name, None)
#| }
#| guard arg.info is (OptionInfo(_) | PositionalInfo(_)) else { continue }
#| if !present {
#| if arg.info is PositionalInfo(_) {
#| let (min, _) = arg_min_max(arg)
#| if min > 0 {
#| raise TooFewValues(arg.name, 0, min)
#| }
#| }
#| continue
#| }
#| let values = matches.values.get(arg.name).unwrap_or([])
#| let count = values.length()
#| let (min, max) = arg_min_max(arg)
#| if count < min {
#| raise TooFewValues(arg.name, count, min)
#| }
#| if !(arg.info is OptionInfo(action=Append, ..)) {
#| match max {
#| Some(max) if count > max => raise TooManyValues(arg.name, count, max)
#| _ => ()
#| }
#| }
#| }
#|}
#|fn validate_relationships(
#| matches : Matches,
#| args : Array[Arg],
#|) -> Unit raise ArgParseError {
#| for arg in args {
#| if !matches_has_value_or_flag(matches, arg.name) {
#| continue
#| }
#| for required in arg.requires {
#| if !matches_has_value_or_flag(matches, required) {
#| raise MissingRequired(required, Some(arg.name))
#| }
#| }
#| for conflict in arg.conflicts_with {
#| if matches_has_value_or_flag(matches, conflict) {
#| raise InvalidArgument(
#| "conflicting arguments: \{arg.name} and \{conflict}",
#| )
#| }
#| }
#| }
#|}
),
"parser_values.mbt": (
#|fn assign_positionals(
#| matches : Matches,
#| positionals : Array[Arg],
#| values : Array[String],
#|) -> Unit raise ArgParseError {
#| let cursor = for idx, arg in positionals; cursor = 0 {
#| let remaining = values.length() - cursor
#| if arg.multiple {
#| let (min, max) = arg_min_max(arg)
#| let reserve = remaining_positional_min(positionals, idx + 1)
#| let mut take = remaining - reserve
#| if take < 0 {
#| take = 0
#| }
#| match max {
#| Some(max_count) if take > max_count => take = max_count
#| _ => ()
#| }
#| if take < min {
#| take = min
#| }
#| if take > remaining {
#| take = remaining
#| }
#| let mut taken = 0
#| while taken < take {
#| add_value(matches, arg.name, values[cursor + taken], arg, Argv)
#| taken += 1
#| }
#| continue cursor + taken
#| }
#| if remaining > 0 {
#| add_value(matches, arg.name, values[cursor], arg, Argv)
#| continue cursor + 1
#| } else {
#| continue cursor
#| }
#| } nobreak {
#| cursor
#| }
#| if cursor < values.length() {
#| let overflow_label = if !positionals.is_empty() {
#| let last = positionals[positionals.length() - 1]
#| if last.multiple {
#| Some("<\{last.name}...>")
#| } else {
#| Some("<\{last.name}>")
#| }
#| } else {
#| None
#| }
#| raise TooManyPositionals(values[cursor], overflow_label)
#| }
#|}
#|fn positional_min_required(arg : Arg) -> Int {
#| let (min, _) = arg_min_max(arg)
#| if min > 0 {
#| min
#| } else {
#| 0
#| }
#|}
#|fn remaining_positional_min(positionals : Array[Arg], start : Int) -> Int {
#| for idx = start, total = 0; idx < positionals.length(); {
#| continue idx + 1, total + positional_min_required(positionals[idx])
#| } nobreak {
#| total
#| }
#|}
#|fn add_value(
#| matches : Matches,
#| name : String,
#| value : String,
#| arg : Arg,
#| source : ValueSource,
#|) -> Unit {
#| if arg.multiple || arg.info is OptionInfo(action=Append, ..) {
#| let arr = matches.values.get(name).unwrap_or([])
#| arr.push(value)
#| matches.values[name] = arr
#| matches.value_sources[name] = source
#| } else {
#| matches.values[name] = [value]
#| matches.value_sources[name] = source
#| }
#|}
#|fn assign_value(
#| matches : Matches,
#| arg : Arg,
#| value : String,
#| source : ValueSource,
#|) -> Unit raise ArgParseError {
#| match arg.info {
#| OptionInfo(action=Append, ..) =>
#| add_value(matches, arg.name, value, arg, source)
#| OptionInfo(action=Set, ..) | PositionalInfo(_) =>
#| add_value(matches, arg.name, value, arg, source)
#| FlagInfo(action=SetTrue, ..) => {
#| let flag = parse_bool(value)
#| matches.flags[arg.name] = flag
#| matches.flag_sources[arg.name] = source
#| }
#| FlagInfo(action=SetFalse, ..) => {
#| let flag = parse_bool(value)
#| matches.flags[arg.name] = !flag
#| matches.flag_sources[arg.name] = source
#| }
#| FlagInfo(action=Count, ..) => {
#| let count = parse_count(value)
#| matches.counts[arg.name] = count
#| matches.flags[arg.name] = count > 0
#| matches.flag_sources[arg.name] = source
#| }
#| FlagInfo(action=Help, ..) =>
#| raise InvalidArgument("help action does not take values")
#| FlagInfo(action=Version, ..) =>
#| raise InvalidArgument("version action does not take values")
#| }
#|}
#|fn option_conflict_label(arg : Arg) -> String {
#| match arg.info {
#| FlagInfo(long=Some(name), ..) | OptionInfo(long=Some(name), ..) =>
#| "--\{name}"
#| FlagInfo(short=Some(short), ..) | OptionInfo(short=Some(short), ..) =>
#| "-\{short}"
#| _ => arg.name
#| }
#|}
#|fn check_duplicate_set_occurrence(
#| matches : Matches,
#| arg : Arg,
#|) -> Unit raise ArgParseError {
#| guard arg.info is (OptionInfo(action=Set, ..) | PositionalInfo(_)) else {
#| return
#| }
#| if matches.values.get(arg.name) is Some(values) && !values.is_empty() {
#| raise InvalidArgument(
#| "argument '\{option_conflict_label(arg)}' cannot be used multiple times",
#| )
#| }
#|}
#|fn should_stop_option_value(value : String, arg : Arg) -> Bool {
#| if !value.has_prefix("-") || value == "-" {
#| return false
#| }
#| if arg.info
#| is (OptionInfo(allow_hyphen_values~, ..)
#| | PositionalInfo(allow_hyphen_values~, ..)) &&
#| allow_hyphen_values {
#| return false
#| }
#| true
#|}
#|fn apply_env(
#| matches : Matches,
#| args : Array[Arg],
#| env : Map[String, String],
#|) -> Unit raise ArgParseError {
#| for arg in args {
#| let name = arg.name
#| if matches_has_value_or_flag(matches, name) {
#| continue
#| }
#| guard arg.env is Some(env_name) else { continue }
#| guard env.get(env_name) is Some(value) else { continue }
#| match arg.info {
#| FlagInfo(action=Help | Version, ..) => ()
#| _ => assign_value(matches, arg, value, Env)
#| }
#| }
#|}
#|fn apply_defaults(matches : Matches, args : Array[Arg]) -> Unit {
#| for arg in args {
#| let default_values = match arg.info {
#| FlagInfo(_) => continue
#| OptionInfo(default_values~, ..) | PositionalInfo(default_values~, ..) =>
#| default_values
#| }
#| if matches_has_value_or_flag(matches, arg.name) {
#| continue
#| }
#| match default_values {
#| Some(values) if !values.is_empty() =>
#| for value in values {
#| let _ = add_value(matches, arg.name, value, arg, Default)
#| }
#| _ => ()
#| }
#| }
#|}
#|fn matches_has_value_or_flag(matches : Matches, name : String) -> Bool {
#| matches.flags.contains(name) || matches.values.contains(name)
#|}
#|fn apply_flag(matches : Matches, arg : Arg, source : ValueSource) -> Unit {
#| match arg.info {
#| FlagInfo(action=SetTrue, ..) => matches.flags[arg.name] = true
#| FlagInfo(action=SetFalse, ..) => matches.flags[arg.name] = false
#| FlagInfo(action=Count, ..) => {
#| let current = matches.counts.get(arg.name).unwrap_or(0)
#| matches.counts[arg.name] = current + 1
#| matches.flags[arg.name] = true
#| }
#| FlagInfo(action=Help, ..) => ()
#| FlagInfo(action=Version, ..) => ()
#| _ => matches.flags[arg.name] = true
#| }
#| matches.flag_sources[arg.name] = source
#|}
#|fn parse_bool(value : String) -> Bool raise ArgParseError {
#| match value {
#| "1" | "true" | "yes" | "on" => true
#| "0" | "false" | "no" | "off" => false
#| _ =>
#| raise InvalidValue(
#| "invalid value '\{value}' for boolean flag; expected one of: 1, 0, true, false, yes, no, on, off",
#| )
#| }
#|}
#|fn parse_count(value : String) -> Int raise ArgParseError {
#| try @string.parse_int(value) catch {
#| _ =>
#| raise InvalidValue(
#| "invalid value '\{value}' for count; expected a non-negative integer",
#| )
#| } noraise {
#| _..<0 =>
#| raise InvalidValue(
#| "invalid value '\{value}' for count; expected a non-negative integer",
#| )
#| v => v
#| }
#|}
),
"runtime_exit.mbt": (
#|fn trim_single_trailing_newline(text : String) -> String {
#| match text.strip_suffix("\n") {
#| Some(view) => view.to_owned()
#| None => text
#| }
#|}
#|fn[T] print_and_exit_success(text : String) -> T {
#| println(trim_single_trailing_newline(text))
#| runtime_exit_success()
#| panic()
#|}
),
"runtime_exit_js.mbt": (
#|#cfg(target="js")
#|extern "js" fn runtime_js_try_exit(code : Int) -> Bool =
#| #| function(code) {
#| #| if (typeof process !== "undefined" && typeof process.exit === "function") {
#| #| process.exit(code);
#| #| return true;
#| #| }
#| #| return false;
#| #| }
#|#cfg(target="js")
#|fn runtime_exit_success() -> Unit {
#| if !runtime_js_try_exit(0) {
#| panic()
#| }
#|}
),
"runtime_exit_native.mbt": (
#|#cfg(any(target="native", target="llvm"))
#|extern "c" fn runtime_native_exit(code : Int) = "exit"
#|#cfg(any(target="native", target="llvm"))
#|fn runtime_exit_success() -> Unit {
#| runtime_native_exit(0)
#|}
),
"runtime_exit_wasm.mbt": (
#|#cfg(target="wasm")
#|fn runtime_wasm_exit(code : Int) -> Unit = "wasi_snapshot_preview1" "proc_exit"
#|#cfg(target="wasm-gc")
#|fn runtime_wasm_exit(code : Int) -> Unit = "__moonbit_sys_unstable" "exit"
#|#cfg(any(target="wasm", target="wasm-gc"))
#|fn runtime_exit_success() -> Unit {
#| runtime_wasm_exit(0)
#|}
),
"value_range.mbt": (
#|#warnings("-deprecated_syntax-deprecated")
#|pub struct ValueRange {
#| priv lower : Int
#| priv upper : Int?
#|} derive(Eq, Show, @debug.Debug)
#|#alias(new, deprecated="Use `ValueRange()` instead")
#|pub fn ValueRange::ValueRange(lower? : Int = 0, upper? : Int) -> ValueRange {
#| { lower, upper, }
#|}
#|pub fn ValueRange::single() -> ValueRange {
#| ValueRange(lower=1, upper=1)
#|}
),
},
)
///|
let moonbitlang_core_array_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/array",
deps={},
files={
"array.mbt": (
#|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() }
#| Array::makei(length, i => merge(l[i], r[i]))
#|}
),
"view.mbt": (
#|#deprecated
#|pub type View[T] = ArrayView[T]
),
},
)
///|
let moonbitlang_core_bench_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/bench",
deps={},
files={
"bench.mbt": (
#|fn iter_n_microseconds(inner : () -> Unit, k : Int) -> Double {
#| let ts = monotonic_clock_start()
#| for _ in 0.. Unit, count : UInt) -> Summary {
#| let count = count.land(0x7FFFFFFF).reinterpret_as_int()
#| let threshold = 100000.0 // 100 ms
#| let target_batch_size = for trial = 1 {
#| 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::bench(
#| self : Bench,
#| 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] Bench::keep(self : Bench, value : Any) -> Unit {
#| let trait_object : &OpaqueValue = @ref.new(value)
#| self._storage = trait_object
#|}
#|#coverage.skip
#|pub fn Bench::dump_summaries(self : Bench) -> String {
#| "[\{self.buffer.to_string()}]"
#|}
#|#skip("slow benchmarking test")
#|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")
#|}
#|#skip("slow benchmarking test")
#|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")
#|}
#|#skip("slow benchmarking test")
#|test "bench - T struct and bench method" {
#| let bench_obj = Bench()
#| 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")
#|}
#|#skip("slow benchmarking test")
#|test "bench - monotonic clock functionality" {
#| let start = monotonic_clock_start()
#| let result = for _ in 0..<1000; result = 0 {
#| continue result + 1
#| } nobreak {
#| result
#| }
#| ignore(result)
#| let elapsed = monotonic_clock_end(start)
#| inspect(elapsed >= 0.0, content="true")
#|}
#|test "bench - keep stores value" {
#| let b = Bench()
#| @test.assert_eq(b.summaries.length(), 0)
#| b.keep(123)
#| @test.assert_eq(b.summaries.length(), 0)
#| b.keep(456)
#| @test.assert_eq(b.summaries.length(), 0)
#|}
),
"debug.mbt": (
#|pub impl @debug.Debug for Bench with fn to_repr(self) {
#| @debug.Repr::opaque_(
#| "Bench",
#| @debug.Repr::array(self.summaries.map(s => Repr(s))),
#| )
#|}
#|pub impl @debug.Debug for Timestamp with fn to_repr(_) {
#| @debug.Repr::opaque_("Timestamp", @debug.Repr::omitted())
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Bench with @debug.Debug::{to_repr}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Summary with @debug.Debug::{to_repr}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Summary with ToJson::{to_json}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Timestamp with @debug.Debug::{to_repr}
),
"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
),
"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, @debug.Debug)
#|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 {
#| for i in data; sum = 0.0 {
#| continue sum + i
#| } nobreak {
#| 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
#| }
#| for i in data; v = 0.0 {
#| let d = i - mean
#| continue v + d * d
#| } nobreak {
#| 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.is_empty()
#| 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.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" {
#| @test.assert_eq(std_dev_pct(mean=0.0, std_dev=5.0), 0.0)
#|}
#|test "median_abs_dev_pct zero median" {
#| @test.assert_eq(median_abs_dev_pct(median=0.0, median_abs_dev=3.0), 0.0)
#|}
#|test "percentile edge cases" {
#| @test.assert_eq(percentile(sorted_data=[42.0], pct=50.0), 42.0)
#| @test.assert_eq(percentile(sorted_data=[1.0, 2.0, 3.0], pct=100.0), 3.0)
#|}
),
"types.mbt": (
#|priv trait OpaqueValue {}
#|impl[X] OpaqueValue for @ref.Ref[X]
#|#alias(T)
#|struct Bench {
#| buffer : StringBuilder
#| summaries : Array[Summary]
#| mut _storage : &OpaqueValue
#|}
#|#alias(new, deprecated="Use `Bench()` instead")
#|#as_free_fn
#|#as_free_fn(new, deprecated="Use `Bench()` instead")
#|pub fn Bench::Bench() -> Bench {
#| let buffer = StringBuilder()
#| let summaries = []
#| { buffer, summaries, _storage: @ref.new(()), }
#|}
),
},
)
///|
let moonbitlang_core_bigint_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/bigint",
deps={},
files={
"bigint.mbt": (
#|pub impl ToJson for BigInt with fn to_json(self : BigInt) -> Json {
#| Json::string(self.to_string())
#|}
#|pub impl Show for BigInt with fn to_string(self) {
#| BigInt::to_string(self)
#|}
#|pub impl @json.FromJson for BigInt with fn from_json(json, path) {
#| guard json is String(s) else {
#| raise JsonDecodeError(
#| (path, "BigInt::from_json: expected number in string representation"),
#| )
#| }
#| parse_bigint(s) catch {
#| _ =>
#| raise JsonDecodeError(
#| (path, "BigInt::from_json: invalid number in string representation"),
#| )
#| }
#|}
#|pub impl Default for BigInt with fn 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::equal_uint(self : BigInt, other : UInt) -> Bool {
#| if is_neg(self) || self.bit_length() > 32 {
#| false
#| } else {
#| self.to_uint() == other
#| }
#|}
#|pub fn BigInt::equal_uint64(self : BigInt, other : UInt64) -> Bool {
#| if is_neg(self) || self.bit_length() > 64 {
#| false
#| } else {
#| self.to_uint64() == 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)
#|}
#|pub fn BigInt::compare_uint(self : BigInt, other : UInt) -> Int {
#| if is_neg(self) {
#| -1
#| } else if self.bit_length() > 32 {
#| 1
#| } else {
#| UInt::compare(self.to_uint(), other)
#| }
#|}
#|pub fn BigInt::compare_uint64(self : BigInt, other : UInt64) -> Int {
#| if is_neg(self) {
#| -1
#| } else if self.bit_length() > 64 {
#| 1
#| } else {
#| UInt64::compare(self.to_uint64(), 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 fn 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 {
#| Int16::from_int(self.to_int())
#|}
#|pub impl @debug.Debug for BigInt with fn to_repr(self) {
#| @debug.Repr::integer(self.to_string())
#|}
),
"bigint_js.mbt": (
#|type BigInt
#|let zero = 0N
#|#internal(internal, "use `@string.parse_bigint` instead")
#|#doc(hidden)
#|pub fn parse_bigint(str : StringView, base? : Int = 10) -> BigInt raise {
#| if base < 2 || base > 36 {
#| base_err()
#| }
#| if str.is_empty() {
#| syntax_err()
#| }
#| match str.unsafe_get(str.length() - 1) {
#| '0'..='9' | 'A'..='Z' | 'a'..='z' => ()
#| _ => syntax_err()
#| }
#| if base == 10 {
#| match str {
#| ['0', 'x' | 'X' | 'o' | 'O' | 'b' | 'B', ..]
#| | ['-', '0', 'x' | 'X' | 'o' | 'O' | 'b' | 'B', ..] => syntax_err()
#| ['0'..='9', ..] | ['-', '0'..='9', ..] => ()
#| _ => syntax_err()
#| }
#| }
#| match base {
#| 2 | 8 | 10 | 16 =>
#| match
#| BigInt::js_parse_string(
#| str.data(),
#| str.start_offset(),
#| str.start_offset() + str.length(),
#| base,
#| value => Some(value),
#| None,
#| ) {
#| Some(value) => value
#| None => syntax_err()
#| }
#| _ => BigInt::from_string_radix(str, base)
#| }
#|}
#|extern "js" fn BigInt::js_parse_string(
#| str : String,
#| start : Int,
#| end : Int,
#| base : Int,
#| some : (BigInt) -> BigInt?,
#| none : BigInt?,
#|) -> BigInt? =
#| #|(str, start, end, base, some, none) => {
#| #| try {
#| #| if (base === 10) {
#| #| const input = start === 0 && end === str.length ? str : str.slice(start, end);
#| #| return some(BigInt(input));
#| #| }
#| #| const negative = str.charCodeAt(start) === 45;
#| #| const digits = str.slice(negative ? start + 1 : start, end);
#| #| const prefix = base === 2 ? "0b" : base === 8 ? "0o" : "0x";
#| #| const value = BigInt(prefix + digits);
#| #| return some(negative ? -value : value);
#| #| } catch (_) {
#| #| return none;
#| #| }
#| #|}
#|pub fn BigInt::from_string(str : String, radix? : Int = 10) -> BigInt {
#| parse_bigint(str, base=radix) catch {
#| Failure(msg) => abort(msg)
#| _ => abort("invalid syntax")
#| }
#|}
#|fn digit_from_char(x : Int) -> Int {
#| match x {
#| '0'..='9' => x - '0'
#| 'A'..='Z' => x + (10 - 'A')
#| 'a'..='z' => x + (10 - 'a')
#| _ => -1
#| }
#|}
#|fn pow2_shift(radix : Int) -> Int? {
#| if radix >= 2 && (radix & (radix - 1)) == 0 {
#| Some(radix.ctz())
#| } else {
#| None
#| }
#|}
#|fn BigInt::from_string_radix(str : StringView, radix : Int) -> BigInt raise {
#| let len = str.length()
#| let sign = if str.unsafe_get(0) == '-' { -1 } else { 1 }
#| let start = if sign == -1 { 1 } else { 0 }
#| if start == len {
#| syntax_err()
#| }
#| let mut acc = 0N
#| match pow2_shift(radix) {
#| Some(shift) =>
#| for i in start..= radix {
#| syntax_err()
#| }
#| acc = (acc << shift) | BigInt::from_int(digit)
#| }
#| None => {
#| let base = BigInt::from_int(radix)
#| for i in start..= radix {
#| syntax_err()
#| }
#| acc = acc * base + BigInt::from_int(digit)
#| }
#| }
#| }
#| if sign == -1 {
#| -acc
#| } else {
#| acc
#| }
#|}
#|pub fn BigInt::to_string(self : BigInt, radix? : Int = 10) -> String {
#| if radix < 2 || radix > 36 {
#| abort("radix must be between 2 and 36")
#| }
#| BigInt::js_to_string_radix(self, radix)
#|}
#|extern "js" fn BigInt::js_to_string_radix(self : BigInt, radix : Int) -> String =
#| #|(x, radix) => x.toString(radix)
#|extern "js" fn hex2(b : Byte) -> String =
#| #|(x) => x.toString(16).padStart(2, '0')
#|pub fn BigInt::from_octets(octets : BytesView, signum? : Int = 1) -> BigInt {
#| if signum < 0 {
#| return -1N * BigInt::from_octets(octets, signum=1)
#| }
#| if signum == 0 {
#| return 0N
#| }
#| if octets.is_empty() {
#| return 0N
#| }
#| let str = StringBuilder()
#| for octet in octets {
#| str.write_string(hex2(octet))
#| }
#| parse_bigint(str.to_string(), base=16) catch {
#| Failure(msg) => abort(msg)
#| _ => abort("invalid syntax")
#| }
#|}
#|pub fn BigInt::to_octets(self : BigInt, length? : Int) -> Bytes {
#| if self < 0 {
#| abort("negative BigInt")
#| }
#| if self == 0 {
#| return match length {
#| Some(len) =>
#| if len <= 0 {
#| abort("negative length")
#| } else {
#| Bytes::make(len, 0)
#| }
#| None => [0]
#| }
#| }
#| let buf = []
#| for v = self {
#| if v > 0 {
#| buf.push(v.to_byte())
#| continue v >> 8
#| } else {
#| break
#| }
#| }
#| 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_js(self : BigInt, other : BigInt) -> Int =
#| #|(x, y) => x < y ? -1 : x > y ? 1 : 0
#|pub impl Compare for BigInt with fn compare(self, other) {
#| self.compare_js(other)
#|}
#|extern "js" fn BigInt::equal_js(self : BigInt, other : BigInt) -> Bool =
#| #|(x, y) => x === y
#|pub impl Eq for BigInt with fn equal(self, other) {
#| self.equal_js(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.asIntN(64, x)
#|pub fn BigInt::from_uint64(x : UInt64) -> BigInt = "%identity"
#|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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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) + z) % 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 fn shl(self : BigInt, n : Int) -> BigInt {
#| if n < 0 {
#| abort("negative shift count")
#| }
#| self.js_shl(n)
#|}
#|pub impl Shr for BigInt with fn 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 fn 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 fn 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 fn 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) -> Array[UInt] {
#| guard !self.is_zero() else { [0] }
#| let result = []
#| for n = self * BigInt::from_int(self.signum()); n > 0; n = n >> 32 {
#| let limb = n.to_uint()
#| result.push(limb)
#| }
#| result
#|}
),
"extends.mbt": (
#|pub extend BigInt with Add::{add}
#|pub extend BigInt with BitAnd::{land}
#|pub extend BigInt with BitOr::{lor}
#|pub extend BigInt with BitXOr::{lxor}
#|pub extend BigInt with Compare::{compare}
#|pub extend BigInt with Div::{div}
#|pub extend BigInt with Eq::{equal}
#|pub extend BigInt with Hash::{hash}
#|pub extend BigInt with Mod::{mod}
#|pub extend BigInt with Mul::{mul}
#|pub extend BigInt with Neg::{neg}
#|pub extend BigInt with Shl::{shl}
#|pub extend BigInt with Shr::{shr}
#|pub extend BigInt with Sub::{sub}
#|pub extend BigInt with ToJson::{to_json}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend BigInt with @debug.Debug::{to_repr}
#|#deprecated("Use `@json.from_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend BigInt with @json.FromJson::{from_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend BigInt with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend BigInt with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend BigInt with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend BigInt with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend BigInt with Show::{output}
),
"strconv_errors.mbt": (
#|let syntax_err_str = "invalid syntax"
#|let base_err_str = "invalid base"
#|fn[T] syntax_err() -> T raise {
#| raise Failure::Failure(syntax_err_str)
#|}
#|fn[T] base_err() -> T raise {
#| raise Failure::Failure(base_err_str)
#|}
),
},
)
///|
let moonbitlang_core_buffer_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/buffer",
deps={},
files={
"buffer.mbt": (
#|struct Buffer {
#| mut data : FixedArray[Byte]
#| mut len : Int
#|}
#|fn buffer_growth_capacity(current : Int, len : Int, required : Int) -> Int {
#| if required < len {
#| abort("Buffer capacity overflow")
#| }
#| let start = if current <= 0 { 1 } else { current }
#| let enough_space = for space = start {
#| if space >= required {
#| break space
#| }
#| let next = space * 2
#| if next <= space {
#| break required
#| }
#| continue next
#| }
#| enough_space
#|}
#|fn Buffer::grow(self : Buffer, required : Int) -> Unit {
#| let new_capacity = buffer_growth_capacity(
#| self.data.length(),
#| self.len,
#| required,
#| )
#| let new_data = FixedArray::make_and_blit(
#| self.data,
#| allocate_len=new_capacity,
#| init=b'\x00',
#| len=self.len,
#| )
#| self.data = new_data
#|}
#|pub fn Buffer::length(self : Buffer) -> Int {
#| self.len
#|}
#|pub fn Buffer::is_empty(self : Buffer) -> Bool {
#| self.len == 0
#|}
#|#deprecated("use `Buffer()` instead (with `Buffer` in scope via the prelude)")
#|pub fn new(size_hint? : Int = 0) -> Buffer {
#| Buffer(size_hint~)
#|}
#|pub fn Buffer::Buffer(size_hint? : Int = 0) -> Buffer {
#| let initial = if size_hint < 1 { 1 } else { size_hint }
#| let data = FixedArray::make(initial, b'\x00')
#| { data, len: 0, }
#|}
#|pub fn from_bytes(bytes : BytesView) -> Buffer {
#| let val_len = bytes.length()
#| let buf = Buffer(size_hint=val_len)
#| buf.data.blit_from_bytes(0, bytes.data(), bytes.start_offset(), val_len)
#| buf.len = val_len
#| buf
#|}
#|pub fn from_array(arr : ArrayView[Byte]) -> Buffer {
#| let buf = Buffer(size_hint=arr.length())
#| let data = buf.data
#| let mut len = buf.len
#| for byte in arr {
#| data.unsafe_set(len, byte)
#| len += 1
#| }
#| buf.len = len
#| buf
#|}
#|pub fn from_iter(iter : Iter[Byte]) -> Buffer {
#| let buf = Buffer()
#| for byte in iter; capacity = buf.data.length() {
#| let capacity = if buf.len == capacity {
#| buf.grow(capacity + 1)
#| buf.data.length()
#| } else {
#| capacity
#| }
#| buf.data.unsafe_set(buf.len, byte)
#| buf.len += 1
#| continue capacity
#| }
#| buf
#|}
#|#deprecated("Buffer's current Logger impl writes UTF-16LE bytes; use StringBuilder or explicit Buffer encoders. A future breaking release may restore it with UTF-8 semantics.", skip_current_package=true)
#|pub impl Logger for Buffer
#|pub impl Logger for Buffer with fn write_string(self, value) {
#| let required = self.len + value.length() * 2
#| if required > self.data.length() || required < self.len {
#| self.grow(required)
#| }
#| self.data.blit_from_string(self.len, value, 0, value.length())
#| self.len += value.length() * 2
#|}
#|pub fn Buffer::write_uint64_be(self : Buffer, value : UInt64) -> Unit {
#| if self.data.length() - self.len < 8 {
#| self.grow(self.len + 8)
#| }
#| let data = self.data
#| let offset = self.len
#| data.unsafe_set(offset, (value >> 56).to_byte())
#| data.unsafe_set(offset + 1, (value >> 48).to_byte())
#| data.unsafe_set(offset + 2, (value >> 40).to_byte())
#| data.unsafe_set(offset + 3, (value >> 32).to_byte())
#| data.unsafe_set(offset + 4, (value >> 24).to_byte())
#| data.unsafe_set(offset + 5, (value >> 16).to_byte())
#| data.unsafe_set(offset + 6, (value >> 8).to_byte())
#| data.unsafe_set(offset + 7, value.to_byte())
#| self.len += 8
#|}
#|pub fn Buffer::write_uint64_le(self : Buffer, value : UInt64) -> Unit {
#| if self.data.length() - self.len < 8 {
#| self.grow(self.len + 8)
#| }
#| let data = self.data
#| let offset = self.len
#| data.unsafe_set(offset, value.to_byte())
#| data.unsafe_set(offset + 1, (value >> 8).to_byte())
#| data.unsafe_set(offset + 2, (value >> 16).to_byte())
#| data.unsafe_set(offset + 3, (value >> 24).to_byte())
#| data.unsafe_set(offset + 4, (value >> 32).to_byte())
#| data.unsafe_set(offset + 5, (value >> 40).to_byte())
#| data.unsafe_set(offset + 6, (value >> 48).to_byte())
#| data.unsafe_set(offset + 7, (value >> 56).to_byte())
#| self.len += 8
#|}
#|pub fn Buffer::write_int64_be(self : Buffer, value : Int64) -> Unit {
#| self.write_uint64_be(value.reinterpret_as_uint64())
#|}
#|pub fn Buffer::write_int64_le(self : Buffer, value : Int64) -> Unit {
#| self.write_uint64_le(value.reinterpret_as_uint64())
#|}
#|pub fn Buffer::write_uint_be(self : Buffer, value : UInt) -> Unit {
#| if self.data.length() - self.len < 4 {
#| self.grow(self.len + 4)
#| }
#| let data = self.data
#| let offset = self.len
#| data.unsafe_set(offset, (value >> 24).to_byte())
#| data.unsafe_set(offset + 1, (value >> 16).to_byte())
#| data.unsafe_set(offset + 2, (value >> 8).to_byte())
#| data.unsafe_set(offset + 3, value.to_byte())
#| self.len += 4
#|}
#|pub fn Buffer::write_uint_le(self : Buffer, value : UInt) -> Unit {
#| if self.data.length() - self.len < 4 {
#| self.grow(self.len + 4)
#| }
#| let data = self.data
#| let offset = self.len
#| data.unsafe_set(offset, value.to_byte())
#| data.unsafe_set(offset + 1, (value >> 8).to_byte())
#| data.unsafe_set(offset + 2, (value >> 16).to_byte())
#| data.unsafe_set(offset + 3, (value >> 24).to_byte())
#| self.len += 4
#|}
#|pub fn Buffer::write_int_be(self : Buffer, value : Int) -> Unit {
#| self.write_uint_be(value.reinterpret_as_uint())
#|}
#|pub fn Buffer::write_int_le(self : Buffer, value : Int) -> Unit {
#| self.write_uint_le(value.reinterpret_as_uint())
#|}
#|pub fn Buffer::write_uint16_be(self : Buffer, value : UInt16) -> Unit {
#| if self.data.length() - self.len < 2 {
#| self.grow(self.len + 2)
#| }
#| let data = self.data
#| let offset = self.len
#| data.unsafe_set(offset, (value.to_int() >> 8).to_byte())
#| data.unsafe_set(offset + 1, value.to_byte())
#| self.len += 2
#|}
#|pub fn Buffer::write_uint16_le(self : Buffer, value : UInt16) -> Unit {
#| if self.data.length() - self.len < 2 {
#| self.grow(self.len + 2)
#| }
#| let data = self.data
#| let offset = self.len
#| data.unsafe_set(offset, value.to_byte())
#| data.unsafe_set(offset + 1, (value.to_int() >> 8).to_byte())
#| self.len += 2
#|}
#|pub fn Buffer::write_int16_be(self : Buffer, value : Int16) -> Unit {
#| self.write_uint16_be(value.reinterpret_as_uint16())
#|}
#|pub fn Buffer::write_int16_le(self : Buffer, value : Int16) -> Unit {
#| self.write_uint16_le(value.reinterpret_as_uint16())
#|}
#|pub fn Buffer::write_double_be(self : Buffer, value : Double) -> Unit {
#| self.write_uint64_be(value.reinterpret_as_uint64())
#|}
#|pub fn Buffer::write_double_le(self : Buffer, value : Double) -> Unit {
#| self.write_uint64_le(value.reinterpret_as_uint64())
#|}
#|pub fn Buffer::write_float_be(self : Buffer, value : Float) -> Unit {
#| self.write_uint_be(value.reinterpret_as_uint())
#|}
#|pub fn Buffer::write_float_le(self : Buffer, value : Float) -> Unit {
#| self.write_uint_le(value.reinterpret_as_uint())
#|}
#|#deprecated("Buffer::write_object writes UTF-16LE bytes; use write_utf8 or explicit Buffer encoders. A future breaking release may restore it with UTF-8 semantics.", skip_current_package=true)
#|pub fn Buffer::write_object(self : Buffer, value : &Show) -> Unit {
#| self.write_string_utf16le(value.to_string())
#|}
#|#alias(write_bytes_interpolation)
#|pub fn[T : Show] Buffer::write_utf8(self : Buffer, value : T) -> Unit {
#| self.write_string_utf8(value.to_string())
#|}
#|pub fn Buffer::write_bytes(self : Buffer, value : BytesView) -> Unit {
#| self.write_bytesview(value)
#|}
#|pub fn Buffer::write_bytesview(self : Buffer, value : BytesView) -> Unit {
#| let val_len = value.length()
#| let required = self.len + val_len
#| if required > self.data.length() || required < self.len {
#| self.grow(required)
#| }
#| self.data.blit_from_bytes(
#| self.len,
#| value.data(),
#| value.start_offset(),
#| value.length(),
#| )
#| self.len += val_len
#|}
#|pub fn Buffer::write_char_utf8(buf : Self, value : Char) -> Unit {
#| let code = value.to_uint()
#| match code {
#| _..<0x80 => {
#| if buf.len >= buf.data.length() {
#| buf.grow(buf.len + 1)
#| }
#| buf.data.unsafe_set(buf.len, ((code & 0x7F) | 0x00).to_byte())
#| buf.len += 1
#| }
#| _..<0x0800 => {
#| if buf.data.length() - buf.len < 2 {
#| buf.grow(buf.len + 2)
#| }
#| let data = buf.data
#| let offset = buf.len
#| data.unsafe_set(offset, (((code >> 6) & 0x1F) | 0xC0).to_byte())
#| data.unsafe_set(offset + 1, ((code & 0x3F) | 0x80).to_byte())
#| buf.len += 2
#| }
#| _..<0x010000 => {
#| if buf.data.length() - buf.len < 3 {
#| buf.grow(buf.len + 3)
#| }
#| let data = buf.data
#| let offset = buf.len
#| data.unsafe_set(offset, (((code >> 12) & 0x0F) | 0xE0).to_byte())
#| data.unsafe_set(offset + 1, (((code >> 6) & 0x3F) | 0x80).to_byte())
#| data.unsafe_set(offset + 2, ((code & 0x3F) | 0x80).to_byte())
#| buf.len += 3
#| }
#| _..<0x110000 => {
#| if buf.data.length() - buf.len < 4 {
#| buf.grow(buf.len + 4)
#| }
#| let data = buf.data
#| let offset = buf.len
#| data.unsafe_set(offset, (((code >> 18) & 0x07) | 0xF0).to_byte())
#| data.unsafe_set(offset + 1, (((code >> 12) & 0x3F) | 0x80).to_byte())
#| data.unsafe_set(offset + 2, (((code >> 6) & 0x3F) | 0x80).to_byte())
#| data.unsafe_set(offset + 3, ((code & 0x3F) | 0x80).to_byte())
#| buf.len += 4
#| }
#| _ => abort("Char out of range")
#| }
#|}
#|pub fn Buffer::write_char_utf16le(buf : Self, value : Char) -> Unit {
#| let code = value.to_uint()
#| if code < 0x10000 {
#| if buf.data.length() - buf.len < 2 {
#| buf.grow(buf.len + 2)
#| }
#| let data = buf.data
#| let offset = buf.len
#| data.unsafe_set(offset, (code & 0xFF).to_byte())
#| data.unsafe_set(offset + 1, (code >> 8).to_byte())
#| buf.len += 2
#| } else if code < 0x110000 {
#| let cp = code - 0x10000
#| let high = (cp >> 10) | 0xD800
#| let low = (cp & 0x3FF) | 0xDC00
#| if buf.data.length() - buf.len < 4 {
#| buf.grow(buf.len + 4)
#| }
#| let data = buf.data
#| let offset = buf.len
#| data.unsafe_set(offset, (high & 0xFF).to_byte())
#| data.unsafe_set(offset + 1, (high >> 8).to_byte())
#| data.unsafe_set(offset + 2, (low & 0xFF).to_byte())
#| data.unsafe_set(offset + 3, (low >> 8).to_byte())
#| buf.len += 4
#| } else {
#| abort("Char out of range")
#| }
#|}
#|pub fn Buffer::write_char_utf16be(buf : Self, value : Char) -> Unit {
#| let code = value.to_uint()
#| if code < 0x10000 {
#| if buf.data.length() - buf.len < 2 {
#| buf.grow(buf.len + 2)
#| }
#| let data = buf.data
#| let offset = buf.len
#| data.unsafe_set(offset, (code >> 8).to_byte())
#| data.unsafe_set(offset + 1, (code & 0xFF).to_byte())
#| buf.len += 2
#| } else if code < 0x110000 {
#| if buf.data.length() - buf.len < 4 {
#| buf.grow(buf.len + 4)
#| }
#| let cp = code - 0x10000
#| let high = (cp >> 10) | 0xD800
#| let low = (cp & 0x3FF) | 0xDC00
#| let data = buf.data
#| let offset = buf.len
#| data.unsafe_set(offset, (high >> 8).to_byte())
#| data.unsafe_set(offset + 1, (high & 0xFF).to_byte())
#| data.unsafe_set(offset + 2, (low >> 8).to_byte())
#| data.unsafe_set(offset + 3, (low & 0xFF).to_byte())
#| buf.len += 4
#| } else {
#| abort("Char out of range")
#| }
#|}
#|pub fn Buffer::write_string_utf8(buf : Self, string : StringView) -> Unit {
#| for ch in string {
#| buf.write_char_utf8(ch)
#| }
#|}
#|#alias(write_stringview, deprecated="use write_string_utf16le instead")
#|pub fn Buffer::write_string_utf16le(buf : Self, string : StringView) -> Unit {
#| let len = string.length()
#| let required = buf.len + len * 2
#| if required > buf.data.length() || required < buf.len {
#| buf.grow(required)
#| }
#| let data = buf.data
#| for code_unit in string.code_units(); j = buf.len {
#| let c = code_unit.to_int().reinterpret_as_uint()
#| data.unsafe_set(j, (c & 0xff).to_byte())
#| data.unsafe_set(j + 1, (c >> 8).to_byte())
#| continue j + 2
#| }
#| buf.len += len * 2
#|}
#|pub fn Buffer::write_string_utf16be(buf : Self, string : StringView) -> Unit {
#| let len = string.length()
#| let required = buf.len + len * 2
#| if required > buf.data.length() || required < buf.len {
#| buf.grow(required)
#| }
#| let data = buf.data
#| for code_unit in string.code_units(); j = buf.len {
#| let c = code_unit.to_int().reinterpret_as_uint()
#| data.unsafe_set(j + 1, (c & 0xff).to_byte())
#| data.unsafe_set(j, (c >> 8).to_byte())
#| continue j + 2
#| }
#| buf.len += len * 2
#|}
#|pub impl Logger for Buffer with fn write_view(self : Buffer, value : StringView) -> Unit {
#| let required = self.len + value.length() * 2
#| if required > self.data.length() || required < self.len {
#| self.grow(required)
#| }
#| self.data.blit_from_string(
#| self.len,
#| value.data(),
#| value.start_offset(),
#| value.length(),
#| )
#| self.len += value.length() * 2
#|}
#|pub impl Logger for Buffer with fn write_char(self : Buffer, value : Char) -> Unit {
#| if self.data.length() - self.len < 4 {
#| self.grow(self.len + 4)
#| }
#| let inc = self.data.set_utf16le_char(self.len, value)
#| self.len += inc
#|}
#|pub fn Buffer::write_byte(self : Buffer, value : Byte) -> Unit {
#| if self.len >= self.data.length() {
#| self.grow(self.len + 1)
#| }
#| self.data.unsafe_set(self.len, value)
#| self.len += 1
#|}
#|pub fn Buffer::write_iter(self : Buffer, iter : Iter[Byte]) -> Unit {
#| for byte in iter {
#| self.write_byte(byte)
#| }
#|}
#|pub fn Buffer::reset(self : Buffer) -> Unit {
#| self.len = 0
#|}
#|#alias(contents)
#|pub fn Buffer::to_bytes(self : Buffer) -> Bytes {
#| Bytes::from_array(self.data[0:self.len])
#|}
#|pub fn Buffer::view(self : Buffer) -> ArrayView[Byte] {
#| self.data[0:self.len]
#|}
#|pub impl Show for Buffer with fn output(self, logger) {
#| logger.write_string(self.contents().to_unchecked_string())
#|}
),
"debug.mbt": (
#|pub impl @debug.Debug for Buffer with fn to_repr(self) {
#| @debug.Repr::opaque_("Buffer", Repr(self.to_bytes().to_array()))
#|}
#|test "Debug for Buffer" {
#| let buf = Buffer()
#| buf.write_bytes(b"ab")
#| @debug.debug_inspect(buf, content="")
#|}
),
"deprecated.mbt": "",
"extends.mbt": (
#|pub extend Buffer with Show::{to_string}
#|#deprecated
#|#warnings("-deprecated")
#|pub extend Buffer with Logger::{
#| write_view,
#| write_string,
#| write_string_interpolation,
#| write_char,
#| write,
#| write_substring,
#|}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Buffer with Show::{output}
#|#deprecated("Use `Debug::to_repr` via the trait or `Repr(x)` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Buffer with @debug.Debug::{to_repr}
),
"sleb128.mbt": (
#|trait Leb128 {
#| fn output(Self, Buffer) -> Unit
#|}
#|pub impl Leb128 for Int with fn output(self, buffer) {
#| let required = buffer.len + 5
#| if required > buffer.data.length() || required < buffer.len {
#| buffer.grow(required)
#| }
#| let data = buffer.data
#| let mut len = buffer.len
#| 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 || sign_bit_set
#| } else {
#| next_value != -1 || !sign_bit_set
#| }
#| if need_more {
#| data.unsafe_set(len, (byte | 0x80).to_byte())
#| len += 1
#| continue next_value
#| } else {
#| data.unsafe_set(len, byte.to_byte())
#| len += 1
#| break
#| }
#| }
#| buffer.len = len
#|}
#|pub impl Leb128 for Int64 with fn output(self, buffer) {
#| let required = buffer.len + 10
#| if required > buffer.data.length() || required < buffer.len {
#| buffer.grow(required)
#| }
#| let data = buffer.data
#| let mut len = buffer.len
#| 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 || sign_bit_set
#| } else {
#| next_value != -1 || !sign_bit_set
#| }
#| if need_more {
#| data.unsafe_set(len, (byte | 0x80).to_byte())
#| len += 1
#| continue next_value
#| } else {
#| data.unsafe_set(len, byte.to_byte())
#| len += 1
#| break
#| }
#| }
#| buffer.len = len
#|}
#|pub fn[A : Leb128] Buffer::write_leb128(buffer : Buffer, value : A) -> Unit {
#| value.output(buffer)
#|}
),
"uleb128.mbt": (
#|pub impl Leb128 for UInt with fn output(self, buffer) {
#| let required = buffer.len + 5
#| if required > buffer.data.length() || required < buffer.len {
#| buffer.grow(required)
#| }
#| let data = buffer.data
#| let mut len = buffer.len
#| for value = self {
#| if value < 128U {
#| data.unsafe_set(len, value.to_byte())
#| len += 1
#| break
#| } else {
#| data.unsafe_set(len, ((value & 127U) | 128U).to_byte())
#| len += 1
#| continue value >> 7
#| }
#| }
#| buffer.len = len
#|}
#|pub impl Leb128 for UInt64 with fn output(self, buffer) {
#| let required = buffer.len + 10
#| if required > buffer.data.length() || required < buffer.len {
#| buffer.grow(required)
#| }
#| let data = buffer.data
#| let mut len = buffer.len
#| for value = self {
#| if value < 128UL {
#| data.unsafe_set(len, value.to_byte())
#| len += 1
#| break
#| } else {
#| data.unsafe_set(len, ((value & 127UL) | 128UL).to_byte())
#| len += 1
#| continue value >> 7
#| }
#| }
#| buffer.len = len
#|}
),
},
)
///|
let moonbitlang_core_builtin_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/builtin",
deps={},
files={
"array.mbt": (
#|#owned(arr)
#|pub fn[T] Array::from_fixed_array(arr : FixedArray[T]) -> Array[T] {
#| let len = arr.length()
#| Array::unsafe_make_and_blit_from_fixed(arr, allocate_len=len, len~)
#|}
#|#owned(elem)
#|pub fn[T] Array::make(len : Int, elem : T) -> Array[T] {
#| let arr = Array::unsafe_make_uninit(len)
#| for i in 0.. T raise?) -> Array[T] raise? {
#| if length <= 0 {
#| []
#| } else {
#| let array = Array::unsafe_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().unsafe_get(idx)
#|}
#|#intrinsic("%array.get")
#|#alias("_[_]")
#|pub fn[T] Array::at(self : Array[T], index : Int) -> T {
#| let len = self.length()
#| guard! index >= 0 && index < len
#| self.buffer().unsafe_get(index)
#|}
#|#intrinsic("%array.get_opt")
#|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")
#|#owned(val)
#|pub fn[T] Array::unsafe_set(self : Array[T], idx : Int, val : T) -> Unit {
#| self.buffer().unsafe_set(idx, val)
#|}
#|#intrinsic("%array.set")
#|#alias("_[_]=_")
#|#owned(value)
#|pub fn[T] Array::set(self : Array[T], index : Int, value : T) -> Unit {
#| let len = self.length()
#| guard! index >= 0 && index < len
#| self.buffer().unsafe_set(index, value)
#|}
#|pub impl[T : Eq] Eq for Array[T] with fn 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 raise?) -> Unit raise? {
#| for v in self {
#| f(v)
#| }
#|}
#|#locals(f)
#|pub fn[T] Array::rev_each(
#| self : Array[T],
#| f : (T) -> Unit raise?,
#|) -> Unit raise? {
#| 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)
#| }
#|}
#|#locals(f)
#|#alias(every)
#|pub fn[T] Array::all(self : Array[T], f : (T) -> Bool raise?) -> Bool raise? {
#| for v in self {
#| if !f(v) {
#| return false
#| }
#| }
#| true
#|}
#|#locals(f)
#|#alias(exists)
#|pub fn[T] Array::any(self : Array[T], f : (T) -> Bool raise?) -> Bool raise? {
#| for v in self {
#| if f(v) {
#| return true
#| }
#| }
#| false
#|}
#|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::unsafe_make_uninit(self.length())
#| for i, v in self {
#| arr.unsafe_set(i, f(v))
#| }
#| arr
#|}
#|#locals(f)
#|#alias(map_inplace, deprecated)
#|pub fn[T] Array::map_in_place(
#| 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.is_empty() {
#| return []
#| }
#| let arr = Array::unsafe_make_uninit(self.length())
#| for i, v in self {
#| arr.unsafe_set(i, f(i, v))
#| }
#| arr
#|}
#|#locals(f)
#|#alias(mapi_inplace, deprecated)
#|pub fn[T] Array::mapi_in_place(
#| 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
#|}
#|#alias(rev_inplace, deprecated)
#|pub fn[T] Array::rev_in_place(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::unsafe_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::unsafe_make_and_blit(
#| self.buffer(),
#| allocate_len=index,
#| len=index,
#| )
#| let v2 = if index != self.length() {
#| let len2 = self.length() - index
#| Array::unsafe_make_and_blit(
#| self.buffer(),
#| allocate_len=len2,
#| src_offset=index,
#| len=len2,
#| )
#| } else {
#| Array::unsafe_make_uninit(0)
#| }
#| (v1, v2)
#|}
#|pub fn[T : Eq] Array::contains(self : Array[T], value : T) -> Bool {
#| for v in self {
#| if v == value {
#| break true
#| }
#| } nobreak {
#| false
#| }
#|}
#|pub fn[T : Eq] Array::count(self : Array[T], value : T) -> Int {
#| self[:].count(value)
#|}
#|#locals(f)
#|pub fn[T] Array::count_if(
#| self : Array[T],
#| f : (T) -> Bool raise?,
#|) -> Int raise? {
#| for v in self; count = 0 {
#| if f(v) {
#| continue count + 1
#| }
#| continue count
#| } nobreak {
#| count
#| }
#|}
#|pub fn[T : Eq] Array::starts_with(
#| self : Array[T],
#| prefix : ArrayView[T],
#|) -> Bool {
#| self[:].starts_with(prefix)
#|}
#|pub fn[T : Eq] Array::ends_with(self : Array[T], suffix : ArrayView[T]) -> Bool {
#| self[:].ends_with(suffix)
#|}
#|pub fn[T : Eq] Array::strip_prefix(
#| self : Array[T],
#| prefix : ArrayView[T],
#|) -> ArrayView[T]? {
#| self[:].strip_prefix(prefix)
#|}
#|pub fn[T : Eq] Array::strip_suffix(
#| self : Array[T],
#| suffix : ArrayView[T],
#|) -> ArrayView[T]? {
#| self[:].strip_suffix(suffix)
#|}
#|pub fn[T : Eq] Array::search(self : Array[T], value : T) -> Int? {
#| self[:].search(value)
#|}
#|#locals(f)
#|#alias(find_index, deprecated)
#|pub fn[T] Array::search_by(
#| self : Array[T],
#| f : (T) -> Bool raise?,
#|) -> Int? raise? {
#| for i, v in self {
#| if f(v) {
#| break Some(i)
#| }
#| } nobreak {
#| None
#| }
#|}
#|pub fn[T : Compare] Array::binary_search(
#| self : Array[T],
#| value : T,
#|) -> Result[Int, Int] {
#| self[:].binary_search(value)
#|}
#|pub fn[T] Array::binary_search_by(
#| self : Array[T],
#| cmp : (T) -> Int raise?,
#|) -> Result[Int, Int] raise? {
#| self[:].binary_search_by(cmp)
#|}
#|pub fn[T] Array::swap(self : Array[T], i : Int, j : Int) -> Unit {
#| if i >= self.length() || j >= self.length() || i < 0 || j < 0 {
#| index_out_of_bounds2(self.length(), 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()
#| let write = for read, v in self; write = 0 {
#| if f(v) {
#| if read != write {
#| self.unsafe_set(write, v)
#| }
#| continue write + 1
#| }
#| continue write
#| } nobreak {
#| write
#| }
#| if write != len {
#| self.unsafe_truncate_to_length(write)
#| }
#|}
#|pub fn[T] Array::resize(self : Array[T], new_len : Int, f : T) -> Unit {
#| if new_len < 0 {
#| abort("negative new length")
#| }
#| let len = self.length()
#| if new_len < len {
#| self.unsafe_truncate_to_length(new_len)
#| } else if new_len > len {
#| self.unsafe_resize_with_default(new_len, f)
#| }
#|}
#|pub fn[T] Array::flatten(self : Array[Array[T]]) -> Array[T] {
#| let len = for x in self; len = 0 {
#| continue len + x.length()
#| } nobreak {
#| len
#| }
#| let res = Array::unsafe_make_uninit(len)
#| for xs in self; i = 0 {
#| res.unsafe_blit(i, xs, 0, xs.length())
#| continue i + xs.length()
#| }
#| res
#|}
#|pub fn[T] Array::repeat(self : Array[T], times : Int) -> Array[T] {
#| if times < 0 {
#| abort("negative repeat count")
#| }
#| let len = self.length()
#| if times == 0 || len == 0 {
#| return []
#| }
#| let total = len * times
#| guard total / times == len else { abort("repeat result too large") }
#| let v = Array::Array(capacity=total)
#| for _ in 0.. B raise?,
#|) -> B raise? {
#| for item in self; acc = init {
#| continue f(acc, item)
#| } nobreak {
#| acc
#| }
#|}
#|#locals(f)
#|#alias(fold_right, deprecated)
#|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])
#| } nobreak {
#| acc
#| }
#|}
#|#locals(f)
#|#alias(fold_lefti, deprecated)
#|pub fn[A, B] Array::foldi(
#| self : Array[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| for i, x in self; acc = init {
#| continue f(i, acc, x)
#| } nobreak {
#| acc
#| }
#|}
#|#locals(f)
#|#alias(fold_righti, deprecated)
#|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 in len>..0; acc = init {
#| continue f(len - i - 1, acc, self[i])
#| } nobreak {
#| acc
#| }
#|}
#|pub fn[T : Eq] Array::dedup(self : Array[T]) -> Unit {
#| if self.is_empty() {
#| return
#| }
#| let w = for i in 1.. Bool raise?,
#|) -> Array[T] raise? {
#| let removed = []
#| for read in 0.. Array[ArrayView[T]] {
#| self[:].chunks(size)
#|}
#|#locals(pred)
#|pub fn[T] Array::chunk_by(
#| self : Array[T],
#| pred : (T, T) -> Bool raise?,
#|) -> Array[ArrayView[T]] raise? {
#| let chunks = []
#| if self.is_empty() {
#| return chunks
#| }
#| let start = for i in 1.. Array[ArrayView[T]] {
#| self[:].windows(size)
#|}
#|pub fn[T] Array::suffixes(
#| self : Array[T],
#| include_empty? : Bool = false,
#|) -> Iter[ArrayView[T]] {
#| self[:].suffixes(include_empty~)
#|}
#|#locals(pred)
#|pub fn[T] Array::split(
#| self : Array[T],
#| pred : (T) -> Bool raise?,
#|) -> Array[Array[T]] raise? {
#| let chunks = []
#| for i = 0; i < self.length(); {
#| let chunk = []
#| let i = for i = i; i < self.length() && !pred(self[i]); {
#| chunk.push(self[i])
#| continue i + 1
#| } nobreak {
#| i
#| }
#| chunks.push(chunk)
#| continue i + 1
#| }
#| chunks
#|}
#|#alias(iterator, deprecated)
#|pub fn[T] Array::iter(self : Array[T]) -> Iter[T] {
#| self[:].iter()
#|}
#|#alias(rev_iterator, deprecated)
#|pub fn[T] Array::rev_iter(self : Array[T]) -> Iter[T] {
#| self[:].rev_iter()
#|}
#|#alias(iterator2, deprecated)
#|pub fn[A] Array::iter2(self : Array[A]) -> Iter2[Int, A] {
#| self[:].iter2()
#|}
#|pub impl[T] Default for Array[T] with fn default() {
#| []
#|}
#|#internal(unsafe, "Panic if the array is empty on non-JS backend.")
#|#doc(hidden)
#|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)
#|}
#|#locals(f)
#|pub fn[A] Array::retain_map(
#| self : Array[A],
#| f : (A) -> A? raise?,
#|) -> Unit raise? {
#| if self.is_empty() {
#| return
#| }
#| let buf = self.buffer()
#| let len = self.length()
#| for read_idx in 0.. {
#| buf[write_idx] = new_val
#| continue write_idx + 1
#| }
#| None => continue write_idx
#| }
#| } nobreak {
#| self.unsafe_truncate_to_length(write_idx)
#| }
#|}
#|#alias(from_iterator, deprecated)
#|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 {
#| if iter.size_hint() is Some(n) {
#| self.reserve_capacity(self.length() + n)
#| }
#| for x in iter {
#| self.push(x)
#| }
#|}
#|#locals(rand)
#|pub fn[T] Array::shuffle_in_place(
#| self : Array[T],
#| rand~ : (Int) -> Int,
#|) -> Unit {
#| let n = self.length()
#| for i in n>..1 {
#| let j = rand(i + 1) % (i + 1)
#| self.swap(i, j)
#| }
#|}
#|pub fn[T] Array::shuffle(self : Array[T], rand~ : (Int) -> Int) -> Array[T] {
#| let new_arr = self.copy()
#| Array::shuffle_in_place(new_arr, rand~)
#| new_arr
#|}
#|#locals(f)
#|pub fn[A, B] Array::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] Array::last(self : Array[A]) -> A? {
#| match self {
#| [] => None
#| [.., last] => Some(last)
#| }
#|}
#|pub fn[A, B] Array::zip(self : Array[A], other : Array[B]) -> Array[(A, B)] {
#| let length = if self.length() < other.length() {
#| self.length()
#| } else {
#| other.length()
#| }
#| Array::makei(length, i => (self[i], other[i]))
#|}
#|pub fn[T1, T2] Array::unzip(self : Array[(T1, T2)]) -> (Array[T1], Array[T2]) {
#| let arr1 : Array[T1] = Array(capacity=self.length())
#| let arr2 : Array[T2] = Array(capacity=self.length())
#| for pair in self {
#| let (x, y) = pair
#| arr1.push(x)
#| arr2.push(y)
#| }
#| (arr1, arr2)
#|}
#|pub fn[A, B] Array::zip_to_iter2(
#| self : Array[A],
#| other : Array[B],
#|) -> Iter2[A, B] {
#| let length = if self.length() < other.length() {
#| self.length()
#| } else {
#| other.length()
#| }
#| let mut i = 0
#| Iter2::new(
#| () => {
#| guard i < length else { None }
#| let elem = (self[i], other[i])
#| i += 1
#| Some(elem)
#| },
#| size_hint=length,
#| ).iter2()
#|}
#|pub fn[A : ToStringView] Array::join(
#| self : Array[A],
#| separator : StringView,
#|) -> String {
#| self[:].join(separator)
#|}
#|pub fn[T : Compare] Array::lexical_compare(
#| self : Array[T],
#| other : Array[T],
#|) -> Int {
#| self[:].lexical_compare(other)
#|}
),
"array_block.mbt": (
#|#internal(unsafe, "Panic if the indices or length are out of bounds")
#|#doc(hidden)
#|pub fn[A] Array::unsafe_blit(
#| dst : Array[A],
#| dst_offset : Int,
#| src : Array[A],
#| src_offset : Int,
#| len : Int,
#|) -> Unit {
#| FixedArray::unsafe_blit(
#| dst.buffer().0,
#| dst_offset,
#| src.buffer().0,
#| src_offset,
#| len,
#| )
#|}
#|pub fn[A] Array::unsafe_blit_fixed(
#| dst : Array[A],
#| dst_offset : Int,
#| src : FixedArray[A],
#| src_offset : Int,
#| len : Int,
#|) -> Unit {
#| UninitializedArray::unsafe_blit_fixed(
#| dst.buffer(),
#| dst_offset,
#| src,
#| src_offset,
#| len,
#| )
#|}
#|test "Array::blit_to/basic" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| src[1:4].blit_to(dst, dst_offset=2)
#| assert_true(dst == [0, 0, 2, 3, 4])
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| src[0:3].blit_to(dst)
#| assert_true(dst == [1, 2, 3, 0, 0])
#|}
#|test "Array::blit_to/zero_length" {
#| let src = [1, 2, 3]
#| let dst = [4, 5, 6]
#| src[0:0].blit_to(dst)
#| assert_true(dst == [4, 5, 6])
#|}
#|test "Array::blit_to/grow_destination" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0]
#| src[0:3].blit_to(dst, dst_offset=1)
#| assert_true(dst == [0, 1, 2, 3])
#|}
#|#warnings("-deprecated")
#|test "Array::blit_to/grow_destination_directly" {
#| let src = [1, 2, 3, 4]
#| let dst = [0]
#| Array::blit_to(src, dst, len=2, src_offset=1, dst_offset=1)
#| assert_true(dst == [0, 2, 3])
#| let self = [1, 2, 3]
#| Array::blit_to(self, self, len=2, dst_offset=3)
#| assert_true(self == [1, 2, 3, 1, 2])
#|}
#|test "Array::blit_to/edge_cases" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| src[1:3].blit_to(dst, dst_offset=2)
#| assert_true(dst == [0, 0, 2, 3, 0])
#| src[0:2].blit_to(src, dst_offset=3)
#| assert_true(src == [1, 2, 3, 1, 2])
#| src[0:0].blit_to(dst, dst_offset=0)
#| assert_true(dst == [0, 0, 2, 3, 0])
#| src[0:5].blit_to(dst)
#| assert_true(dst == [1, 2, 3, 1, 2])
#|}
#|test "panic Array::blit_to/boundary_cases1" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| ignore(src.exact_view(start=3, end=1).blit_to(dst))
#|}
#|test "panic Array::blit_to/boundary_cases2" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| ignore(src.exact_view(start=-1, end=1).blit_to(dst))
#|}
#|test "panic Array::blit_to/boundary_cases3" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| ignore(src.exact_view(start=0, end=6).blit_to(dst))
#|}
#|test "panic Array::blit_to/boundary_cases4" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| ignore(src[0:5].blit_to(dst, dst_offset=6))
#|}
#|#warnings("-deprecated")
#|test "panic Array::blit_to/reject_overflowed_source_range" {
#| let src = [1]
#| let dst = [0]
#| Array::blit_to(src, dst, len=0x7fffffff, src_offset=1)
#|}
#|test "Array::blit_to - random cases" {
#| let src = [10, 20, 30, 40, 50]
#| let dst = [0, 0, 0, 0, 0]
#| src[2:4].blit_to(dst, dst_offset=1)
#| assert_true(dst == [0, 30, 40, 0, 0])
#| src[1:4].blit_to(dst, dst_offset=2)
#| assert_true(dst == [0, 30, 20, 30, 40])
#| src[4:5].blit_to(dst, dst_offset=4)
#| assert_true(dst == [0, 30, 20, 30, 50])
#|}
#|test "Array::blit_to - boundary cases" {
#| let src = [1, 2, 3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| src[4:5].blit_to(dst, dst_offset=0)
#| assert_true(dst == [5, 0, 0, 0, 0])
#| src[0:1].blit_to(dst, dst_offset=4)
#| assert_true(dst == [5, 0, 0, 0, 1])
#| src[3:5].blit_to(dst, dst_offset=3)
#| assert_true(dst == [5, 0, 0, 4, 5])
#|}
#|test "Array::unsafe_blit_fixed" {
#| let src = FixedArray::make(3, 1) // Create a FixedArray with 3 elements of value 1
#| let dst = Array::make(5, 0) // Create an Array with 5 elements of value 0
#| Array::unsafe_blit_fixed(dst, 1, src, 0, 2) // Copy 2 elements from src[0] to dst[1]
#| assert_true(dst == [0, 1, 1, 0, 0])
#|}
#|test "ArrayView::blit_to/basic" {
#| let src = [1, 2, 3, 4, 5]
#| let view = src[1:4] // view = [2, 3, 4]
#| let dst = [0, 0, 0, 0, 0]
#| view.blit_to(dst)
#| assert_true(dst == [2, 3, 4, 0, 0])
#|}
#|test "ArrayView::blit_to/with_offset" {
#| let src = [1, 2, 3, 4, 5]
#| let view = src[1:4] // view = [2, 3, 4]
#| let dst = [0, 0, 0, 0, 0]
#| view.blit_to(dst, dst_offset=2)
#| assert_true(dst == [0, 0, 2, 3, 4])
#|}
#|test "ArrayView::blit_to/grow_destination" {
#| let src = [1, 2, 3, 4, 5]
#| let view = src[1:4] // view = [2, 3, 4]
#| let dst = [0, 0]
#| view.blit_to(dst, dst_offset=1)
#| assert_true(dst == [0, 2, 3, 4])
#|}
#|test "ArrayView::blit_to/empty_view" {
#| let src = [1, 2, 3, 4, 5]
#| let view = src[2:2] // empty view
#| let dst = [0, 0, 0]
#| view.blit_to(dst)
#| assert_true(dst == [0, 0, 0])
#|}
#|test "ArrayView::blit_to/nested_view" {
#| let src = [1, 2, 3, 4, 5, 6, 7]
#| let view1 = src[1:6] // [2, 3, 4, 5, 6]
#| let view2 = view1[1:4] // [3, 4, 5]
#| let dst = [0, 0, 0, 0, 0]
#| view2.blit_to(dst, dst_offset=1)
#| assert_true(dst == [0, 3, 4, 5, 0])
#|}
#|test "panic ArrayView::blit_to/invalid_offset" {
#| let src = [1, 2, 3, 4, 5]
#| let view = src[1:4]
#| let dst = [0, 0, 0]
#| ignore(view.blit_to(dst, dst_offset=-1))
#|}
#|test "panic ArrayView::blit_to/offset_exceeds_length" {
#| let src = [1, 2, 3, 4, 5]
#| let view = src[1:4]
#| let dst = [0, 0, 0]
#| ignore(view.blit_to(dst, dst_offset=4))
#|}
),
"array_sort.mbt": (
#|pub fn[T] MutArrayView::sort_by(self : Self[T], cmp : (T, T) -> Int) -> Unit {
#| fixed_quick_sort_by(self, cmp, None, fixed_get_limit(self.length()))
#|}
#|pub fn[T : Compare] MutArrayView::sort(self : MutArrayView[T]) -> Unit {
#| fixed_quick_sort(self, None, fixed_get_limit(self.length()))
#|}
#|pub fn[T : Compare] MutArrayView::stable_sort(self : MutArrayView[T]) -> Unit {
#| timsort(self)
#|}
#|pub fn[T, K : Compare] MutArrayView::sort_by_key(
#| self : Self[T],
#| map : (T) -> K,
#|) -> Unit {
#| fixed_quick_sort_by(
#| self,
#| (a, b) => map(a).compare(map(b)),
#| None,
#| fixed_get_limit(self.length()),
#| )
#|}
#|pub fn[T : Compare] ArrayView::is_sorted(self : ArrayView[T]) -> Bool {
#| for i in 1.. self[i] {
#| break false
#| }
#| } nobreak {
#| true
#| }
#|}
#|pub fn[T : Compare] Array::is_sorted(self : Array[T]) -> Bool {
#| self[:].is_sorted()
#|}
#|pub fn[T : Compare] Array::sort(self : Array[T]) -> Unit {
#| self.mut_view().sort()
#|}
#|pub fn[T, K : Compare] Array::sort_by_key(
#| self : Array[T],
#| map : (T) -> K,
#|) -> Unit {
#| self.mut_view().sort_by_key(map)
#|}
#|pub fn[T] Array::sort_by(self : Array[T], cmp : (T, T) -> Int) -> Unit {
#| self.mut_view().sort_by(cmp)
#|}
#|pub fn[T : Compare] FixedArray::is_sorted(arr : FixedArray[T]) -> Bool {
#| arr[:].is_sorted()
#|}
#|pub fn[T : Compare] FixedArray::stable_sort(self : FixedArray[T]) -> Unit {
#| self.mut_view().stable_sort()
#|}
#|pub fn[T, K : Compare] FixedArray::sort_by_key(
#| self : FixedArray[T],
#| map : (T) -> K,
#|) -> Unit {
#| self.mut_view().sort_by_key(map)
#|}
#|test "FixedArray::sort_by_key/basic" {
#| let arr : FixedArray[_] = [3, 1, 4, 1, 5]
#| arr.sort_by_key(x => x)
#| assert_true(arr == [1, 1, 3, 4, 5])
#| let arr2 : FixedArray[_] = [3, 1, 4, 1, 5]
#| arr2.sort_by_key(x => -x)
#| assert_true(arr2 == [5, 4, 3, 1, 1])
#|}
#|pub fn[T] FixedArray::sort_by(
#| self : FixedArray[T],
#| cmp : (T, T) -> Int,
#|) -> Unit {
#| self.mut_view().sort_by(cmp)
#|}
#|test "FixedArray::sort_by: basic functionality" {
#| let arr : FixedArray[_] = [5, 3, 2, 4, 1]
#| arr.sort_by((a, b) => a - b)
#| assert_true(arr == [1, 2, 3, 4, 5])
#|}
#|test "FixedArray::sort_by: edge cases" {
#| let empty_arr : FixedArray[Int] = []
#| empty_arr.sort_by((a, b) => a - b)
#| assert_true(empty_arr == [])
#| let single_element_arr : FixedArray[_] = [1]
#| single_element_arr.sort_by((a, b) => a - b)
#| assert_true(single_element_arr == [1])
#|}
#|test "FixedArray::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)
#| assert_true(random_arr1 == [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)
#| assert_true(random_arr2 == [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)
#| assert_true(random_arr3 == [-1, -1, -1, 0, 0, 0, 10, 10, 10])
#|}
#|test "FixedArray::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)
#| assert_true(large_arr == expected)
#|}
#|test "FixedArray::sort_by: negative numbers" {
#| let negative_arr : FixedArray[_] = [-5, -3, -2, -4, -1]
#| negative_arr.sort_by((a, b) => a - b)
#| assert_true(negative_arr == [-5, -4, -3, -2, -1])
#|}
#|test "FixedArray::sort_by: mixed positive and negative numbers" {
#| let mixed_arr : FixedArray[_] = [-5, 3, -2, 4, -1]
#| mixed_arr.sort_by((a, b) => a - b)
#| assert_true(mixed_arr == [-5, -2, -1, 3, 4])
#|}
),
"array_sort_by_impl.mbt": (
#|fn[T] fixed_quick_sort_by(
#| arr : MutArrayView[T],
#| cmp : (T, T) -> Int,
#| pred : T?,
#| limit : Int,
#|) -> Unit {
#| let bubble_sort_len = 16
#| for limit = limit, arr = arr, pred = pred, was_partitioned = true, balanced = 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)
#| let was_partitioned = partitioned
#| let balanced = minimum(pivot, len - pivot) >= len / 8
#| let limit = if !balanced { limit - 1 } else { limit }
#| if pred is Some(p) {
#| if cmp(p, arr.unsafe_get(pivot)) == 0 {
#| let i = for i = pivot; i < len && cmp(p, arr.unsafe_get(i)) == 0; {
#| continue i + 1
#| } nobreak {
#| i
#| }
#| continue limit, arr.slice(i, len), pred, was_partitioned, balanced
#| }
#| }
#| 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)
#| continue limit,
#| right,
#| Some(arr.unsafe_get(pivot)),
#| was_partitioned,
#| balanced
#| } else {
#| fixed_quick_sort_by(right, cmp, Some(arr.unsafe_get(pivot)), limit)
#| continue limit, left, pred, was_partitioned, balanced
#| }
#| }
#|}
#|fn[T] fixed_try_bubble_sort_by(
#| arr : MutArrayView[T],
#| cmp : (T, T) -> Int,
#|) -> Bool {
#| let max_tries = 8
#| for i in 1.. 0 &&
#| cmp(arr.unsafe_get(j - 1), arr.unsafe_get(j)) > 0; {
#| arr.swap(j, j - 1)
#| continue j - 1, false
#| } nobreak {
#| sorted
#| }
#| if !sorted {
#| let tries = tries + 1
#| if tries > max_tries {
#| break false
#| }
#| continue tries
#| } else {
#| continue tries
#| }
#| } nobreak {
#| true
#| }
#|}
#|fn[T] fixed_bubble_sort_by(arr : MutArrayView[T], cmp : (T, T) -> Int) -> Unit {
#| for i in 1.. 0 && cmp(arr.unsafe_get(j - 1), arr.unsafe_get(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(arr.mut_view(), (a, b) => a - b)
#| inspect(sorted, content="true")
#| assert_true(arr == [1, 2, 3, 4, 5, 6, 7, 8])
#|}
#|fn[T] fixed_partition_by(
#| arr : MutArrayView[T],
#| cmp : (T, T) -> Int,
#| pivot_index : Int,
#|) -> (Int, Bool) {
#| arr.swap(pivot_index, arr.length() - 1)
#| let pivot = arr.unsafe_get(arr.length() - 1)
#| let (i, partitioned) = for
#| j in 0..<(arr.length() - 1)
#| i = 0, partitioned = true {
#| if cmp(arr.unsafe_get(j), pivot) < 0 {
#| if i != j {
#| arr.swap(i, j)
#| continue i + 1, false
#| } else {
#| continue i + 1, partitioned
#| }
#| } else {
#| continue i, partitioned
#| }
#| } nobreak {
#| (i, partitioned)
#| }
#| arr.swap(i, arr.length() - 1)
#| (i, partitioned)
#|}
#|fn[T] fixed_choose_pivot_by(
#| arr : MutArrayView[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.unsafe_get(a), arr.unsafe_get(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_in_place()
#| (len - b - 1, true)
#| } else {
#| (b, swaps == 0)
#| }
#|}
#|fn[T] fixed_heap_sort_by(arr : MutArrayView[T], cmp : (T, T) -> Int) -> Unit {
#| let len = arr.length()
#| for i in (len / 2)>..0 {
#| fixed_sift_down_by(arr, i, cmp)
#| }
#| for i in len>..1 {
#| arr.swap(0, i)
#| fixed_sift_down_by(arr.slice(0, i), 0, cmp)
#| }
#|}
#|fn[T] fixed_sift_down_by(
#| arr : MutArrayView[T],
#| index : Int,
#| cmp : (T, T) -> Int,
#|) -> Unit {
#| let len = arr.length()
#| for index = index, child = index * 2 + 1; child < len; {
#| let child = if child + 1 < len &&
#| cmp(arr.unsafe_get(child), arr.unsafe_get(child + 1)) < 0 {
#| child + 1
#| } else {
#| child
#| }
#| if cmp(arr.unsafe_get(index), arr.unsafe_get(child)) >= 0 {
#| return
#| }
#| arr.swap(index, child)
#| continue child, child * 2 + 1
#| }
#|}
#|test "heap_sort" {
#| fixed_test_sort(arr => fixed_heap_sort_by(arr.mut_view(), (a, b) => a - b))
#|}
#|test "bubble_sort" {
#| fixed_test_sort(arr => fixed_bubble_sort_by(arr.mut_view(), (a, b) => a - b))
#|}
#|test "sort" {
#| fixed_test_sort(arr => arr.sort())
#|}
#|test "sort_by" {
#| let arr = [5, 1, 3, 4, 2]
#| arr.mut_view().sort_by_key(x => -x)
#| assert_true(arr == [5, 4, 3, 2, 1])
#|}
#|test "sort_by_fallback" {
#| let arr = FixedArray::makei(100, i => if i % 2 == 0 { 1 } else { 0 })
#| arr
#| .mut_view()
#| .sort_by(
#| (a, b) => if a < b { -1 } else { 1 },
#| )
#| assert_true(arr.is_sorted())
#|}
),
"array_sort_impl.mbt": (
#|priv struct TimSortRun {
#| len : Int
#| start : Int
#|}
#|fn[T : Compare] timsort(arr : MutArrayView[T]) -> Unit {
#| let max_insertion = 20
#| let len = arr.length()
#| if len <= max_insertion {
#| MutArrayView::insertion_sort(arr)
#| return
#| }
#| let runs : Array[TimSortRun] = []
#| for start = 0, end = 0; end < len; {
#| let (streak_end, was_reversed) = find_streak(arr.mut_view(start~))
#| let end = end + streak_end
#| if was_reversed {
#| arr.mut_view(start~, end~).rev_in_place()
#| }
#| let end = provide_sorted_batch(arr, start, end)
#| runs.push({ start, len: end - start, })
#| 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
#| }
#| continue end, end
#| }
#|}
#|fn[T : Compare] MutArrayView::insertion_sort(arr : MutArrayView[T]) -> Unit {
#| for i in 1.. 0 && arr.unsafe_get(j) < arr.unsafe_get(j - 1); j = j - 1 {
#| arr.swap(j, j - 1)
#| }
#| }
#|}
#|fn[T : Compare] merge(arr : MutArrayView[T], mid : Int) -> Unit {
#| let buf_len = arr.length() - mid
#| let buf = UninitializedArray::make_and_blit(
#| arr.buf(),
#| allocate_len=buf_len,
#| src_offset=arr.start() + mid,
#| len=buf_len,
#| )
#| let buf_remaining = for p1 = mid - 1, p2 = buf_len - 1, p = mid + buf_len - 1; p1 >=
#| 0 &&
#| p2 >= 0; {
#| if arr.unsafe_get(p1) > buf[p2] {
#| arr.unsafe_set(p, arr.unsafe_get(p1))
#| continue p1 - 1, p2, p - 1
#| } else {
#| arr.unsafe_set(p, buf[p2])
#| continue p1, p2 - 1, p - 1
#| }
#| } nobreak {
#| p2
#| }
#| if buf_remaining >= 0 {
#| UninitializedArray::unsafe_blit(
#| arr.buf(),
#| arr.start(),
#| buf,
#| 0,
#| buf_remaining + 1,
#| )
#| }
#|}
#|fn[T : Compare] find_streak(arr : MutArrayView[T]) -> (Int, Bool) {
#| let len = arr.length()
#| if len < 2 {
#| return (len, false)
#| }
#| let assume_reverse = arr.unsafe_get(1) < arr.unsafe_get(0)
#| if assume_reverse {
#| let end = for idx in 2..= arr.unsafe_get(idx - 1) {
#| continue
#| }
#| break idx
#| } nobreak {
#| len
#| }
#| (end, false)
#| }
#|}
#|fn[T : Compare] provide_sorted_batch(
#| arr : MutArrayView[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)
#| MutArrayView::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 {
#| self.mut_view().sort()
#|}
#|fn[T] MutArrayView::slice(
#| arr : MutArrayView[T],
#| start : Int,
#| end : Int,
#|) -> MutArrayView[T] {
#| arr.mut_view(start~, end~)
#|}
#|fn[T] MutArrayView::swap(arr : MutArrayView[T], i : Int, j : Int) -> Unit {
#| let temp = arr.unsafe_get(i)
#| arr.unsafe_set(i, arr.unsafe_get(j))
#| arr.unsafe_set(j, temp)
#|}
#|fn[T] MutArrayView::rev_in_place(arr : MutArrayView[T]) -> Unit {
#| let len = arr.length()
#| let mid_len = len / 2
#| for i in 0.. Unit {
#| let bubble_sort_len = 16
#| for limit = limit, arr = arr, pred = pred, was_partitioned = true, balanced = 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)
#| let was_partitioned = partitioned
#| let balanced = minimum(pivot, len - pivot) >= len / 8
#| let limit = if !balanced { limit - 1 } else { limit }
#| if pred is Some(p) {
#| if p == arr.unsafe_get(pivot) {
#| let i = for i = pivot; i < len && p == arr.unsafe_get(i); {
#| continue i + 1
#| } nobreak {
#| i
#| }
#| continue limit, arr.slice(i, len), pred, was_partitioned, balanced
#| }
#| }
#| let left = arr.slice(0, pivot)
#| let right = arr.slice(pivot + 1, len)
#| if left.length() < right.length() {
#| fixed_quick_sort(left, pred, limit)
#| continue limit,
#| right,
#| Some(arr.unsafe_get(pivot)),
#| was_partitioned,
#| balanced
#| } else {
#| fixed_quick_sort(right, Some(arr.unsafe_get(pivot)), limit)
#| continue limit, left, pred, was_partitioned, balanced
#| }
#| }
#|}
#|fn fixed_get_limit(len : Int) -> Int {
#| for len = len, limit = 0; len > 0; {
#| continue len / 2, limit + 1
#| } nobreak {
#| limit
#| }
#|}
#|fn[T : Compare] fixed_try_bubble_sort(arr : MutArrayView[T]) -> Bool {
#| let max_tries = 8
#| for i in 1.. 0 &&
#| arr.unsafe_get(j - 1) > arr.unsafe_get(j); {
#| arr.swap(j, j - 1)
#| continue j - 1, false
#| } nobreak {
#| sorted
#| }
#| if !sorted {
#| let tries = tries + 1
#| if tries > max_tries {
#| break false
#| }
#| continue tries
#| } else {
#| continue tries
#| }
#| } nobreak {
#| true
#| }
#|}
#|fn[T : Compare] fixed_bubble_sort(arr : MutArrayView[T]) -> Unit {
#| for i in 1.. 0 && arr.unsafe_get(j - 1) > arr.unsafe_get(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(arr.mut_view())
#| inspect(sorted, content="true")
#| assert_true(arr == [1, 2, 3, 4, 5, 6, 7, 8])
#|}
#|fn[T : Compare] fixed_partition(
#| arr : MutArrayView[T],
#| pivot_index : Int,
#|) -> (Int, Bool) {
#| arr.swap(pivot_index, arr.length() - 1)
#| let pivot = arr.unsafe_get(arr.length() - 1)
#| let (i, partitioned) = for
#| j in 0..<(arr.length() - 1)
#| i = 0, partitioned = true {
#| if arr.unsafe_get(j) < pivot {
#| if i != j {
#| arr.swap(i, j)
#| continue i + 1, false
#| } else {
#| continue i + 1, partitioned
#| }
#| } else {
#| continue i, partitioned
#| }
#| } nobreak {
#| (i, partitioned)
#| }
#| arr.swap(i, arr.length() - 1)
#| (i, partitioned)
#|}
#|fn[T : Compare] fixed_choose_pivot(arr : MutArrayView[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.unsafe_get(a) > arr.unsafe_get(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_in_place()
#| (len - b - 1, true)
#| } else {
#| (b, swaps == 0)
#| }
#|}
#|fn[T : Compare] fixed_heap_sort(arr : MutArrayView[T]) -> Unit {
#| let len = arr.length()
#| for i in (len / 2)>..0 {
#| fixed_sift_down(arr, i)
#| }
#| for i in len>..1 {
#| arr.swap(0, i)
#| fixed_sift_down(arr.slice(0, i), 0)
#| }
#|}
#|fn[T : Compare] fixed_sift_down(arr : MutArrayView[T], index : Int) -> Unit {
#| let len = arr.length()
#| for index = index, child = index * 2 + 1; child < len; {
#| let child = if child + 1 < len &&
#| arr.unsafe_get(child) < arr.unsafe_get(child + 1) {
#| child + 1
#| } else {
#| child
#| }
#| if arr.unsafe_get(index) >= arr.unsafe_get(child) {
#| return
#| }
#| arr.swap(index, child)
#| continue child, child * 2 + 1
#| }
#|}
#|fn fixed_test_sort(f : (MutArrayView[Int]) -> Unit) -> Unit raise {
#| let arr : FixedArray[_] = [5, 4, 3, 2, 1]
#| f(arr.mut_view())
#| assert_true(arr == [1, 2, 3, 4, 5])
#| let arr : FixedArray[_] = [5, 5, 5, 5, 1]
#| f(arr.mut_view())
#| assert_true(arr == [1, 5, 5, 5, 5])
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| f(arr.mut_view())
#| assert_true(arr == [1, 2, 3, 4, 5])
#| let arr = FixedArray::make(1000, 0)
#| for i in 0..<1000 {
#| arr[i] = 1000 - i - 1
#| }
#| for step in 1..<100 {
#| let i = step * 10
#| arr.swap(i, i - 1)
#| }
#| f(arr.mut_view())
#| let expected = FixedArray::make(1000, 0)
#| for i in 0..<1000 {
#| expected[i] = i
#| }
#| assert_true(arr == expected)
#|}
#|test "fixed_heap_sort" {
#| fixed_test_sort(arr => fixed_heap_sort(arr.mut_view()))
#|}
#|test "fixed_bubble_sort" {
#| fixed_test_sort(arr => fixed_bubble_sort(arr.mut_view()))
#|}
#|test "sort" {
#| fixed_test_sort(arr => arr.sort())
#|}
#|test "stable_sort" {
#| let arr : FixedArray[_] = [5, 1, 3, 4, 2]
#| arr.mut_view().stable_sort()
#| assert_true(arr == [1, 2, 3, 4, 5])
#| let arr = FixedArray::make(1000, 0)
#| for i in 0..<1000 {
#| arr[i] = 1000 - i - 1
#| }
#| for step in 1..<100 {
#| let i = step * 10
#| arr.swap(i, i - 1)
#| }
#| arr.mut_view().stable_sort()
#| let expected = FixedArray::make(1000, 0)
#| for i in 0..<1000 {
#| expected[i] = i
#| }
#| assert_true(arr == expected)
#|}
#|test "stable_sort_complex" {
#| let run_lens = [86, 64, 21, 20, 22]
#| let total_len = run_lens.fold(init=0, (acc, x) => acc + x)
#| let arr = FixedArray::make(total_len, 0)
#| for i in 0.. Int {
#| if x > y {
#| y
#| } else {
#| x
#| }
#|}
),
"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"
#|fn[T] JSArray::ofAnyFixedArray(array : FixedArray[T]) -> JSArray = "%identity"
#|fn[T] JSArray::toAnyFixedArray(self : JSArray) -> FixedArray[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::append_view(
#| self : JSArray,
#| src : JSArray,
#| src_offset : Int,
#| len : Int,
#|) -> Unit =
#| #| (dst, src, src_offset, len) => {
#| #| for (let i = 0; i < len; i++) {
#| #| dst.push(src[src_offset + i]);
#| #| }
#| #| }
#|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)
#|extern "js" fn JSArray::copy(self : JSArray) -> JSArray =
#| #|(arr) => arr.slice(0)
#|#external
#|type Array[T]
#|#doc(hidden)
#|pub fn[T] Array::unsafe_make_uninit(len : Int) -> Array[T] = "%fixedarray.make_uninit"
#|fn[T] Array::unsafe_make_and_blit(
#| src : UninitializedArray[T],
#| allocate_len~ : Int,
#| len~ : Int,
#| src_offset? : Int = 0,
#| dst_offset? : Int = 0,
#|) -> Array[T] {
#| let dst = Array::unsafe_make_uninit(allocate_len)
#| UninitializedArray::unsafe_blit(
#| dst.buffer(),
#| dst_offset,
#| src,
#| src_offset,
#| len,
#| )
#| dst
#|}
#|fn[T] Array::unsafe_make_and_blit_from_fixed(
#| src : FixedArray[T],
#| allocate_len~ : Int,
#| len~ : Int,
#| src_offset? : Int = 0,
#| dst_offset? : Int = 0,
#|) -> Array[T] {
#| let dst = Array::unsafe_make_uninit(allocate_len)
#| UninitializedArray::unsafe_blit_fixed(
#| dst.buffer(),
#| dst_offset,
#| src,
#| src_offset,
#| len,
#| )
#| dst
#|}
#|fn[T] Array::unsafe_resize_with_default(
#| self : Array[T],
#| new_len : Int,
#| value : T,
#|) -> Unit {
#| let len = self.length()
#| guard! new_len >= len
#| JSArray::ofAnyArray(self).set_length(new_len)
#| for i in len.. 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_true(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_true(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::release_unused(self : Array[T], placeholder~ : T) -> Unit {
#| ignore(self)
#| ignore(placeholder)
#|}
#|pub fn[T] Array::push(self : Array[T], value : T) -> Unit {
#| JSArray::ofAnyArray(self).push(JSValue::ofAny(value))
#|}
#|pub fn[T] Array::append(self : Array[T], other : ArrayView[T]) -> Unit {
#| let old_len = self.length()
#| let append_len = other.len()
#| guard! old_len + append_len >= old_len
#| JSArray::ofAnyArray(self).append_view(
#| JSArray::ofAnyFixedArray(other.buf().0),
#| other.start(),
#| append_len,
#| )
#|}
#|#label_migration(src_offset, fill=false, msg="Use ArrayView::blit_to instead")
#|#label_migration(len, fill=false, msg="Use ArrayView::blit_to instead")
#|pub fn[A] Array::blit_to(
#| self : Array[A],
#| dst : Array[A],
#| len? : Int = self.length(),
#| src_offset? : Int = 0,
#| dst_offset? : Int = 0,
#|) -> Unit {
#| let old_len = dst.length()
#| guard! len >= 0 &&
#| dst_offset >= 0 &&
#| src_offset >= 0 &&
#| dst_offset <= old_len &&
#| len <= self.length() - src_offset
#| let new_len = dst_offset + len
#| guard! new_len >= 0
#| if new_len > old_len {
#| JSArray::ofAnyArray(dst).set_length(new_len)
#| }
#| Array::unsafe_blit(dst, dst_offset, self, src_offset, len)
#|}
#|pub fn[A] ArrayView::blit_to(
#| self : ArrayView[A],
#| dst : Array[A],
#| dst_offset? : Int = 0,
#|) -> Unit {
#| let len = self.len()
#| let old_len = dst.length()
#| guard! dst_offset >= 0 && dst_offset <= old_len
#| let new_len = dst_offset + len
#| guard! new_len >= 0
#| if new_len > old_len {
#| JSArray::ofAnyArray(dst).set_length(new_len)
#| }
#| UninitializedArray::unsafe_blit(
#| dst.buffer(),
#| dst_offset,
#| self.buf(),
#| self.start(),
#| len,
#| )
#|}
#|pub fn[T] Array::pop(self : Array[T]) -> T? {
#| if self.is_empty() {
#| None
#| } else {
#| let v = self.unsafe_pop()
#| Some(v)
#| }
#|}
#|#internal(unsafe, "Panic if the array is empty.")
#|#doc(hidden)
#|#alias(pop_exn, deprecated)
#|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))
#|}
#|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)
#|}
#|#alias(clone, deprecated)
#|pub fn[T] Array::copy(self : Array[T]) -> Array[T] {
#| JSArray::ofAnyArray(self).copy().toAnyArray()
#|}
),
"arrayview.mbt": (
#|#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"
#|#intrinsic("%arrayview.length")
#|pub fn[T] ArrayView::length(self : ArrayView[T]) -> Int {
#| self.len()
#|}
#|pub fn[T] ArrayView::is_empty(self : ArrayView[T]) -> Bool {
#| self.length() == 0
#|}
#|pub fn[T] ArrayView::start_offset(self : Self[T]) -> Int {
#| self.start()
#|}
#|#intrinsic("%arrayview.get")
#|#alias("_[_]")
#|pub fn[T] ArrayView::at(self : ArrayView[T], index : Int) -> T {
#| guard index >= 0 && index < self.len() else {
#| index_out_of_bounds(self.len(), index)
#| }
#| self.buf().unsafe_get(self.start() + index)
#|}
#|#intrinsic("%arrayview.get_opt")
#|pub fn[T] ArrayView::get(self : ArrayView[T], index : Int) -> T? {
#| let len = self.length()
#| guard index >= 0 && index < len else { None }
#| Some(self.buf().unsafe_get(self.start() + index))
#|}
#|pub fn[T] ArrayView::last(self : ArrayView[T]) -> T? {
#| let len = self.length()
#| if len == 0 {
#| None
#| } else {
#| Some(self.unsafe_get(len - 1))
#| }
#|}
#|#intrinsic("%arrayview.unsafe_get")
#|#internal(unsafe, "Panic if index is out of bounds")
#|#doc(hidden)
#|pub fn[T] ArrayView::unsafe_get(self : ArrayView[T], index : Int) -> T {
#| self.buf()[self.start() + index]
#|}
#|#intrinsic("%array.view")
#|#alias(view, deprecated="Use `exact_view` instead")
#|#alias(sub, deprecated="Use `exact_view` instead")
#|pub fn[T] Array::exact_view(
#| self : Array[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else {
#| abort("View index out of bounds")
#| }
#| ArrayView::make(self.buffer(), start, end - start)
#|}
#|pub fn[T] Array::get_view(
#| self : Array[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T]? {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else { None }
#| Some(ArrayView::make(self.buffer(), start, end - start))
#|}
#|#intrinsic("%arrayview.view")
#|#alias(view, deprecated="Use `exact_view` instead")
#|#alias(sub, deprecated="Use `exact_view` instead")
#|pub fn[T] ArrayView::exact_view(
#| self : ArrayView[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else {
#| abort("View index out of bounds")
#| }
#| ArrayView::make(self.buf(), self.start() + start, end - start)
#|}
#|pub fn[T] ArrayView::get_view(
#| self : ArrayView[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T]? {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else { None }
#| Some(ArrayView::make(self.buf(), self.start() + start, end - start))
#|}
#|#alias("_[_:_]")
#|pub fn[T] Array::clamped_view(
#| self : Array[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let len = self.length()
#| let lo = clamp_offset(start, len)
#| let hi = match end {
#| None => len
#| Some(end) => clamp_offset(end, len)
#| }
#| let count = if hi > lo { hi - lo } else { 0 }
#| ArrayView::make(self.buffer(), lo, count)
#|}
#|#alias("_[_:_]")
#|pub fn[T] ArrayView::clamped_view(
#| self : ArrayView[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let len = self.length()
#| let lo = clamp_offset(start, len)
#| let hi = match end {
#| None => len
#| Some(end) => clamp_offset(end, len)
#| }
#| let count = if hi > lo { hi - lo } else { 0 }
#| ArrayView::make(self.buf(), self.start() + lo, count)
#|}
#|fn[T] unsafe_cast_fixedarray_to_uninitializedarray(
#| arr : FixedArray[T],
#|) -> UninitializedArray[T] = "%identity"
#|#intrinsic("%fixedarray.view")
#|#alias(view, deprecated="Use `exact_view` instead")
#|#alias(sub, deprecated="Use `exact_view` instead")
#|pub fn[T] FixedArray::exact_view(
#| self : FixedArray[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else {
#| abort("View index out of bounds")
#| }
#| ArrayView::make(
#| unsafe_cast_fixedarray_to_uninitializedarray(self),
#| start,
#| end - start,
#| )
#|}
#|pub fn[T] FixedArray::get_view(
#| self : FixedArray[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T]? {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else { None }
#| Some(
#| ArrayView::make(
#| unsafe_cast_fixedarray_to_uninitializedarray(self),
#| start,
#| end - start,
#| ),
#| )
#|}
#|#alias("_[_:_]")
#|pub fn[T] FixedArray::clamped_view(
#| self : FixedArray[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let len = self.length()
#| let lo = clamp_offset(start, len)
#| let hi = match end {
#| None => len
#| Some(end) => clamp_offset(end, len)
#| }
#| let count = if hi > lo { hi - lo } else { 0 }
#| ArrayView::make(unsafe_cast_fixedarray_to_uninitializedarray(self), lo, count)
#|}
#|pub fn[T] ArrayView::suffixes(
#| self : Self[T],
#| include_empty? : Bool = false,
#|) -> Iter[ArrayView[T]] {
#| let len = self.length()
#| let mut i = 0
#| Iter::new(
#| fn() -> ArrayView[T]? {
#| if i < len {
#| let suffix = self[i:]
#| i += 1
#| Some(suffix)
#| } else if i == len {
#| i += 1
#| if include_empty {
#| Some(self[len:])
#| } else {
#| None
#| }
#| } else {
#| None
#| }
#| },
#| size_hint=if include_empty { len + 1 } else { len },
#| )
#|}
#|pub fn[T] ArrayView::chunks(
#| self : ArrayView[T],
#| size : Int,
#|) -> Array[ArrayView[T]] {
#| guard! size > 0
#| let len = self.length()
#| if len == 0 {
#| return []
#| }
#| let num_chunks = (len + size - 1) / size
#| Array::makei(num_chunks, i => {
#| let start = i * size
#| let end = Int::min(start + size, len)
#| self[start:end]
#| })
#|}
#|#locals(pred)
#|pub fn[T] ArrayView::chunk_by(
#| self : ArrayView[T],
#| pred : (T, T) -> Bool raise?,
#|) -> Array[ArrayView[T]] raise? {
#| let chunks = []
#| if self.is_empty() {
#| return chunks
#| }
#| let start = for i in 1.. Array[ArrayView[T]] {
#| guard! size > 0
#| let len = self.length() - size + 1
#| if len < 1 {
#| return []
#| }
#| Array::makei(len, i => self[i:i + size])
#|}
#|#alias(iterator, deprecated)
#|pub fn[X] ArrayView::iter(self : ArrayView[X]) -> Iter[X] {
#| let mut i = 0
#| let len = self.length()
#| Iter::new(
#| fn() {
#| guard i < len else { None }
#| let elem = self.unsafe_get(i)
#| i += 1
#| Some(elem)
#| },
#| size_hint=len,
#| )
#|}
#|#alias(rev_iterator, deprecated)
#|pub fn[X] ArrayView::rev_iter(self : ArrayView[X]) -> Iter[X] {
#| let len = self.length()
#| let mut i = len
#| Iter::new(
#| fn() {
#| guard i > 0 else { None }
#| i -= 1
#| Some(self.unsafe_get(i))
#| },
#| size_hint=len,
#| )
#|}
#|#alias(iterator2, deprecated)
#|pub fn[X] ArrayView::iter2(self : ArrayView[X]) -> Iter2[Int, X] {
#| let mut i = 0
#| let len = self.length()
#| Iter2::new(
#| fn() {
#| guard i < len else { None }
#| let result = Some((i, self.unsafe_get(i)))
#| i += 1
#| result
#| },
#| size_hint=len,
#| )
#|}
#|#locals(f)
#|pub fn[T] ArrayView::each(
#| self : ArrayView[T],
#| f : (T) -> Unit raise?,
#|) -> Unit raise? {
#| for v in self {
#| f(v)
#| }
#|}
#|#locals(f)
#|pub fn[T] ArrayView::eachi(
#| self : ArrayView[T],
#| f : (Int, T) -> Unit raise?,
#|) -> Unit raise? {
#| for i, v in self {
#| f(i, v)
#| }
#|}
#|#locals(f)
#|pub fn[T] ArrayView::rev_each(
#| self : ArrayView[T],
#| f : (T) -> Unit raise?,
#|) -> Unit raise? {
#| let len = self.length()
#| for i in 0.. Unit raise?,
#|) -> Unit raise? {
#| let len = self.length()
#| for i in 0.. Bool raise?,
#|) -> Bool raise? {
#| for v in self {
#| if !f(v) {
#| return false
#| }
#| }
#| true
#|}
#|#locals(f)
#|#alias(exists)
#|pub fn[T] ArrayView::any(
#| self : ArrayView[T],
#| f : (T) -> Bool raise?,
#|) -> Bool raise? {
#| for v in self {
#| if f(v) {
#| return true
#| }
#| }
#| false
#|}
#|pub fn[T : Eq] ArrayView::contains(self : ArrayView[T], value : T) -> Bool {
#| for v in self {
#| if v == value {
#| break true
#| }
#| } nobreak {
#| false
#| }
#|}
#|pub fn[T : Eq] ArrayView::count(self : ArrayView[T], value : T) -> Int {
#| for v in self; count = 0 {
#| if v == value {
#| continue count + 1
#| }
#| continue count
#| } nobreak {
#| count
#| }
#|}
#|#locals(f)
#|pub fn[T] ArrayView::count_if(
#| self : ArrayView[T],
#| f : (T) -> Bool raise?,
#|) -> Int raise? {
#| for v in self; count = 0 {
#| if f(v) {
#| continue count + 1
#| }
#| continue count
#| } nobreak {
#| count
#| }
#|}
#|pub fn[T : Eq] ArrayView::search(self : ArrayView[T], value : T) -> Int? {
#| for i, x in self {
#| if x == value {
#| break Some(i)
#| }
#| } nobreak {
#| None
#| }
#|}
#|#locals(f)
#|pub fn[T] ArrayView::search_by(
#| self : ArrayView[T],
#| f : (T) -> Bool raise?,
#|) -> Int? raise? {
#| for i, v in self {
#| if f(v) {
#| break Some(i)
#| }
#| } nobreak {
#| None
#| }
#|}
#|pub fn[T : Eq] ArrayView::starts_with(
#| self : ArrayView[T],
#| prefix : ArrayView[T],
#|) -> Bool {
#| if prefix.length() > self.length() {
#| return false
#| }
#| for i in 0.. Bool {
#| let suffix_len = suffix.length()
#| let self_len = self.length()
#| if suffix_len > self_len {
#| return false
#| }
#| for i in 0.. ArrayView[T]? {
#| if self.starts_with(prefix) {
#| Some(self[prefix.length():])
#| } else {
#| None
#| }
#|}
#|pub fn[T : Eq] ArrayView::strip_suffix(
#| self : ArrayView[T],
#| suffix : ArrayView[T],
#|) -> ArrayView[T]? {
#| if self.ends_with(suffix) {
#| Some(self[:self.length() - suffix.length()])
#| } else {
#| None
#| }
#|}
#|pub fn[T : Compare] ArrayView::binary_search(
#| self : ArrayView[T],
#| value : T,
#|) -> Result[Int, Int] {
#| let len = self.length()
#| for i = 0, j = len; i < j; {
#| let h = i + (j - i) / 2
#| if self.unsafe_get(h) < value {
#| continue h + 1, j
#| } else {
#| continue i, h
#| }
#| } nobreak {
#| if i < len && self.unsafe_get(i) == value {
#| Ok(i)
#| } else {
#| Err(i)
#| }
#| }
#|}
#|#locals(cmp)
#|pub fn[T] ArrayView::binary_search_by(
#| self : ArrayView[T],
#| cmp : (T) -> Int raise?,
#|) -> Result[Int, Int] raise? {
#| let len = self.length()
#| for i = 0, j = len; i < j; {
#| let h = i + (j - i) / 2
#| if cmp(self.unsafe_get(h)) < 0 {
#| continue h + 1, j
#| } else {
#| continue i, h
#| }
#| } nobreak {
#| if i < len && cmp(self.unsafe_get(i)) == 0 {
#| Ok(i)
#| } else {
#| Err(i)
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A, B] ArrayView::fold(
#| self : ArrayView[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for x in self; acc = init {
#| continue f(acc, x)
#| } nobreak {
#| acc
#| }
#|}
#|#locals(f)
#|pub fn[A, B] ArrayView::rev_fold(
#| self : ArrayView[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for i = self.length() - 1, acc = init; i >= 0; {
#| continue i - 1, f(acc, self.unsafe_get(i))
#| } nobreak {
#| acc
#| }
#|}
#|#locals(f)
#|pub fn[A, B] ArrayView::foldi(
#| self : ArrayView[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| for i, x in self; acc = init {
#| continue f(i, acc, x)
#| } nobreak {
#| acc
#| }
#|}
#|#locals(f)
#|pub fn[A, B] ArrayView::rev_foldi(
#| self : ArrayView[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| let len = self.length()
#| for i in len>..0; acc = init {
#| continue f(len - i - 1, acc, self.unsafe_get(i))
#| } nobreak {
#| acc
#| }
#|}
#|#locals(f)
#|pub fn[T, U] ArrayView::map(
#| self : ArrayView[T],
#| f : (T) -> U raise?,
#|) -> Array[U] raise? {
#| let arr = Array::unsafe_make_uninit(self.length())
#| for i, x in self {
#| arr.unsafe_set(i, f(x))
#| }
#| arr
#|}
#|#locals(f)
#|pub fn[T, U] ArrayView::mapi(
#| self : ArrayView[T],
#| f : (Int, T) -> U raise?,
#|) -> Array[U] raise? {
#| let arr = Array::unsafe_make_uninit(self.length())
#| for i, x in self {
#| arr.unsafe_set(i, f(i, x))
#| }
#| arr
#|}
#|#locals(f)
#|pub fn[T] ArrayView::filter(
#| self : ArrayView[T],
#| f : (T) -> Bool raise?,
#|) -> Array[T] raise? {
#| let arr = []
#| for v in self {
#| if f(v) {
#| arr.push(v)
#| }
#| }
#| arr
#|}
#|#locals(f)
#|pub fn[A, B] ArrayView::filter_map(
#| self : ArrayView[A],
#| f : (A) -> B? raise?,
#|) -> Array[B] raise? {
#| let result = []
#| for x in self {
#| if f(x) is Some(x) {
#| result.push(x)
#| }
#| }
#| result
#|}
#|#alias(to_array, deprecated)
#|pub fn[T] ArrayView::to_owned(self : ArrayView[T]) -> Array[T] {
#| let len = self.length()
#| if len == 0 {
#| []
#| } else {
#| Array::unsafe_make_and_blit(
#| self.buf(),
#| allocate_len=len,
#| src_offset=self.start(),
#| len~,
#| )
#| }
#|}
#|pub fn[A : ToStringView] ArrayView::join(
#| self : ArrayView[A],
#| separator : StringView,
#|) -> String {
#| match self {
#| [] => ""
#| [hd, .. tl] => {
#| let hd = hd.to_string_view()
#| let size_hint = for s in tl; size_hint = hd.length() {
#| continue size_hint + s.to_string_view().length() + separator.length()
#| } nobreak {
#| size_hint
#| }
#| let size_hint = size_hint << 1
#| let buf = StringBuilder(size_hint~)
#| buf.write_view(hd)
#| if separator is "" {
#| for s in tl {
#| let s = s.to_string_view()
#| buf.write_view(s)
#| }
#| } else {
#| for s in tl {
#| let s = s.to_string_view()
#| buf.write_view(separator)
#| buf.write_view(s)
#| }
#| }
#| buf.to_string()
#| }
#| }
#|}
#|pub fn[T : Compare] ArrayView::lexical_compare(
#| self : ArrayView[T],
#| other : ArrayView[T],
#|) -> Int {
#| let self_len = self.length()
#| let other_len = other.length()
#| let min_len = if self_len < other_len { self_len } else { other_len }
#| for i in 0.. Array[T] {
#| let len = self.length()
#| let arr = Array::unsafe_make_uninit(len)
#| for i in 0.. Bool {
#| if self.length() != other.length() {
#| return false
#| }
#| for i, x in self {
#| if !(x == other.unsafe_get(i)) {
#| return false
#| }
#| } nobreak {
#| true
#| }
#|}
#|pub impl[T : Compare] Compare for ArrayView[T] with fn compare(self, other) -> Int {
#| let len_self = self.length()
#| let len_other = other.length()
#| let cmp = len_self.compare(len_other)
#| guard cmp == 0 else { return cmp }
#| for i, x in self {
#| let cmp = x.compare(other.unsafe_get(i))
#| guard cmp == 0 else { break cmp }
#| } nobreak {
#| 0
#| }
#|}
#|pub impl[A : Hash] Hash for ArrayView[A] with fn hash_combine(self, hasher) {
#| for e in self {
#| hasher.combine(e)
#| }
#|}
#|pub impl[T] Add for ArrayView[T] with fn add(self, other) {
#| let len_self = self.length()
#| let len_other = other.length()
#| if len_self == 0 {
#| Array::unsafe_make_and_blit(
#| other.buf(),
#| allocate_len=len_other,
#| src_offset=other.start(),
#| len=len_other,
#| )
#| } else {
#| let result = Array::unsafe_make_and_blit(
#| self.buf(),
#| allocate_len=len_self + len_other,
#| src_offset=self.start(),
#| len=len_self,
#| )
#| UninitializedArray::unsafe_blit(
#| result.buffer(),
#| len_self,
#| other.buf(),
#| other.start(),
#| len_other,
#| )
#| result
#| }
#|}
),
"assert.mbt": (
#|#callsite(autofill(loc))
#|#coverage.skip
#|pub fn assert_true(x : Bool, msg? : StringView, loc~ : SourceLoc) -> Unit raise {
#| if !x {
#| let fail_msg : StringView = match msg {
#| Some(msg) | (None with msg = "`\{x}` is not true") => msg
#| }
#| fail(fail_msg, loc~)
#| }
#|}
#|#callsite(autofill(loc))
#|#coverage.skip
#|pub fn assert_false(
#| x : Bool,
#| msg? : StringView,
#| loc~ : SourceLoc,
#|) -> Unit raise {
#| if x {
#| let fail_msg : StringView = match msg {
#| Some(msg) | (None with msg = "`\{x}` is not false") => msg
#| }
#| fail(fail_msg, loc~)
#| }
#|}
),
"assert_release.mbt": (
#|pub fn debug_assert(x : () -> Bool) -> Unit = "%ignore"
),
"autoloc.mbt": (
#|pub(all) type SourceLoc
#|fn SourceLoc::repr(self : Self) -> String = "%loc_to_string"
#|pub impl Show for SourceLoc with fn output(self, logger) {
#| logger.write_string(self.repr())
#|}
#|pub impl Show for SourceLoc with fn to_string(self) {
#| self.repr()
#|}
#|priv struct SourceLocRepr {
#| filename : StringView
#| start_line : StringView
#| start_column : StringView
#| end_line : StringView
#| end_column : StringView
#|}
#|fn SourceLocRepr::parse(repr : String) -> SourceLocRepr {
#| lexmatch repr[:] with longest {
#| (re"^.+" as filename) +
#| re":" +
#| (re"[[:digit:]]+" as start_line) +
#| re":" +
#| (re"[[:digit:]]+" as start_column) +
#| re"-" +
#| (re"[[:digit:]]+" as end_line) +
#| re":" +
#| (re"[[:digit:]]+" as end_column) +
#| re"@" +
#| (re"[^:]*$" as _module) =>
#| { filename, start_line, start_column, end_line, end_column, }
#| _ => panic()
#| }
#|}
#|fn SourceLocRepr::to_json_string(self : SourceLocRepr) -> String {
#| (
#| $|{"filename":\{sb => self.filename.escape_to(sb)},"start_line":\{self.start_line},"start_column":\{self.start_column},"end_line":\{self.end_line},"end_column":\{self.end_column}}
#| )
#|}
#|pub fn SourceLoc::to_json_string(self : SourceLoc) -> String {
#| SourceLocRepr::parse(self.repr()).to_json_string()
#|}
#|pub(all) struct ArgsLoc(Array[SourceLoc?])
#|#warnings("-deprecated")
#|pub impl Show for ArgsLoc with fn output(self, logger) {
#| let ArgsLoc(arr) = self
#| arr.output(logger)
#|}
#|pub fn ArgsLoc::to_json(self : ArgsLoc) -> String {
#| let buf = StringBuilder(size_hint=10)
#| let ArgsLoc(self) = self
#| buf.write_char('[')
#| for i, item in self {
#| if i != 0 {
#| buf.write_string(", ")
#| }
#| match item {
#| None => buf.write_string("null")
#| Some(loc) => buf.write_string(loc.to_json_string())
#| }
#| }
#| buf.write_char(']')
#| buf.to_string()
#|}
),
"bitstring.mbt": (
#|fn UInt::extend_sign(self : UInt, len : Int) -> Int {
#| let b = 32 - len
#| self.reinterpret_as_int() << b >> b
#|}
#|fn UInt64::extend_sign(self : UInt64, len : Int) -> Int64 {
#| let b = 64 - len
#| self.reinterpret_as_int64() << b >> b
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_bit(
#| bs : ArrayView[Byte],
#| offset : Int,
#| _len : Int,
#|) -> UInt {
#| let byte_index = offset >> 3
#| let bit_shift = 7 - (offset & 7)
#| let byte_val = bs.unsafe_get(byte_index).to_uint()
#| (byte_val >> bit_shift) & 1U
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_bit_signed(
#| bs : ArrayView[Byte],
#| offset : Int,
#| _len : Int,
#|) -> Int {
#| let byte_index = offset >> 3
#| let bit_shift = 7 - (offset & 7)
#| let byte_val = bs.unsafe_get(byte_index).to_int()
#| ((byte_val >> bit_shift) & 1) * -1
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_byte(
#| bs : ArrayView[Byte],
#| 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")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint_le(
#| bs : ArrayView[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| if (offset & 7) == 0 {
#| if len == 32 {
#| return bs.unsafe_extract_uint_le_aligned(offset >> 3)
#| }
#| if len == 16 {
#| return bs.unsafe_extract_uint16_le_aligned(offset >> 3)
#| }
#| }
#| bs.unsafe_extract_uint_le_slow(offset, len)
#|}
#|fn ArrayView::unsafe_extract_uint_le_slow(
#| bs : ArrayView[Byte],
#| 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")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint_be(
#| bs : ArrayView[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| if (offset & 7) == 0 {
#| if len == 32 {
#| return bs.unsafe_extract_uint_be_aligned(offset >> 3)
#| }
#| if len == 16 {
#| return bs.unsafe_extract_uint16_be_aligned(offset >> 3)
#| }
#| }
#| bs.unsafe_extract_uint_be_slow(offset, len)
#|}
#|fn ArrayView::unsafe_extract_uint_be_slow(
#| bs : ArrayView[Byte],
#| 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")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint64_le(
#| bs : ArrayView[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| if len == 64 && (offset & 7) == 0 {
#| return bs.unsafe_extract_uint64_le_aligned(offset >> 3)
#| }
#| bs.unsafe_extract_uint64_le_slow(offset, len)
#|}
#|fn ArrayView::unsafe_extract_uint64_le_slow(
#| bs : ArrayView[Byte],
#| 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")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint64_be(
#| bs : ArrayView[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| if len == 64 && (offset & 7) == 0 {
#| return bs.unsafe_extract_uint64_be_aligned(offset >> 3)
#| }
#| bs.unsafe_extract_uint64_be_slow(offset, len)
#|}
#|fn ArrayView::unsafe_extract_uint64_be_slow(
#| bs : ArrayView[Byte],
#| 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")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_bytesview(
#| bs : ArrayView[Byte],
#| offset : Int,
#| len : Int,
#|) -> ArrayView[Byte] {
#| let start = offset >> 3
#| let end = start + (len >> 3)
#| bs[start:end]
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_byte_signed(
#| bs : ArrayView[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| let unsigned = bs.unsafe_extract_byte(offset, len)
#| unsigned.extend_sign(len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int_le(
#| bs : ArrayView[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| let unsigned = bs.unsafe_extract_uint_le(offset, len)
#| unsigned.extend_sign(len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int_be(
#| bs : ArrayView[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| let unsigned = bs.unsafe_extract_uint_be(offset, len)
#| unsigned.extend_sign(len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int64_le(
#| bs : ArrayView[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int64 {
#| let unsigned = bs.unsafe_extract_uint64_le(offset, len)
#| unsigned.extend_sign(len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int64_be(
#| bs : ArrayView[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int64 {
#| let unsigned = bs.unsafe_extract_uint64_be(offset, len)
#| unsigned.extend_sign(len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_bit(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_bit(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_bit_signed(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs[:].unsafe_extract_bit_signed(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_byte(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_byte(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_byte_signed(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs[:].unsafe_extract_byte_signed(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_uint_le(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_uint_be(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_int_le(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_int_be(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_uint64_le(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| bs[:].unsafe_extract_uint64_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_uint64_be(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| bs[:].unsafe_extract_uint64_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_int64_le(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int64 {
#| bs[:].unsafe_extract_int64_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_int64_be(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int64 {
#| bs[:].unsafe_extract_int64_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_bytesview(
#| bs : Array[Byte],
#| offset : Int,
#| len : Int,
#|) -> ArrayView[Byte] {
#| bs[:].unsafe_extract_bytesview(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_bit(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_bit(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_bit_signed(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs[:].unsafe_extract_bit_signed(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_byte(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_byte(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_byte_signed(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs[:].unsafe_extract_byte_signed(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_uint_le(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_uint_be(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_int_le(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_int_be(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_uint64_le(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| bs[:].unsafe_extract_uint64_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_uint64_be(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| bs[:].unsafe_extract_uint64_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_int64_le(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int64 {
#| bs[:].unsafe_extract_int64_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_int64_be(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int64 {
#| bs[:].unsafe_extract_int64_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_bytesview(
#| bs : FixedArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> ArrayView[Byte] {
#| bs[:].unsafe_extract_bytesview(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_bit(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_bit(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_bit_signed(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_bit_signed(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_byte(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_byte(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_byte_signed(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_byte_signed(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_uint_le(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_uint_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_uint_be(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_uint_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_int_le(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_int_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_int_be(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_int_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_uint64_le(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_uint64_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_uint64_be(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_uint64_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_int64_le(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int64 {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_int64_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_int64_be(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> Int64 {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_int64_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_bytesview(
#| bs : ReadOnlyArray[Byte],
#| offset : Int,
#| len : Int,
#|) -> ArrayView[Byte] {
#| bs.unsafe_reinterpret_to_fixed_array().unsafe_extract_bytesview(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_bit(
#| bs : BytesView,
#| offset : Int,
#| _len : Int,
#|) -> UInt {
#| let byte_index = offset >> 3
#| let bit_shift = 7 - (offset & 7)
#| let byte_val = bs.unsafe_get(byte_index).to_uint()
#| (byte_val >> bit_shift) & 1U
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_bit_signed(
#| bs : BytesView,
#| offset : Int,
#| _len : Int,
#|) -> Int {
#| let byte_index = offset >> 3
#| let bit_shift = 7 - (offset & 7)
#| let byte_val = bs.unsafe_get(byte_index).to_int()
#| ((byte_val >> bit_shift) & 1) * -1
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_byte(
#| bs : BytesView,
#| 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")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint_le(
#| bs : BytesView,
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| if (offset & 7) == 0 {
#| if len == 32 {
#| return bs.unsafe_extract_uint_le_aligned(offset >> 3)
#| }
#| if len == 16 {
#| return bs.unsafe_extract_uint16_le_aligned(offset >> 3)
#| }
#| }
#| bs.unsafe_extract_uint_le_slow(offset, len)
#|}
#|fn BytesView::unsafe_extract_uint_le_slow(
#| bs : BytesView,
#| 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")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint_be(
#| bs : BytesView,
#| offset : Int,
#| len : Int,
#|) -> UInt {
#| if (offset & 7) == 0 {
#| if len == 32 {
#| return bs.unsafe_extract_uint_be_aligned(offset >> 3)
#| }
#| if len == 16 {
#| return bs.unsafe_extract_uint16_be_aligned(offset >> 3)
#| }
#| }
#| bs.unsafe_extract_uint_be_slow(offset, len)
#|}
#|fn BytesView::unsafe_extract_uint_be_slow(
#| bs : BytesView,
#| 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")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint64_le(
#| bs : BytesView,
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| if len == 64 && (offset & 7) == 0 {
#| return bs.unsafe_extract_uint64_le_aligned(offset >> 3)
#| }
#| bs.unsafe_extract_uint64_le_slow(offset, len)
#|}
#|fn BytesView::unsafe_extract_uint64_le_slow(
#| bs : BytesView,
#| 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")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint64_be(
#| bs : BytesView,
#| offset : Int,
#| len : Int,
#|) -> UInt64 {
#| if len == 64 && (offset & 7) == 0 {
#| return bs.unsafe_extract_uint64_be_aligned(offset >> 3)
#| }
#| bs.unsafe_extract_uint64_be_slow(offset, len)
#|}
#|fn BytesView::unsafe_extract_uint64_be_slow(
#| bs : BytesView,
#| 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")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_bytesview(
#| bs : BytesView,
#| offset : Int,
#| len : Int,
#|) -> BytesView {
#| BytesView::make(bs.bytes(), bs.start() + (offset >> 3), len >> 3)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_byte_signed(
#| bs : BytesView,
#| offset : Int,
#| len : Int,
#|) -> Int {
#| let unsigned = bs.unsafe_extract_byte(offset, len)
#| unsigned.extend_sign(len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int_le(
#| bs : BytesView,
#| offset : Int,
#| len : Int,
#|) -> Int {
#| let unsigned = bs.unsafe_extract_uint_le(offset, len)
#| unsigned.extend_sign(len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int_be(
#| bs : BytesView,
#| offset : Int,
#| len : Int,
#|) -> Int {
#| let unsigned = bs.unsafe_extract_uint_be(offset, len)
#| unsigned.extend_sign(len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int64_le(
#| bs : BytesView,
#| offset : Int,
#| len : Int,
#|) -> Int64 {
#| let unsigned = bs.unsafe_extract_uint64_le(offset, len)
#| unsigned.extend_sign(len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int64_be(
#| bs : BytesView,
#| offset : Int,
#| len : Int,
#|) -> Int64 {
#| let unsigned = bs.unsafe_extract_uint64_be(offset, len)
#| unsigned.extend_sign(len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|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")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_bit_signed(
#| bs : Bytes,
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs[:].unsafe_extract_bit_signed(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|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")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_byte_signed(
#| bs : Bytes,
#| offset : Int,
#| len : Int,
#|) -> Int {
#| bs[:].unsafe_extract_byte_signed(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|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")
#|#doc(hidden)
#|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")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_int_le(bs : Bytes, offset : Int, len : Int) -> Int {
#| bs[:].unsafe_extract_int_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_int_be(bs : Bytes, offset : Int, len : Int) -> Int {
#| bs[:].unsafe_extract_int_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|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")
#|#doc(hidden)
#|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")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_int64_le(
#| bs : Bytes,
#| offset : Int,
#| len : Int,
#|) -> Int64 {
#| bs[:].unsafe_extract_int64_le(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_int64_be(
#| bs : Bytes,
#| offset : Int,
#| len : Int,
#|) -> Int64 {
#| bs[:].unsafe_extract_int64_be(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_bytesview(
#| bs : Bytes,
#| offset : Int,
#| len : Int,
#|) -> BytesView {
#| bs[:].unsafe_extract_bytesview(offset, len)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_byte_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_get(byte_offset).to_uint()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_byte_signed_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_get(byte_offset).to_uint().extend_sign(8)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint16_le_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| fixedarray_read_uint16_le(
#| buffer_to_fixedarray(bs.buf()),
#| bs.start() + byte_offset,
#| ).to_uint()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint16_be_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| fixedarray_read_uint16_be(
#| buffer_to_fixedarray(bs.buf()),
#| bs.start() + byte_offset,
#| ).to_uint()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int16_le_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_extract_uint16_le_aligned(byte_offset).extend_sign(16)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int16_be_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_extract_uint16_be_aligned(byte_offset).extend_sign(16)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint_le_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| fixedarray_read_uint32_le(
#| buffer_to_fixedarray(bs.buf()),
#| bs.start() + byte_offset,
#| )
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint_be_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| fixedarray_read_uint32_be(
#| buffer_to_fixedarray(bs.buf()),
#| bs.start() + byte_offset,
#| )
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int_le_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_extract_uint_le_aligned(byte_offset).reinterpret_as_int()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int_be_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_extract_uint_be_aligned(byte_offset).reinterpret_as_int()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint64_le_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt64 {
#| fixedarray_read_uint64_le(
#| buffer_to_fixedarray(bs.buf()),
#| bs.start() + byte_offset,
#| )
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_uint64_be_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> UInt64 {
#| fixedarray_read_uint64_be(
#| buffer_to_fixedarray(bs.buf()),
#| bs.start() + byte_offset,
#| )
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int64_le_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int64 {
#| bs.unsafe_extract_uint64_le_aligned(byte_offset).reinterpret_as_int64()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_int64_be_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> Int64 {
#| bs.unsafe_extract_uint64_be_aligned(byte_offset).reinterpret_as_int64()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_byte_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_get(byte_offset).to_uint()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_byte_signed_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_get(byte_offset).to_uint().extend_sign(8)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint16_le_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_read_uint16_le(byte_offset).to_uint()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint16_be_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_read_uint16_be(byte_offset).to_uint()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int16_le_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_extract_uint16_le_aligned(byte_offset).extend_sign(16)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int16_be_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_extract_uint16_be_aligned(byte_offset).extend_sign(16)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint_le_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_read_uint32_le(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint_be_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_read_uint32_be(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int_le_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_read_uint32_le(byte_offset).reinterpret_as_int()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int_be_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int {
#| bs.unsafe_read_uint32_be(byte_offset).reinterpret_as_int()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint64_le_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt64 {
#| bs.unsafe_read_uint64_le(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_uint64_be_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> UInt64 {
#| bs.unsafe_read_uint64_be(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int64_le_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int64 {
#| bs.unsafe_read_uint64_le(byte_offset).reinterpret_as_int64()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_int64_be_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> Int64 {
#| bs.unsafe_read_uint64_be(byte_offset).reinterpret_as_int64()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_byte_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_byte_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_byte_signed_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_byte_signed_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_uint16_le_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint16_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_uint16_be_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint16_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_int16_le_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int16_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_int16_be_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int16_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_uint_le_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_uint_be_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_int_le_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_int_be_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_uint64_le_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> UInt64 {
#| bs[:].unsafe_extract_uint64_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_uint64_be_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> UInt64 {
#| bs[:].unsafe_extract_uint64_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_int64_le_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> Int64 {
#| bs[:].unsafe_extract_int64_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_int64_be_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> Int64 {
#| bs[:].unsafe_extract_int64_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_byte_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_byte_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_byte_signed_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_byte_signed_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_uint16_le_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint16_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_uint16_be_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint16_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_int16_le_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int16_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_int16_be_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int16_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_uint_le_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_uint_be_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_int_le_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_int_be_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_uint64_le_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> UInt64 {
#| bs[:].unsafe_extract_uint64_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_uint64_be_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> UInt64 {
#| bs[:].unsafe_extract_uint64_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_int64_le_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> Int64 {
#| bs[:].unsafe_extract_int64_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_int64_be_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> Int64 {
#| bs[:].unsafe_extract_int64_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_byte_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_byte_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_byte_signed_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_byte_signed_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_uint16_le_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_uint16_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_uint16_be_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_uint16_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_int16_le_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_int16_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_int16_be_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_int16_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_uint_le_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_uint_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_uint_be_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> UInt {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_uint_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_int_le_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_int_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_int_be_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> Int {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_int_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_uint64_le_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> UInt64 {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_uint64_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_uint64_be_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> UInt64 {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_uint64_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_int64_le_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> Int64 {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_int64_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_int64_be_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> Int64 {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_int64_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_byte_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_byte_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_byte_signed_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_byte_signed_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_uint16_le_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint16_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_uint16_be_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint16_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_int16_le_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int16_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_int16_be_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int16_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_uint_le_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> UInt {
#| bs.unsafe_read_uint32_le(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_uint_be_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> UInt {
#| bs[:].unsafe_extract_uint_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_int_le_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_int_be_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> Int {
#| bs[:].unsafe_extract_int_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_uint64_le_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> UInt64 {
#| bs.unsafe_read_uint64_le(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_uint64_be_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> UInt64 {
#| bs[:].unsafe_extract_uint64_be_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_int64_le_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> Int64 {
#| bs[:].unsafe_extract_int64_le_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_int64_be_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> Int64 {
#| bs[:].unsafe_extract_int64_be_aligned(byte_offset)
#|}
),
"bitstring_v128.mbt": (
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ArrayView::unsafe_extract_v128_aligned(
#| bs : ArrayView[Byte],
#| byte_offset : Int,
#|) -> V128 {
#| v128_load(buffer_to_fixedarray(bs.buf()), bs.start() + byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn BytesView::unsafe_extract_v128_aligned(
#| bs : BytesView,
#| byte_offset : Int,
#|) -> V128 {
#| v128_load(unsafe_from_bytes(bs.bytes()), bs.start() + byte_offset)
#|}
#|#borrow(bs)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Bytes::unsafe_extract_v128_aligned(
#| bs : Bytes,
#| byte_offset : Int,
#|) -> V128 {
#| v128_load(unsafe_from_bytes(bs), byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn Array::unsafe_extract_v128_aligned(
#| bs : Array[Byte],
#| byte_offset : Int,
#|) -> V128 {
#| bs[:].unsafe_extract_v128_aligned(byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_extract_v128_aligned(
#| bs : FixedArray[Byte],
#| byte_offset : Int,
#|) -> V128 {
#| v128_load(bs, byte_offset)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn ReadOnlyArray::unsafe_extract_v128_aligned(
#| bs : ReadOnlyArray[Byte],
#| byte_offset : Int,
#|) -> V128 {
#| bs
#| .unsafe_reinterpret_to_fixed_array()
#| .unsafe_extract_v128_aligned(byte_offset)
#|}
),
"bool.mbt": (
#|pub fn Bool::to_int(self : Bool) -> Int {
#| if self {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub fn Bool::to_int64(self : Bool) -> Int64 {
#| if self {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub fn Bool::to_uint(self : Bool) -> UInt {
#| if self {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub fn Bool::to_uint64(self : Bool) -> UInt64 {
#| if self {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub impl Hash for Bool with fn hash_combine(self, hasher) {
#| hasher.combine_bool(self)
#|}
#|pub impl Hash for Bool with fn hash(self : Bool) -> Int {
#| Hash::hash(if self { 1U } else { 0U })
#|}
#|pub fn Bool::to_uint16(self : Bool) -> UInt16 {
#| if self {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub fn Bool::to_int16(self : Bool) -> Int16 {
#| if self {
#| 1
#| } else {
#| 0
#| }
#|}
),
"bounds.mbt": (
#|#inline(never)
#|fn[T] index_out_of_bounds(len : Int, index : Int) -> T {
#| abort(
#| "index out of bounds: the len is from 0 to \{len} but the index is \{index}",
#| )
#|}
#|#inline(never)
#|fn[T] index_out_of_bounds2(len : Int, i : Int, j : Int) -> T {
#| abort(
#| "index out of bounds: the len is from 0 to \{len} but the index is (\{i}, \{j})",
#| )
#|}
#|fn clamp_offset(offset : Int, len : Int) -> Int {
#| if offset < 0 {
#| 0
#| } else if offset > len {
#| len
#| } else {
#| offset
#| }
#|}
),
"byte.mbt": (
#|pub fn Byte::Byte(self : Byte) -> Byte = "%identity"
#|pub impl Mul for Byte with fn mul(self : Byte, that : Byte) -> Byte {
#| (self.to_int() * that.to_int()).to_byte()
#|}
#|pub impl Div for Byte with fn div(self : Byte, that : Byte) -> Byte {
#| (self.to_int() / that.to_int()).to_byte()
#|}
#|pub impl Mod for Byte with fn mod(self : Byte, that : Byte) -> Byte {
#| (self.to_int() % that.to_int()).to_byte()
#|}
#|pub impl Eq for Byte with fn equal(self : Byte, that : Byte) -> Bool {
#| self.to_int() == that.to_int()
#|}
#|pub impl Eq for Byte with fn not_equal(self : Byte, that : Byte) -> Bool {
#| self.to_int() != that.to_int()
#|}
#|pub impl Add for Byte with fn add(self : Byte, that : Byte) -> Byte {
#| (self.to_int() + that.to_int()).to_byte()
#|}
#|pub impl Sub for Byte with fn sub(self : Byte, that : Byte) -> Byte {
#| (self.to_int() - that.to_int()).to_byte()
#|}
#|pub impl Compare for Byte with fn compare(self : Byte, that : Byte) -> Int {
#| self.to_int().compare(that.to_int())
#|}
#|pub impl Compare for Byte with fn op_lt(x, y) {
#| x.to_int() < y.to_int()
#|}
#|pub impl Compare for Byte with fn op_le(x, y) {
#| x.to_int() <= y.to_int()
#|}
#|pub impl Compare for Byte with fn op_gt(x, y) {
#| x.to_int() > y.to_int()
#|}
#|pub impl Compare for Byte with fn op_ge(x, y) {
#| x.to_int() >= y.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 fn hash_combine(self, hasher) {
#| hasher.combine_byte(self)
#|}
#|pub impl Default for Byte with fn default() {
#| b'\x00'
#|}
#|pub fn Byte::lnot(self : Byte) -> Byte {
#| self.to_int().lnot().to_byte()
#|}
#|pub impl BitAnd for Byte with fn land(self : Byte, that : Byte) -> Byte {
#| (self.to_int() & that.to_int()).to_byte()
#|}
#|pub impl BitOr for Byte with fn lor(self : Byte, that : Byte) -> Byte {
#| (self.to_int() | that.to_int()).to_byte()
#|}
#|pub impl BitXOr for Byte with fn 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 fn Byte::to_uint64(self : Byte) -> UInt64 {
#| self.to_uint().to_uint64()
#|}
#|pub fn Byte::popcnt(self : Byte) -> Int {
#| self.to_uint().popcnt()
#|}
#|pub impl Shl for Byte with fn shl(self : Byte, count : Int) -> Byte {
#| (self.to_int() << count).to_byte()
#|}
#|pub impl Shr for Byte with fn shr(self : Byte, count : Int) -> Byte {
#| (self.to_uint() >> count).reinterpret_as_int().to_byte()
#|}
),
"bytes.mbt": (
#|#internal(unsafe, "Creating mutable Bytes")
#|#doc(hidden)
#|pub fn FixedArray::unsafe_reinterpret_as_bytes(
#| self : FixedArray[Byte],
#|) -> Bytes = "%identity"
#|#locals(value)
#|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_get(i).to_int().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::blit_from_bytesview(
#| self : FixedArray[Byte],
#| bytes_offset : Int,
#| src : BytesView,
#|) -> Unit {
#| FixedArray::blit_from_bytes(
#| self,
#| bytes_offset,
#| src.bytes(),
#| src.start(),
#| src.len(),
#| )
#|}
#|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 fn equal(self : Bytes, other : Bytes) -> Bool = "%bytes.equal"
#|pub impl Compare for Bytes with fn compare(self, other) {
#| let self_len = self.length()
#| let other_len = other.length()
#| let cmp = self_len.compare(other_len)
#| if cmp != 0 {
#| return cmp
#| }
#| self.lexical_compare(other)
#|}
#|#alias(of, deprecated)
#|pub fn Bytes::from_array(arr : ArrayView[Byte]) -> Bytes {
#| let len = arr.length()
#| if len == 0 {
#| return []
#| }
#| let result = UninitializedArray::unsafe_make_and_blit(
#| arr.buf(),
#| len,
#| arr.start(),
#| 0,
#| len,
#| )
#| buffer_to_fixedarray(result).unsafe_reinterpret_as_bytes()
#|}
#|#deprecated("Use Bytes::from_array instead")
#|pub fn Bytes::from_fixedarray(arr : FixedArray[Byte], len? : Int) -> Bytes {
#| let len = match len {
#| None => arr.length()
#| Some(x) => {
#| guard! 0 <= x && x <= arr.length()
#| x
#| }
#| }
#| let result = FixedArray::make_and_blit(arr, allocate_len=len, init=0, len~)
#| result.unsafe_reinterpret_as_bytes()
#|}
#|#label_migration(len, fill=false)
#|pub fn Bytes::to_fixedarray(self : Bytes, len? : Int) -> FixedArray[Byte] {
#| let len = match len {
#| None => self.length()
#| Some(x) => {
#| guard! 0 <= x && x <= self.length()
#| x
#| }
#| }
#| FixedArray::make_and_blit(
#| unsafe_from_bytes(self),
#| allocate_len=len,
#| init=0,
#| len~,
#| )
#|}
#|pub fn BytesView::to_fixedarray(self : BytesView) -> FixedArray[Byte] {
#| let len = self.length()
#| FixedArray::make_and_blit(
#| unsafe_from_bytes(self.data()),
#| allocate_len=len,
#| init=0,
#| src_offset=self.start_offset(),
#| len~,
#| )
#|}
#|#alias(from_iterator, deprecated)
#|pub fn Bytes::from_iter(iter : Iter[Byte]) -> Bytes {
#| Bytes::from_array(iter.collect())
#|}
#|pub fn Bytes::to_array(self : Bytes) -> Array[Byte] {
#| let len = self.length()
#| Array::unsafe_make_and_blit_from_fixed(
#| unsafe_from_bytes(self),
#| allocate_len=len,
#| len~,
#| )
#|}
#|pub fn BytesView::to_array(self : BytesView) -> Array[Byte] {
#| let len = self.length()
#| Array::unsafe_make_and_blit_from_fixed(
#| unsafe_from_bytes(self.data()),
#| allocate_len=len,
#| src_offset=self.start_offset(),
#| len~,
#| )
#|}
#|#alias(iterator, deprecated)
#|pub fn Bytes::iter(self : Bytes) -> Iter[Byte] {
#| let mut i = 0
#| let len = self.length()
#| Iter::new(
#| fn() {
#| guard i < len else { None }
#| let c = self.unsafe_get(i)
#| i += 1
#| Some(c)
#| },
#| size_hint=len,
#| )
#|}
#|#alias(iterator2, deprecated)
#|pub fn Bytes::iter2(self : Bytes) -> Iter2[Int, Byte] {
#| let mut i = 0
#| let len = self.length()
#| Iter::new(
#| fn() {
#| guard i < len else { None }
#| let result = (i, self.unsafe_get(i))
#| i += 1
#| Some(result)
#| },
#| size_hint=len,
#| )
#|}
#|pub impl Default for Bytes with fn default() {
#| b""
#|}
#|pub fn Bytes::is_empty(self : Bytes) -> Bool {
#| self.length() == 0
#|}
#|#intrinsic("%bytes.get_opt")
#|pub fn Bytes::get(self : Bytes, index : Int) -> Byte? {
#| guard index >= 0 && index < self.length() else { None }
#| Some(self[index])
#|}
#|pub impl Add for Bytes with fn add(self : Bytes, other : Bytes) -> Bytes {
#| self.bytes_add_impl(other)
#|}
#|#cfg(not(target="js"))
#|fn Bytes::bytes_add_impl(self : Bytes, other : Bytes) -> Bytes {
#| let len_self = self.length()
#| let len_other = other.length()
#| let rv = UninitializedArray::unsafe_make_and_blit_from_fixed(
#| unsafe_from_bytes(self),
#| len_self + len_other,
#| 0,
#| 0,
#| len_self,
#| )
#| UninitializedArray::unsafe_blit_fixed(
#| rv,
#| len_self,
#| unsafe_from_bytes(other),
#| 0,
#| len_other,
#| )
#| unsafe_to_bytes(buffer_to_fixedarray(rv))
#|}
#|#cfg(target="js")
#|fn Bytes::bytes_add_impl(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)
#| rv.blit_from_bytes(0, self, 0, len_self)
#| rv.blit_from_bytes(len_self, other, 0, len_other)
#| unsafe_to_bytes(rv)
#|}
#|pub impl Hash for Bytes with fn hash_combine(self, hasher) {
#| hasher.combine(self[:])
#|}
#|#cfg(not(target="js"))
#|pub impl Hash for Bytes with fn hash(self : Bytes) -> Int {
#| let mut acc = seed.reinterpret_as_uint() + GPRIME5
#| let (cur, remain) = for cur = 0, remain = self.length(); remain >= 4; {
#| acc += 4U
#| acc = consume4_acc(acc, self.unsafe_read_uint32_le(cur))
#| continue cur + 4, remain - 4
#| } nobreak {
#| (cur, remain)
#| }
#| for cur = cur, remain = remain; remain >= 1; {
#| acc = rotl(acc + self.unsafe_get(cur).to_uint() * GPRIME5, 11) * GPRIME1
#| continue cur + 1, remain - 1
#| }
#| finalize_acc(acc)
#|}
#|pub fn Bytes::repeat(self : Self, count : Int) -> Bytes {
#| if count < 0 {
#| abort("negative repeat count")
#| }
#| if count == 0 || self.is_empty() {
#| return []
#| }
#| if count == 1 {
#| return self
#| }
#| let len = self.length()
#| let total = len * count
#| guard total / count == len else { abort("repeat result too large") }
#| let arr = FixedArray::make(total, (0 : Byte))
#| arr.blit_from_bytes(0, self, 0, len)
#| for filled = len; filled < total; {
#| let remaining = total - filled
#| let copy_len = if filled < remaining { filled } else { remaining }
#| let src = unsafe_to_bytes(arr)
#| arr.blit_from_bytes(filled, src, 0, copy_len)
#| continue filled + copy_len
#| }
#| unsafe_to_bytes(arr)
#|}
#|pub fn Bytes::lexical_compare(self : Bytes, other : Bytes) -> Int {
#| self[:].lexical_compare(other)
#|}
),
"bytes_find.mbt": (
#|let find_max_short_pattern : Int = 32
#|let find_max_bruteforce : Int = 64
#|let find_prime_rk : UInt = 16777619U
#|pub fn BytesView::find(target : BytesView, pattern : BytesView) -> Int? {
#| find_index(target, pattern)
#|}
#|pub fn Bytes::find(target : Bytes, pattern : BytesView) -> Int? {
#| target[:].find(pattern)
#|}
#|fn find_index(target : BytesView, pattern : BytesView) -> Int? {
#| let target_len = target.length()
#| let pattern_len = pattern.length()
#| if pattern_len == 0 {
#| return Some(0)
#| }
#| if pattern_len > target_len {
#| return None
#| }
#| if pattern_len == 1 {
#| let found = find_byte_from_view(
#| target,
#| 0,
#| target_len,
#| pattern.unsafe_get(0),
#| )
#| if found < 0 {
#| None
#| } else {
#| Some(found)
#| }
#| } else if pattern_len == target_len {
#| if target == pattern {
#| Some(0)
#| } else {
#| None
#| }
#| } else if pattern_len <= find_max_short_pattern {
#| find_short(target, pattern)
#| } else {
#| find_long_by_byte_scanner(target, pattern)
#| }
#|}
#|#inline
#|fn find_cutover(i : Int) -> Int {
#| 4 + i / 16
#|}
#|declare fn find_byte_from_view(
#| target : BytesView,
#| start : Int,
#| end : Int,
#| byte : Byte,
#|) -> Int
#|#cfg(any(target="js", target="wasm-gc"))
#|fn find_byte_from_view(
#| target : BytesView,
#| start : Int,
#| end : Int,
#| byte : Byte,
#|) -> Int {
#| for pos in start.. Int {
#| let target_start = target.start_offset()
#| let found = find_byte_from_bytes(
#| target.data(),
#| target_start + start,
#| target_start + end,
#| byte,
#| )
#| if found < 0 {
#| -1
#| } else {
#| found - target_start
#| }
#|}
#|declare fn rev_find_byte_from_view(
#| target : BytesView,
#| start : Int,
#| end : Int,
#| byte : Byte,
#|) -> Int
#|#cfg(any(target="js", target="wasm-gc"))
#|fn rev_find_byte_from_view(
#| target : BytesView,
#| start : Int,
#| end : Int,
#| byte : Byte,
#|) -> Int {
#| for pos = end - 1; pos >= start; {
#| if target.unsafe_get(pos) == byte {
#| break pos
#| }
#| continue pos - 1
#| } nobreak {
#| -1
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn rev_find_byte_from_view(
#| target : BytesView,
#| start : Int,
#| end : Int,
#| byte : Byte,
#|) -> Int {
#| let target_start = target.start_offset()
#| let found = rev_find_byte_from_bytes(
#| target.data(),
#| target_start + start,
#| target_start + end,
#| byte,
#| )
#| if found < 0 {
#| -1
#| } else {
#| found - target_start
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn Bytes::v128_load(self : Bytes, offset : Int) -> V128 {
#| v128_load(unsafe_from_bytes(self), offset)
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn find_byte_from_bytes(
#| data : Bytes,
#| start : Int,
#| end : Int,
#| byte : Byte,
#|) -> Int {
#| let byte_v = i8x16_splat(byte)
#| let tail_start = for pos = start; pos + 16 <= end; {
#| let mask = i8x16_bitmask(i8x16_eq(data.v128_load(pos), byte_v))
#| if mask != 0 {
#| return pos + mask.ctz()
#| }
#| continue pos + 16
#| } nobreak {
#| pos
#| }
#| for pos in tail_start.. Int {
#| let byte_v = i8x16_splat(byte)
#| let head_end = for pos = end; pos - 16 >= start; {
#| let chunk_start = pos - 16
#| let mask = i8x16_bitmask(i8x16_eq(data.v128_load(chunk_start), byte_v))
#| if mask != 0 {
#| return chunk_start + 31 - mask.clz()
#| }
#| continue chunk_start
#| } nobreak {
#| pos
#| }
#| for pos = head_end - 1; pos >= start; {
#| if data.unsafe_get(pos) == byte {
#| break pos
#| }
#| continue pos - 1
#| } nobreak {
#| -1
#| }
#|}
#|declare fn find_short(target : BytesView, pattern : BytesView) -> Int?
#|#cfg(any(target="js", target="wasm-gc"))
#|fn find_short(target : BytesView, pattern : BytesView) -> Int? {
#| let target_len = target.length()
#| let pattern_len = pattern.length()
#| let target_start = target.start_offset()
#| let pattern_start = pattern.start_offset()
#| let last_offset = pattern_len - 1
#| let last_byte = pattern.unsafe_get(last_offset)
#| for anchor_pos = last_offset; anchor_pos < target_len; {
#| let found = find_byte_from_view(target, anchor_pos, target_len, last_byte)
#| if found < 0 {
#| break None
#| }
#| let candidate = found - last_offset
#| if target
#| .data()
#| .unsafe_range_equal(
#| pattern.data(),
#| self_off=target_start + candidate,
#| other_off=pattern_start,
#| len=last_offset,
#| ) {
#| break Some(candidate)
#| }
#| continue found + 1
#| } nobreak {
#| None
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn find_short(target : BytesView, pattern : BytesView) -> Int? {
#| let target_len = target.length()
#| let pattern_len = pattern.length()
#| let last = target_len - pattern_len
#| let target_start = target.start_offset()
#| let pattern_start = pattern.start_offset()
#| let candidate_end = target_start + last + 1
#| let first = pattern.unsafe_get(0)
#| let last_offset = pattern_len - 1
#| let last_byte = pattern.unsafe_get(last_offset)
#| let middle_len = last_offset - 1
#| for pos = 0; pos <= last; {
#| let found = find_short_candidate_from_bytes(
#| target.data(),
#| target_start + pos,
#| candidate_end,
#| first,
#| last_offset,
#| last_byte,
#| )
#| if found < 0 {
#| break None
#| }
#| let candidate = found - target_start
#| if target
#| .data()
#| .unsafe_range_equal(
#| pattern.data(),
#| self_off=found + 1,
#| other_off=pattern_start + 1,
#| len=middle_len,
#| ) {
#| break Some(candidate)
#| }
#| continue candidate + 1
#| } nobreak {
#| None
#| }
#|}
#|#cfg(any(target="js", target="wasm-gc"))
#|fn rev_find_short_candidate_from_view(
#| target : BytesView,
#| start : Int,
#| candidate_end : Int,
#| first : Byte,
#| last_offset : Int,
#| last : Byte,
#|) -> Int {
#| for pos = candidate_end - 1; pos >= start; {
#| if target.unsafe_get(pos) == first &&
#| target.unsafe_get(pos + last_offset) == last {
#| break pos
#| }
#| continue pos - 1
#| } nobreak {
#| -1
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn find_short_candidate_from_bytes(
#| data : Bytes,
#| start : Int,
#| candidate_end : Int,
#| first : Byte,
#| last_offset : Int,
#| last : Byte,
#|) -> Int {
#| let first_v = i8x16_splat(first)
#| let last_v = i8x16_splat(last)
#| let tail_start = for pos = start; pos + 16 <= candidate_end; {
#| let mask = v128_and(
#| i8x16_eq(data.v128_load(pos), first_v),
#| i8x16_eq(data.v128_load(pos + last_offset), last_v),
#| )
#| let bits = i8x16_bitmask(mask)
#| if bits != 0 {
#| return pos + bits.ctz()
#| }
#| continue pos + 16
#| } nobreak {
#| pos
#| }
#| for pos in tail_start.. Int {
#| let first_v = i8x16_splat(first)
#| let last_v = i8x16_splat(last)
#| let head_end = for pos = candidate_end; pos - 16 >= start; {
#| let chunk_start = pos - 16
#| let mask = v128_and(
#| i8x16_eq(data.v128_load(chunk_start), first_v),
#| i8x16_eq(data.v128_load(chunk_start + last_offset), last_v),
#| )
#| let bits = i8x16_bitmask(mask)
#| if bits != 0 {
#| return chunk_start + 31 - bits.clz()
#| }
#| continue chunk_start
#| } nobreak {
#| pos
#| }
#| for pos = head_end - 1; pos >= start; {
#| if data.unsafe_get(pos) == first &&
#| data.unsafe_get(pos + last_offset) == last {
#| break pos
#| }
#| continue pos - 1
#| } nobreak {
#| -1
#| }
#|}
#|declare fn rev_find_by_byte_scanner(
#| target : BytesView,
#| pattern : BytesView,
#|) -> Int?
#|#cfg(any(target="js", target="wasm-gc"))
#|fn rev_find_by_byte_scanner(target : BytesView, pattern : BytesView) -> Int? {
#| let target_len = target.length()
#| let pattern_len = pattern.length()
#| let last = target_len - pattern_len
#| let target_start = target.start_offset()
#| let pattern_start = pattern.start_offset()
#| let first = pattern.unsafe_get(0)
#| let last_offset = pattern_len - 1
#| let last_byte = pattern.unsafe_get(last_offset)
#| let middle_len = last_offset - 1
#| for candidate_end = last + 1; candidate_end > 0; {
#| let found = rev_find_short_candidate_from_view(
#| target, 0, candidate_end, first, last_offset, last_byte,
#| )
#| if found < 0 {
#| break None
#| }
#| if target
#| .data()
#| .unsafe_range_equal(
#| pattern.data(),
#| self_off=target_start + found + 1,
#| other_off=pattern_start + 1,
#| len=middle_len,
#| ) {
#| break Some(found)
#| }
#| continue found
#| } nobreak {
#| None
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn rev_find_by_byte_scanner(target : BytesView, pattern : BytesView) -> Int? {
#| let target_len = target.length()
#| let pattern_len = pattern.length()
#| let last = target_len - pattern_len
#| let target_start = target.start_offset()
#| let pattern_start = pattern.start_offset()
#| let first = pattern.unsafe_get(0)
#| let last_offset = pattern_len - 1
#| let last_byte = pattern.unsafe_get(last_offset)
#| let middle_len = last_offset - 1
#| for candidate_end = last + 1; candidate_end > 0; {
#| let found = rev_find_short_candidate_from_bytes(
#| target.data(),
#| target_start,
#| target_start + candidate_end,
#| first,
#| last_offset,
#| last_byte,
#| )
#| if found < 0 {
#| break None
#| }
#| let candidate = found - target_start
#| if target
#| .data()
#| .unsafe_range_equal(
#| pattern.data(),
#| self_off=found + 1,
#| other_off=pattern_start + 1,
#| len=middle_len,
#| ) {
#| break Some(candidate)
#| }
#| continue candidate
#| } nobreak {
#| None
#| }
#|}
#|fn find_rabin_karp_from(
#| target : BytesView,
#| pattern : BytesView,
#| start : Int,
#|) -> Int? {
#| fn hash(bytes : BytesView, start : Int, length : Int) -> UInt {
#| for i in 0.. UInt {
#| for pow = 1U, square = find_prime_rk, exp = length; exp > 0; {
#| let next_pow = if exp % 2 == 1 { pow * square } else { pow }
#| continue next_pow, square * square, exp / 2
#| } nobreak {
#| pow
#| }
#| }
#| let pattern_len = pattern.length()
#| let target_len = target.length()
#| if start + pattern_len > target_len {
#| return None
#| }
#| let target_start = target.start_offset()
#| let pattern_start = pattern.start_offset()
#| let pattern_hash = hash(pattern, 0, pattern_len)
#| let pow = prime_pow(pattern_len)
#| let hash = hash(target, start, pattern_len)
#| if hash == pattern_hash &&
#| target
#| .data()
#| .unsafe_range_equal(
#| pattern.data(),
#| self_off=target_start + start,
#| other_off=pattern_start,
#| len=pattern_len,
#| ) {
#| return Some(start)
#| }
#| for index = start + pattern_len, hash = hash; index < target_len; {
#| let hash = hash * find_prime_rk + target.unsafe_get(index).to_uint()
#| let hash = hash - pow * target.unsafe_get(index - pattern_len).to_uint()
#| let candidate = index - pattern_len + 1
#| if hash == pattern_hash &&
#| target
#| .data()
#| .unsafe_range_equal(
#| pattern.data(),
#| self_off=target_start + candidate,
#| other_off=pattern_start,
#| len=pattern_len,
#| ) {
#| break Some(candidate)
#| }
#| continue index + 1, hash
#| } nobreak {
#| None
#| }
#|}
#|fn find_long_by_byte_scanner(target : BytesView, pattern : BytesView) -> Int? {
#| let target_len = target.length()
#| let pattern_len = pattern.length()
#| let last = target_len - pattern_len
#| let target_start = target.start_offset()
#| let pattern_start = pattern.start_offset()
#| let first_byte = pattern.unsafe_get(0)
#| for pos = 0, failures = 0; pos <= last; {
#| let found = find_byte_from_view(target, pos, target_len, first_byte)
#| if found < 0 || found > last {
#| break None
#| }
#| if target
#| .data()
#| .unsafe_range_equal(
#| pattern.data(),
#| self_off=target_start + found + 1,
#| other_off=pattern_start + 1,
#| len=pattern_len - 1,
#| ) {
#| break Some(found)
#| }
#| let failures = failures + 1
#| if failures > find_max_bruteforce || failures > find_cutover(found) {
#| break find_rabin_karp_from(target, pattern, found + 1)
#| }
#| continue found + 1, failures
#| } nobreak {
#| None
#| }
#|}
#|pub fn BytesView::rev_find(target : BytesView, pattern : BytesView) -> Int? {
#| let target_len = target.length()
#| let pattern_len = pattern.length()
#| if pattern_len == 0 {
#| return Some(target_len)
#| }
#| if pattern_len > target_len {
#| return None
#| }
#| if pattern_len == 1 {
#| let found = rev_find_byte_from_view(
#| target,
#| 0,
#| target_len,
#| pattern.unsafe_get(0),
#| )
#| if found < 0 {
#| None
#| } else {
#| Some(found)
#| }
#| } else if pattern_len == target_len {
#| if target == pattern {
#| Some(0)
#| } else {
#| None
#| }
#| } else {
#| rev_find_by_byte_scanner(target, pattern)
#| }
#|}
#|pub fn Bytes::rev_find(target : Bytes, pattern : BytesView) -> Int? {
#| target[:].rev_find(pattern)
#|}
#|pub fn BytesView::has_prefix(self : BytesView, prefix : BytesView) -> Bool {
#| let prefix_len = prefix.length()
#| self.length() >= prefix_len && self[:prefix_len] == prefix
#|}
#|pub fn Bytes::has_prefix(self : Bytes, prefix : BytesView) -> Bool {
#| self[:].has_prefix(prefix)
#|}
#|pub fn BytesView::has_suffix(self : BytesView, suffix : BytesView) -> Bool {
#| let self_len = self.length()
#| let suffix_len = suffix.length()
#| self_len >= suffix_len && self[self_len - suffix_len:] == suffix
#|}
#|pub fn Bytes::has_suffix(self : Bytes, suffix : BytesView) -> Bool {
#| self[:].has_suffix(suffix)
#|}
#|pub fn BytesView::chop_prefix(
#| self : BytesView,
#| prefix : BytesView,
#|) -> BytesView? {
#| let prefix_len = prefix.length()
#| if self.length() >= prefix_len && self[:prefix_len] == prefix {
#| Some(self[prefix_len:])
#| } else {
#| None
#| }
#|}
#|pub fn Bytes::chop_prefix(self : Bytes, prefix : BytesView) -> BytesView? {
#| self[:].chop_prefix(prefix)
#|}
#|pub fn BytesView::chop_suffix(
#| self : BytesView,
#| suffix : BytesView,
#|) -> BytesView? {
#| let self_len = self.length()
#| let suffix_len = suffix.length()
#| if self_len >= suffix_len && self[self_len - suffix_len:] == suffix {
#| Some(self[:self_len - suffix_len])
#| } else {
#| None
#| }
#|}
#|pub fn Bytes::chop_suffix(self : Bytes, suffix : BytesView) -> BytesView? {
#| self[:].chop_suffix(suffix)
#|}
),
"bytes_unsafe.mbt": (
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_write_uint64_le")
#|pub fn FixedArray::unsafe_write_uint64_le(
#| bytes : FixedArray[Byte],
#| index : Int,
#| value : UInt64,
#|) -> Unit {
#| bytes.unsafe_set(index, value.to_byte())
#| bytes.unsafe_set(index + 1, (value >> 8).to_byte())
#| bytes.unsafe_set(index + 2, (value >> 16).to_byte())
#| bytes.unsafe_set(index + 3, (value >> 24).to_byte())
#| bytes.unsafe_set(index + 4, (value >> 32).to_byte())
#| bytes.unsafe_set(index + 5, (value >> 40).to_byte())
#| bytes.unsafe_set(index + 6, (value >> 48).to_byte())
#| bytes.unsafe_set(index + 7, (value >> 56).to_byte())
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_write_uint64_be")
#|pub fn FixedArray::unsafe_write_uint64_be(
#| bytes : FixedArray[Byte],
#| index : Int,
#| value : UInt64,
#|) -> Unit {
#| bytes.unsafe_set(index, (value >> 56).to_byte())
#| bytes.unsafe_set(index + 1, (value >> 48).to_byte())
#| bytes.unsafe_set(index + 2, (value >> 40).to_byte())
#| bytes.unsafe_set(index + 3, (value >> 32).to_byte())
#| bytes.unsafe_set(index + 4, (value >> 24).to_byte())
#| bytes.unsafe_set(index + 5, (value >> 16).to_byte())
#| bytes.unsafe_set(index + 6, (value >> 8).to_byte())
#| bytes.unsafe_set(index + 7, value.to_byte())
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_write_uint32_le")
#|pub fn FixedArray::unsafe_write_uint32_le(
#| bytes : FixedArray[Byte],
#| index : Int,
#| value : UInt,
#|) -> Unit {
#| bytes.unsafe_set(index, value.to_byte())
#| bytes.unsafe_set(index + 1, (value >> 8).to_byte())
#| bytes.unsafe_set(index + 2, (value >> 16).to_byte())
#| bytes.unsafe_set(index + 3, (value >> 24).to_byte())
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_write_uint32_be")
#|pub fn FixedArray::unsafe_write_uint32_be(
#| bytes : FixedArray[Byte],
#| index : Int,
#| value : UInt,
#|) -> Unit {
#| bytes.unsafe_set(index, (value >> 24).to_byte())
#| bytes.unsafe_set(index + 1, (value >> 16).to_byte())
#| bytes.unsafe_set(index + 2, (value >> 8).to_byte())
#| bytes.unsafe_set(index + 3, value.to_byte())
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_write_uint16_le")
#|pub fn FixedArray::unsafe_write_uint16_le(
#| bytes : FixedArray[Byte],
#| index : Int,
#| value : UInt16,
#|) -> Unit {
#| bytes.unsafe_set(index, value.to_byte())
#| bytes.unsafe_set(index + 1, (value >> 8).to_byte())
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_write_uint16_be")
#|pub fn FixedArray::unsafe_write_uint16_be(
#| bytes : FixedArray[Byte],
#| index : Int,
#| value : UInt16,
#|) -> Unit {
#| bytes.unsafe_set(index, (value >> 8).to_byte())
#| bytes.unsafe_set(index + 1, value.to_byte())
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint64_le")
#|#doc(hidden)
#|pub fn Bytes::unsafe_read_uint64_le(bytes : Bytes, index : Int) -> UInt64 {
#| bytes.unsafe_get(index).to_uint64() |
#| (bytes.unsafe_get(index + 1).to_uint64() << 8) |
#| (bytes.unsafe_get(index + 2).to_uint64() << 16) |
#| (bytes.unsafe_get(index + 3).to_uint64() << 24) |
#| (bytes.unsafe_get(index + 4).to_uint64() << 32) |
#| (bytes.unsafe_get(index + 5).to_uint64() << 40) |
#| (bytes.unsafe_get(index + 6).to_uint64() << 48) |
#| (bytes.unsafe_get(index + 7).to_uint64() << 56)
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint64_be")
#|#doc(hidden)
#|pub fn Bytes::unsafe_read_uint64_be(bytes : Bytes, index : Int) -> UInt64 {
#| (bytes.unsafe_get(index).to_uint64() << 56) |
#| (bytes.unsafe_get(index + 1).to_uint64() << 48) |
#| (bytes.unsafe_get(index + 2).to_uint64() << 40) |
#| (bytes.unsafe_get(index + 3).to_uint64() << 32) |
#| (bytes.unsafe_get(index + 4).to_uint64() << 24) |
#| (bytes.unsafe_get(index + 5).to_uint64() << 16) |
#| (bytes.unsafe_get(index + 6).to_uint64() << 8) |
#| bytes.unsafe_get(index + 7).to_uint64()
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint32_le")
#|#doc(hidden)
#|pub fn Bytes::unsafe_read_uint32_le(bytes : Bytes, index : Int) -> UInt {
#| bytes.unsafe_get(index).to_uint() |
#| (bytes.unsafe_get(index + 1).to_uint() << 8) |
#| (bytes.unsafe_get(index + 2).to_uint() << 16) |
#| (bytes.unsafe_get(index + 3).to_uint() << 24)
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint32_be")
#|#doc(hidden)
#|pub fn Bytes::unsafe_read_uint32_be(bytes : Bytes, index : Int) -> UInt {
#| (bytes.unsafe_get(index).to_uint() << 24) |
#| (bytes.unsafe_get(index + 1).to_uint() << 16) |
#| (bytes.unsafe_get(index + 2).to_uint() << 8) |
#| bytes.unsafe_get(index + 3).to_uint()
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint16_le")
#|#doc(hidden)
#|pub fn Bytes::unsafe_read_uint16_le(bytes : Bytes, index : Int) -> UInt16 {
#| bytes.unsafe_get(index).to_uint16() |
#| (bytes.unsafe_get(index + 1).to_uint16() << 8)
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint16_be")
#|#doc(hidden)
#|pub fn Bytes::unsafe_read_uint16_be(bytes : Bytes, index : Int) -> UInt16 {
#| (bytes.unsafe_get(index).to_uint16() << 8) |
#| bytes.unsafe_get(index + 1).to_uint16()
#|}
#|#doc(hidden)
#|pub fn BytesView::unsafe_read_uint64_le(
#| bytes : BytesView,
#| index : Int,
#|) -> UInt64 {
#| bytes.bytes().unsafe_read_uint64_le(bytes.start() + index)
#|}
#|#doc(hidden)
#|pub fn BytesView::unsafe_read_uint64_be(
#| bytes : BytesView,
#| index : Int,
#|) -> UInt64 {
#| bytes.bytes().unsafe_read_uint64_be(bytes.start() + index)
#|}
#|#doc(hidden)
#|pub fn BytesView::unsafe_read_uint32_le(bytes : BytesView, index : Int) -> UInt {
#| bytes.bytes().unsafe_read_uint32_le(bytes.start() + index)
#|}
#|#doc(hidden)
#|pub fn BytesView::unsafe_read_uint32_be(bytes : BytesView, index : Int) -> UInt {
#| bytes.bytes().unsafe_read_uint32_be(bytes.start() + index)
#|}
#|#doc(hidden)
#|pub fn BytesView::unsafe_read_uint16_le(
#| bytes : BytesView,
#| index : Int,
#|) -> UInt16 {
#| bytes.bytes().unsafe_read_uint16_le(bytes.start() + index)
#|}
#|#doc(hidden)
#|pub fn BytesView::unsafe_read_uint16_be(
#| bytes : BytesView,
#| index : Int,
#|) -> UInt16 {
#| bytes.bytes().unsafe_read_uint16_be(bytes.start() + index)
#|}
#|#borrow(self, other)
#|#intrinsic("%bytes.unsafe_range_equal")
#|fn Bytes::unsafe_range_equal(
#| self : Bytes,
#| self_off~ : Int,
#| other : Bytes,
#| other_off~ : Int,
#| len~ : Int,
#|) -> Bool {
#| for i in 0.. FixedArray[Byte] = "%identity"
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint16_le")
#|fn fixedarray_read_uint16_le(bytes : FixedArray[Byte], index : Int) -> UInt16 {
#| bytes.unsafe_get(index).to_uint16() |
#| (bytes.unsafe_get(index + 1).to_uint16() << 8)
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint16_be")
#|fn fixedarray_read_uint16_be(bytes : FixedArray[Byte], index : Int) -> UInt16 {
#| (bytes.unsafe_get(index).to_uint16() << 8) |
#| bytes.unsafe_get(index + 1).to_uint16()
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint32_le")
#|fn fixedarray_read_uint32_le(bytes : FixedArray[Byte], index : Int) -> UInt {
#| bytes.unsafe_get(index).to_uint() |
#| (bytes.unsafe_get(index + 1).to_uint() << 8) |
#| (bytes.unsafe_get(index + 2).to_uint() << 16) |
#| (bytes.unsafe_get(index + 3).to_uint() << 24)
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint32_be")
#|fn fixedarray_read_uint32_be(bytes : FixedArray[Byte], index : Int) -> UInt {
#| (bytes.unsafe_get(index).to_uint() << 24) |
#| (bytes.unsafe_get(index + 1).to_uint() << 16) |
#| (bytes.unsafe_get(index + 2).to_uint() << 8) |
#| bytes.unsafe_get(index + 3).to_uint()
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint64_le")
#|fn fixedarray_read_uint64_le(bytes : FixedArray[Byte], index : Int) -> UInt64 {
#| bytes.unsafe_get(index).to_uint64() |
#| (bytes.unsafe_get(index + 1).to_uint64() << 8) |
#| (bytes.unsafe_get(index + 2).to_uint64() << 16) |
#| (bytes.unsafe_get(index + 3).to_uint64() << 24) |
#| (bytes.unsafe_get(index + 4).to_uint64() << 32) |
#| (bytes.unsafe_get(index + 5).to_uint64() << 40) |
#| (bytes.unsafe_get(index + 6).to_uint64() << 48) |
#| (bytes.unsafe_get(index + 7).to_uint64() << 56)
#|}
#|#borrow(bytes)
#|#intrinsic("%bytes.unsafe_read_uint64_be")
#|fn fixedarray_read_uint64_be(bytes : FixedArray[Byte], index : Int) -> UInt64 {
#| (bytes.unsafe_get(index).to_uint64() << 56) |
#| (bytes.unsafe_get(index + 1).to_uint64() << 48) |
#| (bytes.unsafe_get(index + 2).to_uint64() << 40) |
#| (bytes.unsafe_get(index + 3).to_uint64() << 32) |
#| (bytes.unsafe_get(index + 4).to_uint64() << 24) |
#| (bytes.unsafe_get(index + 5).to_uint64() << 16) |
#| (bytes.unsafe_get(index + 6).to_uint64() << 8) |
#| bytes.unsafe_get(index + 7).to_uint64()
#|}
),
"bytesview.mbt": (
#|fn BytesView::bytes(self : BytesView) -> Bytes = "%bytesview.bytes"
#|fn BytesView::start(self : BytesView) -> Int = "%bytesview.start"
#|fn BytesView::len(self : BytesView) -> Int = "%bytesview.len"
#|fn BytesView::make(b : Bytes, start : Int, len : Int) -> BytesView = "%bytesview.make"
#|#intrinsic("%bytesview.length")
#|pub fn BytesView::length(self : BytesView) -> Int {
#| self.len()
#|}
#|pub fn BytesView::is_empty(self : BytesView) -> Bool {
#| self.length() == 0
#|}
#|#intrinsic("%bytesview.get")
#|#alias("_[_]")
#|pub fn BytesView::at(self : BytesView, index : Int) -> Byte {
#| guard index >= 0 && index < self.length() else {
#| index_out_of_bounds(self.length(), index)
#| }
#| self.bytes().unsafe_get(self.start() + index)
#|}
#|#intrinsic("%bytesview.get_opt")
#|pub fn BytesView::get(self : BytesView, index : Int) -> Byte? {
#| guard index >= 0 && index < self.length() else { None }
#| Some(self.bytes().unsafe_get(self.start() + index))
#|}
#|#intrinsic("%bytesview.unsafe_get")
#|#internal(unsafe, "Panic if index is out of bounds")
#|#doc(hidden)
#|pub fn BytesView::unsafe_get(self : BytesView, index : Int) -> Byte {
#| self.bytes().unsafe_get(self.start() + index)
#|}
#|#intrinsic("%bytes.view")
#|#alias(view, deprecated="Use `exact_view` instead")
#|#alias(sub, deprecated="Use `exact_view` instead")
#|pub fn Bytes::exact_view(
#| self : Bytes,
#| start? : Int = 0,
#| end? : Int,
#|) -> BytesView {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else {
#| abort("Invalid index for View")
#| }
#| BytesView::make(self, start, end - start)
#|}
#|pub fn Bytes::get_view(
#| self : Bytes,
#| start? : Int = 0,
#| end? : Int,
#|) -> BytesView? {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else { None }
#| Some(BytesView::make(self, start, end - start))
#|}
#|pub fn BytesView::get_view(
#| self : BytesView,
#| start? : Int = 0,
#| end? : Int,
#|) -> BytesView? {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else { None }
#| Some(BytesView::make(self.bytes(), self.start() + start, end - start))
#|}
#|#intrinsic("%bytesview.view")
#|#alias(view, deprecated="Use `exact_view` instead")
#|#alias(sub, deprecated="Use `exact_view` instead")
#|pub fn BytesView::exact_view(
#| self : BytesView,
#| start? : Int = 0,
#| end? : Int,
#|) -> BytesView {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else {
#| abort("Invalid index for View")
#| }
#| BytesView::make(self.bytes(), self.start() + start, end - start)
#|}
#|#alias("_[_:_]")
#|pub fn Bytes::clamped_view(
#| self : Bytes,
#| start? : Int = 0,
#| end? : Int,
#|) -> BytesView {
#| let len = self.length()
#| let lo = clamp_offset(start, len)
#| let hi = match end {
#| None => len
#| Some(end) => clamp_offset(end, len)
#| }
#| let count = if hi > lo { hi - lo } else { 0 }
#| BytesView::make(self, lo, count)
#|}
#|#alias("_[_:_]")
#|pub fn BytesView::clamped_view(
#| self : BytesView,
#| start? : Int = 0,
#| end? : Int,
#|) -> BytesView {
#| let len = self.length()
#| let lo = clamp_offset(start, len)
#| let hi = match end {
#| None => len
#| Some(end) => clamp_offset(end, len)
#| }
#| let count = if hi > lo { hi - lo } else { 0 }
#| BytesView::make(self.bytes(), self.start() + lo, count)
#|}
#|#alias(iterator, deprecated)
#|pub fn BytesView::iter(self : BytesView) -> Iter[Byte] {
#| let mut i = 0
#| let len = self.length()
#| Iter::new(
#| fn() {
#| guard i < len else { None }
#| let result = self.unsafe_get(i)
#| i += 1
#| Some(result)
#| },
#| size_hint=len,
#| )
#|}
#|#alias(iterator2, deprecated)
#|pub fn BytesView::iter2(self : BytesView) -> Iter2[Int, Byte] {
#| let mut i = 0
#| let len = self.length()
#| Iter2::new(
#| fn() {
#| guard i < len else { None }
#| let result = (i, self.unsafe_get(i))
#| i += 1
#| Some(result)
#| },
#| size_hint=len,
#| )
#|}
#|fn[T : Logger] write_byte_hex(logger : T, byte : Byte) -> Unit {
#| fn hex_digit(value : Int) -> Char {
#| if value < 10 {
#| (value + '0'.to_int()).unsafe_to_char()
#| } else {
#| (value - 10 + 'a'.to_int()).unsafe_to_char()
#| }
#| }
#| let value = byte.to_int()
#| logger.write_char(hex_digit(value >> 4))
#| logger.write_char(hex_digit(value & 0x0f))
#|}
#|fn[T : Logger] BytesView::escape_to(self : BytesView, logger : T) -> Unit {
#| for byte in self {
#| if byte is (b' '..=b'~') && byte != b'"' && byte != b'\\' {
#| logger.write_char(byte.to_char())
#| } else {
#| logger.write_string("\\x")
#| write_byte_hex(logger, byte)
#| }
#| }
#|}
#|pub impl Show for BytesView with fn output(self, logger) {
#| logger <+ "b\"\{cb => self.escape_to(cb)}\""
#|}
#|pub impl Show for Bytes with fn output(self, logger) {
#| BytesView::output(self, logger)
#|}
#|pub impl Eq for BytesView with fn equal(self, other) -> Bool {
#| let len = self.length()
#| guard len == other.length() else { return false }
#| self
#| .bytes()
#| .unsafe_range_equal(
#| other.bytes(),
#| self_off=self.start(),
#| other_off=other.start(),
#| len~,
#| )
#|}
#|pub fn BytesView::equal_to_bytes(self : BytesView, other : Bytes) -> Bool {
#| let len = self.length()
#| guard len == other.length() else { return false }
#| self
#| .bytes()
#| .unsafe_range_equal(other, self_off=self.start(), other_off=0, len~)
#|}
#|pub impl Compare for BytesView with fn compare(self, other) -> Int {
#| let self_len = self.length()
#| let other_len = other.length()
#| let cmp = self_len.compare(other_len)
#| guard cmp == 0 else { return cmp }
#| self.lexical_compare(other)
#|}
#|pub fn BytesView::lexical_compare(self : BytesView, other : BytesView) -> Int {
#| self.bytesview_lexical_compare_impl(other)
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn BytesView::bytesview_lexical_compare_impl(
#| self : BytesView,
#| other : BytesView,
#|) -> Int {
#| let self_len = self.length()
#| let other_len = other.length()
#| let min_len = if self_len < other_len { self_len } else { other_len }
#| if min_len >= 16 {
#| let cmp = self.unsafe_get(0).compare(other.unsafe_get(0))
#| if cmp != 0 {
#| return cmp
#| }
#| let cmp = self.unsafe_get(1).compare(other.unsafe_get(1))
#| if cmp != 0 {
#| return cmp
#| }
#| }
#| let self_bytes = unsafe_from_bytes(self.bytes())
#| let other_bytes = unsafe_from_bytes(other.bytes())
#| let self_start = self.start()
#| let other_start = other.start()
#| let mut i = 0
#| let block_limit = min_len - min_len % 16
#| while i < block_limit {
#| let a = v128_load(self_bytes, self_start + i)
#| let b = v128_load(other_bytes, other_start + i)
#| let diff_bits = i8x16_bitmask(i8x16_eq(a, b)) ^ 0xFFFF
#| if diff_bits != 0 {
#| let lane = diff_bits.ctz()
#| return self_bytes
#| .unsafe_get(self_start + i + lane)
#| .compare(other_bytes.unsafe_get(other_start + i + lane))
#| }
#| i += 16
#| }
#| while i < min_len {
#| let cmp = self.unsafe_get(i).compare(other.unsafe_get(i))
#| if cmp != 0 {
#| return cmp
#| }
#| i += 1
#| }
#| self_len.compare(other_len)
#|}
#|#cfg(not(any(target="native", target="wasm")))
#|fn BytesView::bytesview_lexical_compare_impl(
#| self : BytesView,
#| other : BytesView,
#|) -> Int {
#| let self_len = self.length()
#| let other_len = other.length()
#| let min_len = if self_len < other_len { self_len } else { other_len }
#| for i in 0.. Bytes {
#| self.bytes()
#|}
#|pub fn BytesView::start_offset(self : BytesView) -> Int {
#| self.start()
#|}
#|#alias(to_bytes, deprecated="Use `to_owned` to allocate an owned `Bytes` from a `BytesView`")
#|pub fn BytesView::to_owned(self : BytesView) -> Bytes {
#| if 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 ToJson for BytesView with fn to_json(self) -> Json {
#| let sb = StringBuilder()
#| self.escape_to(sb)
#| Json::string(sb.to_string())
#|}
#|pub impl ToJson for Bytes with fn to_json(self : Bytes) -> Json {
#| BytesView::to_json(self)
#|}
),
"char.mbt": (
#|fn Char::to_hex(char : Char) -> String {
#| let code = char.to_int()
#| match code {
#| 0..=0xFF => code.to_byte().to_hex()
#| _..=0xFFFF => (code >> 8).to_byte().to_hex() + code.to_byte().to_hex()
#| _ =>
#| (code >> 16).to_byte().to_hex() +
#| (code >> 8).to_byte().to_hex() +
#| code.to_byte().to_hex()
#| }
#|}
#|test "Char::to_hex" {
#| inspect(Char::to_hex('A'), content="41")
#| inspect(Char::to_hex('a'), content="61")
#| inspect(Char::to_hex('0'), content="30")
#| inspect(Char::to_hex('\n'), content="0a")
#| inspect(Char::to_hex('\u{0}'), content="00")
#| inspect(Char::to_hex('\u{FF}'), content="ff")
#| inspect(Char::to_hex('\u{100}'), content="0100")
#| inspect(Char::to_hex('\u{1000}'), content="1000")
#| inspect(Char::to_hex('😀'), content="01f600")
#|}
#|pub impl Hash for Char with fn hash_combine(self, hasher) -> Unit {
#| hasher.combine_char(self)
#|}
#|pub impl Hash for Char with fn hash(self : Char) -> Int {
#| Hash::hash(self.to_uint())
#|}
#|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{09}'..='\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 {
#| if self <= '\u{20}' {
#| return self.is_ascii_whitespace()
#| }
#| self
#| is ('\u0085'
#| | '\u00A0'
#| | '\u1680'
#| | '\u2000'..='\u200A'
#| | '\u2028'
#| | '\u2029'
#| | '\u202F'
#| | '\u205F'
#| | '\u3000')
#|}
#|pub fn Char::is_numeric(self : Self) -> Bool {
#| if self is ('0'..='9') {
#| return true
#| }
#| if self < '\u{B2}' {
#| return false
#| }
#| self
#| is ('\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 fn to_string(self : Char) -> String {
#| char_to_string(self)
#|}
#|#intrinsic("%char.to_string")
#|fn char_to_string(char : Char) -> String {
#| [char]
#|}
#|pub fn Char::escape(self : Char, quote? : Bool = true) -> String {
#| let buf = StringBuilder()
#| self.escape_to(buf, quote~)
#| buf.to_string()
#|}
#|fn Char::escape_to(self : Char, logger : &Logger, quote? : Bool = true) -> Unit {
#| if quote {
#| logger.write_char('\'')
#| }
#| match self {
#| '\'' | '\\' => {
#| logger.write_char('\\')
#| logger.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() {
#| logger <+ "\\u{\{cb => cb.write_string(self.to_hex())}}"
#| } else {
#| logger.write_char(self)
#| }
#| }
#| if quote {
#| logger.write_char('\'')
#| }
#|}
#|pub impl ToJson for Char with fn to_json(self : Char) -> Json {
#| Json::string(self.to_string())
#|}
#|#alias(length, deprecated="Use `utf16_len` instead")
#|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
#|}
),
"compare_fn.mbt": (
#|pub fn[A : Compare] compare(x : A, y : A) -> Int {
#| Compare::compare(x, y)
#|}
),
"console.mbt": (
#|fn println_mono(s : String) -> Unit = "%println"
#|pub fn[T : Show] println(input : T) -> Unit {
#| println_mono(input.to_string())
#|}
#|fn eprintln_mono(s : String) -> Unit = "%eprintln"
#|pub fn[T : Show] eprintln(input : T) -> Unit {
#| eprintln_mono(input.to_string())
#|}
#|pub(all) suberror InspectError {
#| InspectError(String)
#|}
#|fn base64_encode(data : FixedArray[Byte]) -> String {
#| let base64 = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
#| let buf = StringBuilder()
#| 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 <+ "=="
#| } 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_json_string()
#| let args_loc = args_loc.to_json()
#| 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 {
#| SnapshotError(String)
#|}
#|#deprecated
#|pub(all) suberror BenchError {
#| BenchError(String)
#|}
#|test "panic error case of inspect" {
#| let x : Int = 42
#| inspect(x, content="100")
#|}
),
"deprecated.mbt": (
#|#deprecated("check `@encoding/utf8.encode`")
#|#coverage.skip
#|pub fn Bytes::of_string(str : String) -> Bytes {
#| let arr = FixedArray::make(str.length() * 2, b'\x00')
#| arr.blit_from_string(0, str, 0, str.length())
#| arr.unsafe_reinterpret_as_bytes()
#|}
#|#deprecated("Bytes are immutable. Use `FixedArray::blit_from_bytes` if it's really necessary.")
#|#alias(clone, deprecated)
#|pub fn Bytes::copy(self : Bytes) -> Bytes {
#| Bytes::makei(self.length(), i => self[i])
#|}
#|#deprecated("Use `Map([], capacity=...)` instead")
#|pub fn[K, V] Map::new(capacity? : Int = default_init_capacity) -> Map[K, V] {
#| new_map(capacity)
#|}
#|#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()
#|}
#|#deprecated("Use `s.get_char(i).unwrap()` instead", skip_current_package=true)
#|pub fn String::unsafe_char_at(self : String, index : Int) -> Char {
#| let c1 = self.unsafe_get(index)
#| if c1.is_leading_surrogate() {
#| let c2 = self.unsafe_get(index + 1)
#| code_point_of_surrogate_pair(c1.to_int(), c2.to_int())
#| } else {
#| c1.unsafe_to_char()
#| }
#|}
#|#deprecated("Use `Array(capacity=...)` instead")
#|pub fn[T] Array::new(capacity? : Int = 0) -> Array[T] {
#| Array(capacity~)
#|}
),
"double.mbt": (
#|pub fn Double::Double(self : Double) -> Double = "%identity"
#|pub fn Double::from_int(i : Int) -> Double {
#| i.to_double()
#|}
#|pub fn Double::abs(self : Double) -> Double = "%f64.abs"
#|pub fn Double::min(self : Double, other : Double) -> Double {
#| if self.is_nan() {
#| other
#| } else if other.is_nan() {
#| self
#| } else if self < other {
#| self
#| } else {
#| other
#| }
#|}
#|pub fn Double::max(self : Double, other : Double) -> Double {
#| if self.is_nan() {
#| other
#| } else if other.is_nan() {
#| self
#| } else if self > other {
#| self
#| } else {
#| other
#| }
#|}
#|pub fn Double::clamp(self : Double, min~ : Double, max~ : Double) -> Double {
#| guard! min <= max
#| if self < min {
#| min
#| } else if self > max {
#| max
#| } else {
#| self
#| }
#|}
#|pub fn Double::lerp(self : Double, target~ : Double, t~ : Double) -> Double {
#| self + (target - self) * t
#|}
#|pub fn Double::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 Double::is_nan(self : Double) -> Bool {
#| self != self
#|}
#|pub fn Double::is_inf(self : Double) -> Bool {
#| self > double_max_value || self < double_min_value
#|}
#|pub fn Double::is_pos_inf(self : Double) -> Bool {
#| self > double_max_value
#|}
#|pub fn Double::is_neg_inf(self : Double) -> Bool {
#| self < double_min_value
#|}
#|pub impl Hash for Double with fn hash_combine(self, hasher) {
#| hasher.combine_double(self)
#|}
#|#intrinsic("%f64.to_string")
#|pub fn Double::to_string(self : Double) -> String {
#| ryu_to_string(self)
#|}
#|pub impl Show for Double with fn to_string(self) {
#| Double::to_string(self)
#|}
#|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
#|}
#|#deprecated
#|#doc(hidden)
#|pub fn Double::to_be_bytes(self : Double) -> Bytes {
#| self.reinterpret_as_uint64().to_be_bytes()
#|}
#|#deprecated
#|#doc(hidden)
#|pub fn Double::to_le_bytes(self : Double) -> Bytes {
#| self.reinterpret_as_uint64().to_le_bytes()
#|}
),
"double_limits.mbt": (
#|#cfg(not(target="js"))
#|let not_a_number : Double = 0x7FF8000000000001L.reinterpret_as_double()
#|let double_max_value : Double = 0x7FEFFFFFFFFFFFFFL.reinterpret_as_double()
#|let double_min_value : Double = 0xFFEFFFFFFFFFFFFFL.reinterpret_as_double()
),
"double_mod_js.mbt": (
#|extern "js" fn Double::mod_ffi(self : Double, other : Double) -> Double =
#| #| (a, b) => (a % b)
#|pub impl Mod for Double with fn mod(self, other) {
#| self.mod_ffi(other)
#|}
),
"double_pow_js.mbt": (
#|#deprecated("Use `@math.pow` instead")
#|pub fn Double::pow(self : Double, other : Double) -> Double = "Math" "pow"
#|let _j : (FixedArray[String], StringView) -> String = FixedArray::join
),
"double_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"
),
"double_ryu_js.mbt": (
#|extern "js" fn ryu_to_string(val : Double) -> String =
#| #|(number) => number.toString()
),
"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_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_uint.mbt": (
#|pub fn Double::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)
#| }
#|}
),
"extends.mbt": (
#|type Tuple2[A, B] = (A, B)
#|type Tuple3[A, B, C] = (A, B, C)
#|type Tuple4[A, B, C, D] = (A, B, C, D)
#|type Tuple5[A, B, C, D, E] = (A, B, C, D, E)
#|type Tuple6[A, B, C, D, E, F] = (A, B, C, D, E, F)
#|type Tuple7[A, B, C, D, E, F, G] = (A, B, C, D, E, F, G)
#|type Tuple8[A, B, C, D, E, F, G, H] = (A, B, C, D, E, F, G, H)
#|type Tuple9[A, B, C, D, E, F, G, H, I] = (A, B, C, D, E, F, G, H, I)
#|type Tuple10[A, B, C, D, E, F, G, H, I, J] = (A, B, C, D, E, F, G, H, I, J)
#|type Tuple11[A, B, C, D, E, F, G, H, I, J, K] = (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#| H,
#| I,
#| J,
#| K,
#|)
#|type Tuple12[A, B, C, D, E, F, G, H, I, J, K, L] = (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#| H,
#| I,
#| J,
#| K,
#| L,
#|)
#|type Tuple13[A, B, C, D, E, F, G, H, I, J, K, L, M] = (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#| H,
#| I,
#| J,
#| K,
#| L,
#| M,
#|)
#|type Tuple14[A, B, C, D, E, F, G, H, I, J, K, L, M, N] = (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#| H,
#| I,
#| J,
#| K,
#| L,
#| M,
#| N,
#|)
#|type Tuple15[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O] = (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#| H,
#| I,
#| J,
#| K,
#| L,
#| M,
#| N,
#| O,
#|)
#|type Tuple16[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P] = (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#| H,
#| I,
#| J,
#| K,
#| L,
#| M,
#| N,
#| O,
#| P,
#|)
#|pub extend ArgsLoc with Show::{to_string}
#|pub extend Array with Add::{add}
#|pub extend Array with Compare::{compare}
#|pub extend Array with Eq::{equal}
#|pub extend Array with Hash::{hash}
#|pub extend Array with ToJson::{to_json}
#|pub extend ArrayView with Add::{add}
#|pub extend ArrayView with Compare::{compare}
#|pub extend ArrayView with Eq::{equal}
#|pub extend ArrayView with Hash::{hash}
#|pub extend ArrayView with ToJson::{to_json}
#|pub extend Bool with Compare::{compare}
#|pub extend Bool with Eq::{equal}
#|pub extend Bool with Hash::{hash}
#|pub extend Bool with Show::{to_string}
#|pub extend Bool with ToJson::{to_json}
#|pub extend Byte with Add::{add}
#|pub extend Byte with BitAnd::{land}
#|pub extend Byte with BitOr::{lor}
#|pub extend Byte with BitXOr::{lxor}
#|pub extend Byte with Compare::{compare}
#|pub extend Byte with Default::{default}
#|pub extend Byte with Div::{div}
#|pub extend Byte with Eq::{equal}
#|pub extend Byte with Hash::{hash}
#|pub extend Byte with Mod::{mod}
#|pub extend Byte with Mul::{mul}
#|pub extend Byte with Shl::{shl}
#|pub extend Byte with Shr::{shr}
#|pub extend Byte with Sub::{sub}
#|pub extend Byte with ToJson::{to_json}
#|pub extend Bytes with Add::{add}
#|pub extend Bytes with Compare::{compare}
#|pub extend Bytes with Eq::{equal}
#|pub extend Bytes with Hash::{hash}
#|pub extend Bytes with Show::{to_string}
#|pub extend Bytes with ToJson::{to_json}
#|pub extend BytesView with Compare::{compare}
#|pub extend BytesView with Eq::{equal}
#|pub extend BytesView with Hash::{hash}
#|pub extend BytesView with Show::{to_string}
#|pub extend BytesView with ToJson::{to_json}
#|pub extend Char with Compare::{compare}
#|pub extend Char with Eq::{equal}
#|pub extend Char with Hash::{hash}
#|pub extend Char with Show::{to_string}
#|pub extend Char with ToJson::{to_json}
#|pub extend Double with Add::{add}
#|pub extend Double with Compare::{compare}
#|pub extend Double with Div::{div}
#|pub extend Double with Eq::{equal}
#|pub extend Double with Hash::{hash}
#|pub extend Double with Mod::{mod}
#|pub extend Double with Mul::{mul}
#|pub extend Double with Neg::{neg}
#|pub extend Double with Sub::{sub}
#|pub extend Double with ToJson::{to_json}
#|pub extend Failure with Show::{to_string}
#|pub extend Failure with ToJson::{to_json}
#|pub extend FixedArray with Add::{add}
#|pub extend FixedArray with Compare::{compare}
#|pub extend FixedArray with Eq::{equal}
#|pub extend FixedArray with Hash::{hash}
#|pub extend FixedArray with ToJson::{to_json}
#|pub extend Int with Add::{add}
#|pub extend Int with BitAnd::{land}
#|pub extend Int with BitOr::{lor}
#|pub extend Int with BitXOr::{lxor}
#|pub extend Int with Compare::{compare}
#|pub extend Int with Div::{div}
#|pub extend Int with Eq::{equal}
#|pub extend Int with Hash::{hash}
#|pub extend Int with Mod::{mod}
#|pub extend Int with Mul::{mul}
#|pub extend Int with Neg::{neg}
#|pub extend Int with Sub::{sub}
#|pub extend Int with ToJson::{to_json}
#|pub extend Int64 with Add::{add}
#|pub extend Int64 with BitAnd::{land}
#|pub extend Int64 with BitOr::{lor}
#|pub extend Int64 with BitXOr::{lxor}
#|pub extend Int64 with Compare::{compare}
#|pub extend Int64 with Div::{div}
#|pub extend Int64 with Eq::{equal}
#|pub extend Int64 with Hash::{hash}
#|pub extend Int64 with Mod::{mod}
#|pub extend Int64 with Mul::{mul}
#|pub extend Int64 with Neg::{neg}
#|pub extend Int64 with Sub::{sub}
#|pub extend Int64 with ToJson::{to_json}
#|pub extend Iter with Add::{add}
#|pub extend Iter with ToJson::{to_json}
#|pub extend Json with Eq::{equal}
#|pub extend Map with Eq::{equal}
#|pub extend Map with ToJson::{to_json}
#|pub extend MutArrayView with Compare::{compare}
#|pub extend MutArrayView with Eq::{equal}
#|pub extend MutArrayView with Hash::{hash}
#|pub extend Option with Compare::{compare}
#|pub extend Option with Eq::{equal}
#|pub extend Option with Hash::{hash}
#|pub extend Option with ToJson::{to_json}
#|pub extend ReadOnlyArray with Compare::{compare}
#|pub extend ReadOnlyArray with Eq::{equal}
#|pub extend ReadOnlyArray with Hash::{hash}
#|pub extend ReadOnlyArray with ToJson::{to_json}
#|pub extend Result with Compare::{compare}
#|pub extend Result with Eq::{equal}
#|pub extend Result with Hash::{hash}
#|pub extend Result with ToJson::{to_json}
#|pub extend SourceLoc with Show::{to_string}
#|pub extend String with Add::{add}
#|pub extend String with Compare::{compare}
#|pub extend String with Eq::{equal}
#|pub extend String with Hash::{hash}
#|pub extend String with Show::{to_string}
#|pub extend String with ToJson::{to_json}
#|pub extend String with ToStringView::{to_string_view}
#|pub extend StringBuilder with Logger::{
#| write_char,
#| write_string,
#| write_substring,
#| write_view,
#|}
#|pub extend StringView with Add::{add}
#|pub extend StringView with Compare::{compare}
#|pub extend StringView with Eq::{equal}
#|pub extend StringView with Hash::{hash}
#|pub extend StringView with ToJson::{to_json}
#|pub extend StringView with ToStringView::{to_string_view}
#|#doc(hidden)
#|pub extend Tuple10 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple10 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple11 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple11 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple12 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple12 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple13 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple13 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple14 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple14 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple15 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple15 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple16 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple16 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple2 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple2 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple2 with Hash::{hash}
#|#doc(hidden)
#|pub extend Tuple3 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple3 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple3 with Hash::{hash}
#|#doc(hidden)
#|pub extend Tuple4 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple4 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple4 with Hash::{hash}
#|#doc(hidden)
#|pub extend Tuple5 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple5 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple5 with Hash::{hash}
#|#doc(hidden)
#|pub extend Tuple6 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple6 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple6 with Hash::{hash}
#|#doc(hidden)
#|pub extend Tuple7 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple7 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple7 with Hash::{hash}
#|#doc(hidden)
#|pub extend Tuple8 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple8 with Eq::{equal}
#|#doc(hidden)
#|pub extend Tuple9 with Compare::{compare}
#|#doc(hidden)
#|pub extend Tuple9 with Eq::{equal}
#|pub extend UInt with Add::{add}
#|pub extend UInt with BitAnd::{land}
#|pub extend UInt with BitOr::{lor}
#|pub extend UInt with BitXOr::{lxor}
#|pub extend UInt with Compare::{compare}
#|pub extend UInt with Div::{div}
#|pub extend UInt with Eq::{equal}
#|pub extend UInt with Hash::{hash}
#|pub extend UInt with Mod::{mod}
#|pub extend UInt with Mul::{mul}
#|pub extend UInt with Sub::{sub}
#|pub extend UInt with ToJson::{to_json}
#|pub extend UInt16 with Add::{add}
#|pub extend UInt16 with BitAnd::{land}
#|pub extend UInt16 with BitOr::{lor}
#|pub extend UInt16 with BitXOr::{lxor}
#|pub extend UInt16 with Compare::{compare}
#|pub extend UInt16 with Div::{div}
#|pub extend UInt16 with Eq::{equal}
#|pub extend UInt16 with Hash::{hash}
#|pub extend UInt16 with Mod::{mod}
#|pub extend UInt16 with Mul::{mul}
#|pub extend UInt16 with Shl::{shl}
#|pub extend UInt16 with Shr::{shr}
#|pub extend UInt16 with Sub::{sub}
#|pub extend UInt16 with ToJson::{to_json}
#|pub extend UInt64 with Add::{add}
#|pub extend UInt64 with BitAnd::{land}
#|pub extend UInt64 with BitOr::{lor}
#|pub extend UInt64 with BitXOr::{lxor}
#|pub extend UInt64 with Compare::{compare}
#|pub extend UInt64 with Div::{div}
#|pub extend UInt64 with Eq::{equal}
#|pub extend UInt64 with Hash::{hash}
#|pub extend UInt64 with Mod::{mod}
#|pub extend UInt64 with Mul::{mul}
#|pub extend UInt64 with Sub::{sub}
#|pub extend UInt64 with ToJson::{to_json}
#|pub extend Unit with Compare::{compare}
#|pub extend Unit with Eq::{equal}
#|pub extend Unit with Hash::{hash}
#|pub extend Unit with Show::{to_string}
#|pub extend Unit with ToJson::{to_json}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ArgsLoc with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Array with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Array with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Array with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Array with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Array with Show::{to_string, output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ArrayView with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ArrayView with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ArrayView with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend ArrayView with Show::{to_string, output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Bool with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Bool with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Bool with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Bool with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Bool with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Byte with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Byte with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Byte with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Byte with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Bytes with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Bytes with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Bytes with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Bytes with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Bytes with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend BytesView with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend BytesView with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend BytesView with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend BytesView with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Char with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Char with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Char with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Char with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Char with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Double with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Double with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Double with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Double with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Double with Show::{output}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Failure with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend FixedArray with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend FixedArray with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend FixedArray with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend FixedArray with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend FixedArray with Show::{to_string, output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int64 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int64 with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int64 with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int64 with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int64 with Show::{output}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Iter with Show::{to_string, output}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Json with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Json with Eq::{not_equal}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Map with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Map with Eq::{not_equal}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Map with Show::{to_string, output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend MutArrayView with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend MutArrayView with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend MutArrayView with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend MutArrayView with Show::{to_string, output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Option with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Option with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Option with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Option with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Option with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ReadOnlyArray with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ReadOnlyArray with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ReadOnlyArray with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ReadOnlyArray with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend ReadOnlyArray with Show::{to_string, output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Result with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Result with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Result with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Result with Show::{to_string, output}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SourceLoc with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend String with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend String with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend String with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend String with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend String with Show::{output}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend StringBuilder with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend StringView with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend StringView with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend StringView with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend StringView with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend StringView with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple10 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple10 with Eq::{not_equal}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple10 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple10 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple11 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple11 with Eq::{not_equal}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple11 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple11 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple12 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple12 with Eq::{not_equal}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple12 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple12 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple13 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple13 with Eq::{not_equal}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple13 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple13 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple14 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple14 with Eq::{not_equal}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple14 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple14 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple15 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple15 with Eq::{not_equal}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple15 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple15 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple16 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple16 with Eq::{not_equal}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple16 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple16 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple2 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple2 with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple2 with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple2 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple2 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple3 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple3 with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple3 with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple3 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple3 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple4 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple4 with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple4 with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple4 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple4 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple5 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple5 with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple5 with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple5 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple5 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple6 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple6 with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple6 with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple6 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple6 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple7 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple7 with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple7 with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple7 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple7 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple8 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple8 with Eq::{not_equal}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple8 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple8 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple9 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple9 with Eq::{not_equal}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple9 with Show::{to_string, output}
#|#deprecated("Use `ToJson::to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple9 with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt16 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt16 with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt16 with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt16 with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt16 with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt64 with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt64 with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt64 with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt64 with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt64 with Show::{output}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Unit with Compare::{op_lt, op_le, op_ge, op_gt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Unit with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Unit with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Unit with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Unit with Show::{output}
),
"failure.mbt": (
#|#warnings("-deprecated_syntax")
#|pub(all) suberror Failure {
#| Failure(String)
#|} derive(ToJson, Show)
#|#callsite(autofill(loc))
#|pub fn[T] fail(msg : StringView, loc~ : SourceLoc) -> T raise Failure {
#| raise Failure("\{loc} FAILED: \{msg}")
#|}
),
"fixedarray.mbt": (
#|#intrinsic("%fixedarray.get_opt")
#|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))
#|}
#|pub impl[X] Default for FixedArray[X] with fn default() {
#| []
#|}
#|#owned(value)
#|pub fn[T] FixedArray::fill(
#| self : FixedArray[T],
#| value : T,
#| start? : Int = 0,
#| end? : Int,
#|) -> Unit {
#| let array_length = self.length()
#| guard array_length > 0 else { return }
#| guard! start >= 0 && start < array_length
#| let length = match end {
#| None => array_length - start
#| Some(e) => {
#| guard! e >= start && e <= array_length
#| e - start
#| }
#| }
#| self.unchecked_fill(start, value, length)
#|}
#|#coverage.skip
#|#intrinsic("%fixedarray.fill")
#|#owned(value)
#|fn[T] FixedArray::unchecked_fill(
#| self : FixedArray[T],
#| start : Int,
#| value : T,
#| len : Int,
#|) -> Unit {
#| for i in start..<(start + len) {
#| self[i] = value
#| }
#|}
#|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] {
#| self[:].binary_search(value)
#|}
#|pub fn[T] FixedArray::binary_search_by(
#| self : FixedArray[T],
#| cmp : (T) -> Int raise?,
#|) -> Result[Int, Int] raise? {
#| self[:].binary_search_by(cmp)
#|}
#|#locals(f)
#|pub fn[T] FixedArray::each(
#| self : FixedArray[T],
#| f : (T) -> Unit raise?,
#|) -> Unit raise? {
#| for v in self {
#| f(v)
#| }
#|}
#|test "each" {
#| let mut i = 0
#| let mut failed = false
#| let f = elem => {
#| if elem != i + 1 {
#| failed = true
#| }
#| i += 1
#| }
#| {
#| i = 0
#| ([] : FixedArray[_]).each(f)
#| assert_false(failed)
#| inspect(i, content="0")
#| }
#| {
#| i = 0
#| ([1] : FixedArray[_]).each(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| }
#| i = 0
#| ([1, 2, 3, 4, 5] : FixedArray[_]).each(f)
#| assert_false(failed)
#| inspect(i, content="5")
#|}
#|#locals(f)
#|pub fn[T] FixedArray::eachi(
#| self : FixedArray[T],
#| f : (Int, T) -> Unit raise?,
#|) -> Unit raise? {
#| for i, v in self {
#| f(i, v)
#| }
#|}
#|test "eachi" {
#| let mut i = 0
#| let mut failed = false
#| let f = (index, elem) => {
#| if index != i || elem != i + 1 {
#| failed = true
#| }
#| i += 1
#| }
#| {
#| i = 0
#| ([] : FixedArray[_]).eachi(f)
#| assert_false(failed)
#| inspect(i, content="0")
#| }
#| {
#| i = 0
#| ([1] : FixedArray[_]).eachi(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| }
#| i = 0
#| ([1, 2, 3, 4, 5] : FixedArray[_]).eachi(f)
#| assert_false(failed)
#| inspect(i, content="5")
#|}
#|#locals(f)
#|pub fn[T] FixedArray::rev_each(
#| self : FixedArray[T],
#| f : (T) -> Unit raise?,
#|) -> Unit raise? {
#| for i in self.length()>..0 {
#| f(self.unsafe_get(i))
#| }
#|}
#|test "rev_each" {
#| let mut i = 6
#| let mut failed = false
#| let f = elem => {
#| if elem != i - 1 {
#| failed = true
#| }
#| i -= 1
#| }
#| {
#| i = 1
#| ([] : FixedArray[_]).rev_each(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| }
#| {
#| i = 2
#| ([1] : FixedArray[_]).rev_each(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| }
#| i = 6
#| ([1, 2, 3, 4, 5] : FixedArray[_]).rev_each(f)
#| assert_false(failed)
#| inspect(i, content="1")
#|}
#|#locals(f)
#|pub fn[T] FixedArray::rev_eachi(
#| self : FixedArray[T],
#| f : (Int, T) -> Unit raise?,
#|) -> Unit raise? {
#| let len = self.length()
#| for i in 0.. {
#| if index != j || elem != i - 1 {
#| failed = true
#| }
#| i -= 1
#| j += 1
#| }
#| {
#| i = 1
#| j = 0
#| ([] : FixedArray[_]).rev_eachi(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| inspect(j, content="0")
#| }
#| {
#| i = 2
#| j = 0
#| ([1] : FixedArray[_]).rev_eachi(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| inspect(j, content="1")
#| }
#| i = 6
#| j = 0
#| ([1, 2, 3, 4, 5] : FixedArray[_]).rev_eachi(f)
#| assert_false(failed)
#| inspect(i, content="1")
#| inspect(j, content="5")
#|}
#|#locals(f)
#|pub fn[T, U] FixedArray::map(
#| self : FixedArray[T],
#| f : (T) -> U raise?,
#|) -> FixedArray[U] raise? {
#| if self.is_empty() {
#| return []
#| }
#| let len = self.length()
#| let res = FixedArray::make(len, f(self.unsafe_get(0)))
#| for i in 1.. x)
#| assert_true(empty == [])
#| let simple_arr : FixedArray[_] = [6]
#| let simple_doubled = simple_arr.map(x => x * 2)
#| assert_true(simple_doubled == [12])
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| let doubled = arr.map(x => x * 2)
#| assert_true(doubled == [2, 4, 6, 8, 10])
#|}
#|#locals(f)
#|pub fn[T, U] FixedArray::mapi(
#| self : FixedArray[T],
#| f : (Int, T) -> U raise?,
#|) -> FixedArray[U] raise? {
#| if self.is_empty() {
#| return []
#| }
#| let len = self.length()
#| let res = FixedArray::make(len, f(0, self.unsafe_get(0)))
#| for i in 1.. x + i)
#| assert_true(empty == [])
#| let simple_arr : FixedArray[_] = [6]
#| let simple_doubled = simple_arr.mapi((i, x) => x * 2 + i)
#| assert_true(simple_doubled == [12])
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| let doubled = arr.mapi((i, x) => x * 2 + i)
#| assert_true(doubled == [2, 5, 8, 11, 14])
#|}
#|#locals(value)
#|pub fn[T] FixedArray::makei(
#| length : Int,
#| value : (Int) -> T raise?,
#|) -> FixedArray[T] raise? {
#| if length <= 0 {
#| []
#| } else {
#| let array = FixedArray::make(length, value(0))
#| for i in 1.. i)
#| inspect(empty.length(), content="0")
#| let simple_arr = FixedArray::makei(1, i => i)
#| inspect(simple_arr.length(), content="1")
#| inspect(simple_arr[0], content="0")
#| let arr = FixedArray::makei(2, i => i)
#| inspect(arr.length(), content="2")
#| inspect(arr[0], content="0")
#| inspect(arr[1], content="1")
#|}
#|pub fn[T] FixedArray::from_array(array : ArrayView[T]) -> FixedArray[T] {
#| FixedArray::makei(array.length(), i => array.unsafe_get(i))
#|}
#|test "from_array" {
#| let array = FixedArray::from_array([1, 2, 3, 4, 5])
#| assert_true(array == [1, 2, 3, 4, 5])
#|}
#|#locals(f)
#|pub fn[A, B] FixedArray::fold(
#| self : FixedArray[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for x in self; acc = init {
#| continue f(acc, x)
#| } nobreak {
#| acc
#| }
#|}
#|test "fold" {
#| let sum = ([] : FixedArray[_]).fold(init=1, (sum, elem) => sum + elem)
#| inspect(sum, content="1")
#| let sum = ([1] : FixedArray[_]).fold(init=2, (sum, elem) => sum + elem)
#| inspect(sum, content="3")
#| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).fold(init=0, (sum, elem) => {
#| sum + elem
#| })
#| inspect(sum, content="15")
#|}
#|#locals(f)
#|pub fn[A, B] FixedArray::rev_fold(
#| self : FixedArray[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for i = self.length() - 1, acc = init; i >= 0; {
#| continue i - 1, f(acc, self.unsafe_get(i))
#| } nobreak {
#| acc
#| }
#|}
#|test "rev_fold" {
#| let sum = ([] : FixedArray[_]).rev_fold(init=1, (sum, elem) => sum + elem)
#| inspect(sum, content="1")
#| let sum = ([1] : FixedArray[_]).rev_fold(init=2, (sum, elem) => sum + elem)
#| inspect(sum, content="3")
#| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).rev_fold(init=0, (sum, elem) => {
#| sum + elem
#| })
#| inspect(sum, content="15")
#|}
#|#locals(f)
#|pub fn[A, B] FixedArray::foldi(
#| self : FixedArray[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| for i, x in self; acc = init {
#| continue f(i, acc, x)
#| } nobreak {
#| acc
#| }
#|}
#|test "fold_lefti" {
#| let f = (index, sum, elem) => index + sum + elem
#| {
#| let sum = ([] : FixedArray[_]).foldi(init=1, f)
#| inspect(sum, content="1")
#| }
#| {
#| let sum = ([1] : FixedArray[_]).foldi(init=2, f)
#| inspect(sum, content="3")
#| }
#| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).foldi(init=0, f)
#| inspect(sum, content="25")
#|}
#|#locals(f)
#|pub fn[A, B] FixedArray::rev_foldi(
#| self : FixedArray[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| for i in self.length()>..0; index = 0, acc = init {
#| continue index + 1, f(index, acc, self.unsafe_get(i))
#| } nobreak {
#| acc
#| }
#|}
#|test "rev_foldi" {
#| let f = (index, sum, elem) => index + sum + elem
#| {
#| let sum = ([] : FixedArray[_]).rev_foldi(init=1, f)
#| inspect(sum, content="1")
#| }
#| {
#| let sum = ([1] : FixedArray[_]).rev_foldi(init=2, f)
#| inspect(sum, content="3")
#| }
#| let sum = ([1, 2, 3, 4, 5] : FixedArray[_]).rev_foldi(init=0, f)
#| inspect(sum, content="25")
#|}
#|test "rev_foldi preserves reversed index element pairs" {
#| let trace = ([10, 20, 30] : FixedArray[_]).rev_foldi(init=0, (
#| index,
#| acc,
#| elem,
#| ) => acc * 1000 + index * 100 + elem)
#| inspect(trace, content="30120210")
#|}
#|#alias(rev_inplace, deprecated)
#|pub fn[T] FixedArray::rev_in_place(self : FixedArray[T]) -> Unit {
#| let mid_len = self.length() / 2
#| for i in 0.. FixedArray[T] {
#| match self {
#| [] => []
#| [.., first] => {
#| let res = FixedArray::make(self.length(), first)
#| let len = self.length()
#| for i in 1.. Unit {
#| let temp = self[i]
#| self[i] = self[j]
#| self[j] = temp
#|}
#|test "swap" {
#| {
#| let arr : FixedArray[Int] = [1]
#| arr.swap(0, 0)
#| assert_true(arr == [1])
#| }
#| {
#| let arr : FixedArray[_] = [1, 2]
#| arr.swap(0, 0)
#| assert_true(arr == [1, 2])
#| arr.swap(0, 1)
#| assert_true(arr == [2, 1])
#| }
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| arr.swap(3, 3)
#| assert_true(arr == [1, 2, 3, 4, 5])
#| arr.swap(1, 3)
#| assert_true(arr == [1, 4, 3, 2, 5])
#|}
#|#alias(every)
#|pub fn[T] FixedArray::all(
#| self : FixedArray[T],
#| f : (T) -> Bool raise?,
#|) -> Bool raise? {
#| self[:].all(f)
#|}
#|test "all" {
#| {
#| let arr : FixedArray[Int] = []
#| assert_true(arr.all(ele => ele < 6))
#| assert_true(arr.all(ele => ele < 5))
#| }
#| {
#| let arr : FixedArray[_] = [5]
#| assert_true(arr.all(ele => ele < 6))
#| assert_false(arr.all(ele => ele < 5))
#| }
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| assert_true(arr.all(ele => ele < 6))
#| assert_false(arr.all(ele => ele < 5))
#|}
#|#alias(exists)
#|pub fn[T] FixedArray::any(
#| self : FixedArray[T],
#| f : (T) -> Bool raise?,
#|) -> Bool raise? {
#| self[:].any(f)
#|}
#|test "any" {
#| {
#| let arr : FixedArray[Int] = []
#| assert_false(arr.any(ele => ele < 6))
#| assert_false(arr.any(ele => ele < 5))
#| }
#| {
#| let arr : FixedArray[_] = [5]
#| assert_true(arr.any(ele => ele < 6))
#| assert_false(arr.any(ele => ele < 5))
#| }
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| assert_true(arr.any(ele => ele < 6))
#| assert_true(arr.any(ele => ele < 5))
#|}
#|test "fill" {
#| {
#| let arr : FixedArray[Int] = []
#| arr.fill(3)
#| assert_true(arr == [])
#| }
#| {
#| let arr : FixedArray[_] = [6]
#| arr.fill(5)
#| assert_true(arr == [5])
#| }
#| let arr : FixedArray[_] = [0, 0, 0, 0, 0]
#| arr.fill(3)
#| assert_true(arr == [3, 3, 3, 3, 3])
#|}
#|pub fn[T : Eq] FixedArray::search(self : FixedArray[T], value : T) -> Int? {
#| self[:].search(value)
#|}
#|test "search" {
#| {
#| let arr : FixedArray[Int] = []
#| assert_true(arr.search(3) == None)
#| assert_true(arr.search(-1) == None)
#| }
#| {
#| let arr : FixedArray[_] = [3]
#| assert_true(arr.search(3) == Some(0))
#| assert_true(arr.search(-1) == None)
#| }
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| assert_true(arr.search(1) == Some(0))
#| assert_true(arr.search(5) == Some(4))
#| assert_true(arr.search(3) == Some(2))
#| assert_true(arr.search(-1) == None)
#|}
#|pub fn[T : Eq] FixedArray::contains(self : FixedArray[T], value : T) -> Bool {
#| for x in self {
#| if x == value {
#| return true
#| }
#| }
#| false
#|}
#|test "contains" {
#| {
#| let arr : FixedArray[Int] = []
#| assert_false(arr.contains(3))
#| assert_false(arr.contains(-1))
#| }
#| {
#| let arr : FixedArray[_] = [3]
#| assert_true(arr.contains(3))
#| assert_false(arr.contains(-1))
#| }
#| let arr : FixedArray[_] = [3, 4, 5]
#| assert_true(arr.contains(3))
#| assert_true(arr.contains(4))
#| assert_true(arr.contains(5))
#| assert_false(arr.contains(6))
#|}
#|pub fn[T : Eq] FixedArray::starts_with(
#| self : FixedArray[T],
#| prefix : ArrayView[T],
#|) -> Bool {
#| self[:].starts_with(prefix)
#|}
#|test "starts_with" {
#| {
#| let arr : FixedArray[Int] = []
#| assert_true(arr.starts_with([]))
#| assert_false(arr.starts_with([1]))
#| }
#| {
#| let arr : FixedArray[_] = [3]
#| assert_true(arr.starts_with([]))
#| assert_true(arr.starts_with([3]))
#| assert_false(arr.starts_with([2]))
#| assert_false(arr.starts_with([3, 1]))
#| }
#| let arr : FixedArray[_] = [3, 4, 5]
#| assert_true(arr.starts_with([]))
#| assert_true(arr.starts_with([3]))
#| assert_false(arr.starts_with([2]))
#| assert_true(arr.starts_with([3, 4]))
#| assert_false(arr.starts_with([3, 2]))
#| assert_true(arr.starts_with([3, 4, 5]))
#| assert_false(arr.starts_with([3, 4, 2]))
#| assert_false(arr.starts_with([3, 4, 5, 6]))
#|}
#|pub fn[T : Eq] FixedArray::ends_with(
#| self : FixedArray[T],
#| suffix : ArrayView[T],
#|) -> Bool {
#| self[:].ends_with(suffix)
#|}
#|test "ends_with" {
#| {
#| let arr : FixedArray[Int] = []
#| assert_true(arr.ends_with([]))
#| assert_false(arr.ends_with([1]))
#| }
#| {
#| let arr : FixedArray[_] = [3]
#| assert_true(arr.ends_with([]))
#| assert_true(arr.ends_with([3]))
#| assert_false(arr.ends_with([2]))
#| assert_false(arr.ends_with([3, 1]))
#| }
#| let arr : FixedArray[_] = [3, 4, 5]
#| assert_true(arr.ends_with([]))
#| assert_true(arr.ends_with([5]))
#| assert_false(arr.ends_with([2]))
#| assert_true(arr.ends_with([4, 5]))
#| assert_false(arr.ends_with([4, 2]))
#| assert_false(arr.ends_with([2, 5]))
#| assert_true(arr.ends_with([3, 4, 5]))
#| assert_false(arr.ends_with([3, 4, 2]))
#| assert_false(arr.ends_with([3, 2, 5]))
#| assert_false(arr.ends_with([2, 4, 5]))
#| assert_false(arr.ends_with([3, 4, 5, 6]))
#| assert_false(arr.ends_with([2, 3, 4, 5]))
#|}
#|pub impl[T : Eq] Eq for FixedArray[T] with fn equal(
#| self : FixedArray[T],
#| that : FixedArray[T],
#|) -> Bool {
#| if self.length() != that.length() {
#| return false
#| }
#| for i, x in self {
#| if x != that[i] {
#| return false
#| }
#| }
#| true
#|}
#|pub impl[T : Hash] Hash for FixedArray[T] with fn hash_combine(self, hasher) {
#| for v in self {
#| v.hash_combine(hasher)
#| }
#|}
#|test "equal" {
#| {
#| inspect(([] : FixedArray[Int]) == [], content="true")
#| inspect(([] : FixedArray[_]) == [1], content="false")
#| inspect(([1, 2] : FixedArray[_]) == [], content="false")
#| }
#| {
#| inspect(([1] : FixedArray[_]) == [1], content="true")
#| inspect(([1] : FixedArray[_]) == [2], content="false")
#| inspect(([1, 2] : FixedArray[_]) == [1], content="false")
#| inspect(([1] : FixedArray[_]) == [1, 2], content="false")
#| }
#| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [1, 2, 3, 4, 5], content="true")
#| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [1, 2, 3, 4], content="false")
#| inspect(([1, 2, 3, 4] : FixedArray[_]) == [1, 2, 3, 4, 5], content="false")
#| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [6, 2, 3, 4, 5], content="false")
#| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [1, 2, 6, 4, 5], content="false")
#| inspect(([1, 2, 3, 4, 5] : FixedArray[_]) == [1, 2, 3, 4, 6], content="false")
#|}
#|pub impl[T : Compare] Compare for FixedArray[T] with fn compare(self, other) {
#| let len_self = self.length()
#| let len_other = other.length()
#| let cmp = len_self.compare(len_other)
#| guard cmp == 0 else { return cmp }
#| for i in 0.. {
#| if i < slen {
#| self[i]
#| } else {
#| other[i - slen]
#| }
#| })
#|}
#|test "add" {
#| {
#| assert_true(([] : FixedArray[Int]) + [] == [])
#| assert_true(([] : FixedArray[_]) + [1, 2, 3, 4, 5] == [1, 2, 3, 4, 5])
#| assert_true(([1, 2, 3, 4, 5] : FixedArray[_]) + [] == [1, 2, 3, 4, 5])
#| }
#| {
#| assert_true(([1] : FixedArray[_]) + [2] == [1, 2])
#| assert_true(([1] : FixedArray[_]) + [1, 2, 3, 4, 5] == [1, 1, 2, 3, 4, 5])
#| assert_true(([1, 2, 3, 4, 5] : FixedArray[_]) + [1] == [1, 2, 3, 4, 5, 1])
#| }
#| assert_true(
#| ([1, 2, 3, 4, 5] : FixedArray[_]) + [6, 7, 8, 9, 10] ==
#| [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
#| )
#|}
#|test "iter" {
#| let arr : FixedArray[_] = [1, 2, 3, 4, 5]
#| let iter = arr.iter()
#| let exb = StringBuilder()
#| let mut i = 0
#| iter.each(x => {
#| exb <+ "\{x}\n"
#| i += 1
#| })
#| assert_true(i == arr.length())
#| inspect(
#| exb,
#| content=(
#| #|1
#| #|2
#| #|3
#| #|4
#| #|5
#| #|
#| ),
#| )
#|}
#|#alias(from_iterator, deprecated)
#|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[A : ToStringView] FixedArray::join(
#| self : FixedArray[A],
#| separator : StringView,
#|) -> String {
#| let len = self.length()
#| if len == 0 {
#| return ""
#| }
#| let first = self[0].to_string_view()
#| let size_hint = for i in 1.. Iter[X] {
#| self[:].iter()
#|}
#|#alias(iterator2, deprecated)
#|pub fn[X] FixedArray::iter2(self : FixedArray[X]) -> Iter2[Int, X] {
#| self[:].iter2()
#|}
#|#cfg(not(target="js"))
#|#alias(clone, deprecated)
#|pub fn[T] FixedArray::copy(self : FixedArray[T]) -> FixedArray[T] {
#| let len = self.length()
#| if len == 0 {
#| []
#| } else {
#| FixedArray::make_and_blit(self, allocate_len=len, init=self[0], len~)
#| }
#|}
#|#cfg(target="js")
#|#alias(clone, deprecated)
#|pub fn[T] FixedArray::copy(self : FixedArray[T]) -> FixedArray[T] {
#| JSArray::ofAnyFixedArray(self).copy().toAnyFixedArray()
#|}
#|pub fn[T : Compare] FixedArray::lexical_compare(
#| self : FixedArray[T],
#| other : FixedArray[T],
#|) -> Int {
#| self[:].lexical_compare(other)
#|}
),
"fixedarray_block.mbt": (
#|#owned(dst, src)
#|#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 {
#| dst[dst_offset + i] = src[src_offset + i]
#| }
#| }
#|}
#|#owned(dst, src)
#|#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 in len>..0 {
#| dst[dst_offset + i] = src[src_offset + i]
#| }
#|}
#|#intrinsic("%fixedarray.make_with_init_blit")
#|#owned(src, init)
#|fn[T] FixedArray::unsafe_make_and_blit(
#| src : FixedArray[T],
#| allocate_len : Int,
#| init : T,
#| src_offset : Int,
#| dst_offset : Int,
#| blit_len : Int,
#|) -> FixedArray[T] {
#| let dst = FixedArray::make(allocate_len, init)
#| FixedArray::unsafe_blit(dst, dst_offset, src, src_offset, blit_len)
#| dst
#|}
#|#owned(src, init)
#|pub fn[T] FixedArray::make_and_blit(
#| src : FixedArray[T],
#| allocate_len~ : Int,
#| init~ : T,
#| len~ : Int,
#| src_offset? : Int = 0,
#| dst_offset? : Int = 0,
#|) -> FixedArray[T] {
#| guard allocate_len >= 0 &&
#| len >= 0 &&
#| src_offset >= 0 &&
#| dst_offset >= 0 &&
#| src_offset + len <= src.length() &&
#| dst_offset + len <= allocate_len else {
#| abort(
#| "bounds check failed: allocate_len = \{allocate_len}, src_offset = \{src_offset}, dst_offset = \{dst_offset}, len = \{len}, src.length = \{src.length()}",
#| )
#| }
#| FixedArray::unsafe_make_and_blit(
#| src, allocate_len, init, src_offset, dst_offset, len,
#| )
#|}
#|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)
#|}
),
"hash_fn.mbt": (
#|pub fn[T : Hash] hash(value : T) -> Int {
#| Hash::hash(value)
#|}
),
"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
#|}
#|#alias(new, deprecated="Use `Hasher()` instead")
#|pub fn Hasher::Hasher(seed? : Int = seed) -> Hasher {
#| { acc: seed.reinterpret_as_uint() + GPRIME5, }
#|}
#|#cfg(any(target="native", target="llvm"))
#|let seed : Int = {
#| let bytes : FixedArray[Byte] = FixedArray::make(4, b'\x00')
#| if moonbit_rt_get_random_for_hash_seed(bytes) == 0 {
#| fixedarray_read_uint32_le(bytes, 0).reinterpret_as_int()
#| } else {
#| 0
#| }
#|}
#|#cfg(any(target="wasm", target="wasm-gc"))
#|let seed : Int = 0
#|#cfg(target="js")
#|let seed : Int = random_seed()
#|#cfg(target="js")
#|extern "js" fn random_seed() -> Int =
#| #|() => {
#| #| if (globalThis.crypto?.getRandomValues) {
#| #| const array = new Uint32Array(1);
#| #| globalThis.crypto.getRandomValues(array);
#| #| return array[0] | 0; // Convert to signed 32
#| #| } else {
#| #| return Math.floor(Math.random() * 0x100000000) | 0; // Fallback to Math.random
#| #| }
#| #|}
#|#cfg(any(target="native", target="llvm"))
#|#borrow(bytes)
#|extern "c" fn moonbit_rt_get_random_for_hash_seed(
#| bytes : FixedArray[Byte],
#|) -> Int = "moonbit_rt_get_random"
#|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(if value is 0 { 0L } else { value.reinterpret_as_int64() })
#|}
#|#deprecated
#|pub fn Hasher::combine_float(self : Hasher, value : Float) -> Unit {
#| self.combine_uint(if value is 0 { 0U } else { value.reinterpret_as_uint() })
#|}
#|fn Float::reinterpret_as_uint(self : Float) -> UInt = "%f32.to_i32_reinterpret"
#|pub fn Hasher::combine_byte(self : Hasher, value : Byte) -> Unit {
#| self.consume1(value)
#|}
#|pub fn Hasher::combine_bytes(self : Hasher, value : Bytes) -> Unit {
#| for data = value.exact_view() {
#| if data is [u32le(x), .. rest] {
#| self.consume4(x)
#| continue rest
#| } else {
#| if data is [b0, .. data] {
#| self.consume1(b0)
#| if data is [b1, .. data] {
#| self.consume1(b1)
#| if data is [b2, ..] {
#| self.consume1(b2)
#| }
#| }
#| }
#| break
#| }
#| }
#|}
#|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 {
#| finalize_acc(self.acc)
#|}
#|fn finalize_acc(acc : UInt) -> Int {
#| avalanche_acc(acc).reinterpret_as_int()
#|}
#|fn avalanche_acc(acc : UInt) -> UInt {
#| let mut acc = 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 = consume4_acc(self.acc, input)
#|}
#|fn consume4_acc(acc : UInt, input : UInt) -> UInt {
#| rotl(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))
#|}
#|pub impl Hash for String with fn hash_combine(self, hasher) {
#| hasher.combine_string(self)
#|}
#|pub impl Hash for String with fn hash(self : String) -> Int {
#| let mut acc = seed.reinterpret_as_uint() + GPRIME5
#| for i in 0.. Unit {
#| let str = self.str()
#| for i in self.start().. Int {
#| let str = self.str()
#| let mut acc = seed.reinterpret_as_uint() + GPRIME5
#| for i in self.start().. Int {
#| let acc = seed.reinterpret_as_uint() + GPRIME5 + 4U
#| finalize_acc(consume4_acc(acc, self.reinterpret_as_uint()))
#|}
#|pub impl Hash for UInt with fn hash_combine(self, hasher) {
#| hasher.combine_uint(self)
#|}
#|pub impl Hash for UInt with fn hash(self : UInt) -> Int {
#| let acc = seed.reinterpret_as_uint() + GPRIME5 + 4U
#| finalize_acc(consume4_acc(acc, self))
#|}
#|pub impl Hash for UInt64 with fn hash_combine(self, hasher) {
#| hasher.combine_uint64(self)
#|}
#|pub impl Hash for UInt64 with fn hash(self : UInt64) -> Int {
#| let acc = seed.reinterpret_as_uint() + GPRIME5 + 8U
#| let low = (self & 0xFFFF_FFFFUL).to_uint()
#| let high = ((self >> 32) & 0xFFFF_FFFFUL).to_uint()
#| let acc = consume4_acc(acc, low)
#| let acc = consume4_acc(acc, high)
#| finalize_acc(acc)
#|}
#|pub impl[X : Hash] Hash for X? with fn hash_combine(self, hasher) {
#| match self {
#| None => hasher.combine_int(0)
#| Some(x) => {
#| hasher.combine_int(1)
#| hasher.combine(x)
#| }
#| }
#|}
#|pub impl[T : Hash, E : Hash] Hash for Result[T, E] with fn hash_combine(
#| self,
#| hasher,
#|) {
#| match self {
#| Ok(x) => {
#| hasher.combine_int(0)
#| hasher.combine(x)
#| }
#| Err(x) => {
#| hasher.combine_int(1)
#| hasher.combine(x)
#| }
#| }
#|}
#|pub impl Hash for BytesView with fn hash_combine(
#| self : BytesView,
#| hasher : Hasher,
#|) {
#| for data = self {
#| if data is [u32le(x), .. rest] {
#| hasher.combine_uint(x)
#| continue rest
#| } else {
#| if data is [b0, .. data] {
#| hasher.combine_byte(b0)
#| if data is [b1, .. data] {
#| hasher.combine_byte(b1)
#| if data is [b2, ..] {
#| hasher.combine_byte(b2)
#| }
#| }
#| }
#| break
#| }
#| }
#|}
),
"int.mbt": (
#|pub fn Int::Int(self : Int) -> Int = "%identity"
#|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
#|}
#|pub fn Int::abs(self : Int) -> Int {
#| if self < 0 {
#| -self
#| } else {
#| self
#| }
#|}
),
"int64.mbt": (
#|pub fn Int64::Int64(self : Int64) -> Int64 = "%identity"
#|pub fn Int64::from_int(i : Int) -> Int64 {
#| i.to_int64()
#|}
#|pub fn Int64::abs(self : Int64) -> Int64 {
#| if self < 0L {
#| -self
#| } else {
#| self
#| }
#|}
#|pub fn Int64::min(self : Int64, other : Int64) -> Int64 {
#| if self < other {
#| self
#| } else {
#| other
#| }
#|}
#|pub fn Int64::max(self : Int64, other : Int64) -> Int64 {
#| if self > other {
#| self
#| } else {
#| other
#| }
#|}
#|pub fn Int64::clamp(self : Int64, min~ : Int64, max~ : Int64) -> Int64 {
#| guard! min <= max
#| if self < min {
#| min
#| } else if self > max {
#| max
#| } else {
#| self
#| }
#|}
#|pub impl Hash for Int64 with fn hash_combine(self, hasher) {
#| hasher.combine_int64(self)
#|}
#|pub impl Hash for Int64 with fn hash(self : Int64) -> Int {
#| Hash::hash(self.reinterpret_as_uint64())
#|}
#|pub impl Neg for Int64 with fn neg(self : Int64) -> Int64 = "%i64_neg"
#|pub impl Add for Int64 with fn add(self, other) = "%i64_add"
#|pub impl Sub for Int64 with fn sub(self, other) = "%i64_sub"
#|pub impl Mul for Int64 with fn mul(self, other) = "%i64_mul"
#|pub impl Div for Int64 with fn div(self, other) = "%i64_div"
#|pub impl Mod for Int64 with fn mod(self, other) = "%i64_mod"
#|pub fn Int64::lnot(self : Int64) -> Int64 = "%i64_lnot"
#|pub impl BitAnd for Int64 with fn land(self, other) = "%i64_land"
#|pub impl BitOr for Int64 with fn lor(self, other) = "%i64_lor"
#|pub impl BitXOr for Int64 with fn 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 fn shl(self, other) = "%i64_shl"
#|pub impl Shr for Int64 with fn 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 fn equal(self : Int64, other : Int64) -> Bool = "%i64_eq"
#|pub impl Eq for Int64 with fn not_equal(self : Int64, other : Int64) -> Bool = "%i64_ne"
#|pub impl Compare for Int64 with fn compare(self, other) = "%i64_compare"
#|pub impl Compare for Int64 with fn op_lt(x, y) = "%i64.lt"
#|pub impl Compare for Int64 with fn op_le(x, y) = "%i64.le"
#|pub impl Compare for Int64 with fn op_gt(x, y) = "%i64.gt"
#|pub impl Compare for Int64 with fn op_ge(x, y) = "%i64.ge"
#|pub impl Default for Int64 with fn 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_uint16(self : Int64) -> UInt16 = "%i64_to_u16"
#|pub fn UInt64::trunc_double(val : Double) -> UInt64 = "%f64.to_u64"
#|#deprecated("Use `Float::from_int64` instead")
#|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 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_uint16(self : UInt64) -> UInt16 {
#| self.reinterpret_as_int64().to_uint16()
#|}
#|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 fn add(self, other) = "%u64.add"
#|pub impl Sub for UInt64 with fn sub(self, other) = "%u64.sub"
#|pub impl Mul for UInt64 with fn mul(self, other) = "%u64.mul"
#|pub impl Div for UInt64 with fn div(self, other) = "%u64.div"
#|pub impl Mod for UInt64 with fn mod(self, other) = "%u64.mod"
#|pub impl Compare for UInt64 with fn compare(self, other) = "%u64.compare"
#|pub impl Compare for UInt64 with fn op_lt(x, y) = "%u64.lt"
#|pub impl Compare for UInt64 with fn op_le(x, y) = "%u64.le"
#|pub impl Compare for UInt64 with fn op_gt(x, y) = "%u64.gt"
#|pub impl Compare for UInt64 with fn op_ge(x, y) = "%u64.ge"
#|pub impl Eq for UInt64 with fn equal(self : UInt64, other : UInt64) -> Bool = "%u64.eq"
#|pub impl Eq for UInt64 with fn not_equal(self : UInt64, other : UInt64) -> Bool = "%u64.ne"
#|pub impl BitAnd for UInt64 with fn land(self, other) = "%u64.bitand"
#|pub impl BitOr for UInt64 with fn lor(self, other) = "%u64.bitor"
#|pub impl BitXOr for UInt64 with fn 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 fn shl(self, shift) = "%u64.shl"
#|pub impl Shr for UInt64 with fn 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"
#|#deprecated("Use `Float::from_uint64` instead")
#|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 using @abort {abort}
#|pub fn[T] panic() -> T = "%panic"
#|#deprecated
#|pub fn not(x : Bool) -> Bool = "%bool_not"
#|pub impl Eq for Bool with fn 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 fn compare(self, other) = "%bool_compare"
#|pub impl Default for Bool with fn default() = "%bool_default"
#|pub impl Neg for Int with fn neg(self) = "%i32_neg"
#|pub impl Add for Int with fn add(self, other) = "%i32_add"
#|pub impl Sub for Int with fn sub(self, other) = "%i32_sub"
#|pub impl Mul for Int with fn mul(self, other) = "%i32_mul"
#|pub impl Div for Int with fn div(self, other) = "%i32_div"
#|pub impl Mod for Int with fn mod(self, other) = "%i32_mod"
#|pub fn Int::lnot(self : Int) -> Int = "%i32_lnot"
#|pub impl BitAnd for Int with fn land(self : Int, other : Int) -> Int = "%i32_land"
#|pub impl BitOr for Int with fn lor(self : Int, other : Int) -> Int = "%i32_lor"
#|pub impl BitXOr for Int with fn lxor(self : Int, other : Int) -> Int = "%i32_lxor"
#|pub impl Shl for Int with fn shl(self, other) = "%i32_shl"
#|pub impl Shr for Int with fn 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 fn equal(self : Int, other : Int) -> Bool = "%i32_eq"
#|pub impl Eq for Int with fn not_equal(self : Int, other : Int) -> Bool = "%i32_ne"
#|pub impl Compare for Int with fn compare(self, other) = "%i32_compare"
#|pub impl Compare for Int with fn op_lt(x, y) = "%i32.lt"
#|pub impl Compare for Int with fn op_le(x, y) = "%i32.le"
#|pub impl Compare for Int with fn op_gt(x, y) = "%i32.gt"
#|pub impl Compare for Int with fn op_ge(x, y) = "%i32.ge"
#|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 fn 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 fn neg(self) = "%f64_neg"
#|pub impl Add for Double with fn add(self, other) = "%f64_add"
#|pub impl Sub for Double with fn sub(self, other) = "%f64_sub"
#|pub impl Mul for Double with fn mul(self, other) = "%f64_mul"
#|pub impl Div for Double with fn div(self, other) = "%f64_div"
#|pub fn Double::sqrt(self : Double) -> Double = "%f64_sqrt"
#|pub impl Eq for Double with fn equal(self : Double, other : Double) -> Bool = "%f64_eq"
#|pub impl Eq for Double with fn not_equal(self : Double, other : Double) -> Bool = "%f64_ne"
#|#deprecated("Use `a != b` instead")
#|#doc(hidden)
#|pub fn Double::op_neq(self : Double, other : Double) -> Bool = "%f64_ne"
#|pub impl Compare for Double with fn compare(self, other) = "%f64_compare"
#|pub impl Compare for Double with fn op_lt(x, y) = "%f64.lt"
#|pub impl Compare for Double with fn op_le(x, y) = "%f64.le"
#|pub impl Compare for Double with fn op_gt(x, y) = "%f64.gt"
#|pub impl Compare for Double with fn op_ge(x, y) = "%f64.ge"
#|pub impl Default for Double with fn 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 fn equal(self : Char, other : Char) -> Bool = "%char_eq"
#|pub impl Eq for Char with fn not_equal(self : Char, other : Char) -> Bool = "%i32_ne"
#|pub impl Compare for Char with fn compare(self, other) = "%char_compare"
#|pub impl Compare for Char with fn op_lt(x, y) = "%i32.lt"
#|pub impl Compare for Char with fn op_le(x, y) = "%i32.le"
#|pub impl Compare for Char with fn op_gt(x, y) = "%i32.gt"
#|pub impl Compare for Char with fn op_ge(x, y) = "%i32.ge"
#|pub impl Default for Char with fn default() = "%char_default"
#|#alias("_[_]")
#|pub fn Bytes::at(self : Bytes, idx : Int) -> Byte = "%bytes_get"
#|#internal(unsafe, "Panic if index is out of bounds")
#|#doc(hidden)
#|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"
#|#doc(hidden)
#|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()
#|}
#|#alias("_[_]")
#|pub fn[T] FixedArray::at(self : FixedArray[T], idx : Int) -> T = "%fixedarray.get"
#|#internal(unsafe, "Panic if index is out of bounds")
#|#doc(hidden)
#|pub fn[T] FixedArray::unsafe_get(self : FixedArray[T], idx : Int) -> T = "%fixedarray.unsafe_get"
#|#internal(unsafe, "Panic if index is out of bounds")
#|#doc(hidden)
#|pub fn[T] FixedArray::unsafe_set(
#| self : FixedArray[T],
#| idx : Int,
#| val : T,
#|) -> Unit = "%fixedarray.unsafe_set"
#|#alias("_[_]=_")
#|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"
#|#alias(charcode_length, deprecated)
#|pub fn String::length(self : String) -> Int = "%string_length"
#|#alias("_[_]")
#|#alias(code_unit_at)
#|pub fn String::at(self : String, idx : Int) -> UInt16 = "%string_get"
#|#internal(unsafe, "Undefined behavior if index is out of bounds.")
#|#doc(hidden)
#|pub fn String::unsafe_get(self : String, idx : Int) -> UInt16 = "%string.unsafe_get"
#|#internal(unsafe, "Panic if index is out of bounds.")
#|#doc(hidden)
#|#deprecated("Use `String::unsafe_get` instead")
#|pub fn String::unsafe_charcode_at(self : String, idx : Int) -> Int = "%string.unsafe_get"
#|pub impl Add for String with fn add(self, other) = "%string_add"
#|pub impl Eq for String with fn equal(self : String, other : String) -> Bool = "%string_eq"
#|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 fn add(self, other) = "%u32.add"
#|pub impl Sub for UInt with fn sub(self, other) = "%u32.sub"
#|pub impl Mul for UInt with fn mul(self, other) = "%u32.mul"
#|pub impl Div for UInt with fn div(self, other) = "%u32.div"
#|pub impl Mod for UInt with fn mod(self, other) = "%u32.mod"
#|pub impl Eq for UInt with fn equal(self : UInt, other : UInt) -> Bool = "%u32.eq"
#|pub impl Eq for UInt with fn not_equal(self : UInt, other : UInt) -> Bool = "%u32.ne"
#|#deprecated("Use `a != b` instead")
#|#doc(hidden)
#|pub fn UInt::op_neq(self : UInt, other : UInt) -> Bool = "%u32.ne"
#|pub impl Compare for UInt with fn compare(self, other) = "%u32.compare"
#|pub impl Compare for UInt with fn op_lt(x, y) = "%u32.lt"
#|pub impl Compare for UInt with fn op_le(x, y) = "%u32.le"
#|pub impl Compare for UInt with fn op_gt(x, y) = "%u32.gt"
#|pub impl Compare for UInt with fn op_ge(x, y) = "%u32.ge"
#|pub impl BitAnd for UInt with fn land(self : UInt, other : UInt) -> UInt = "%u32.bitand"
#|pub impl BitOr for UInt with fn lor(self : UInt, other : UInt) -> UInt = "%u32.bitor"
#|pub impl BitXOr for UInt with fn 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 fn shl(self, shift) = "%u32.shl"
#|pub impl Shr for UInt with fn 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"
#|#deprecated("Use `Float::from_int` instead")
#|pub fn Int::to_float(self : Int) -> Float = "%i32.to_f32"
#|#deprecated("Use `Float::reinterpret_from_int` instead")
#|pub fn Int::reinterpret_as_float(self : Int) -> Float = "%i32.to_f32_reinterpret"
#|#deprecated("Use `Float::reinterpret_from_uint` instead")
#|pub fn UInt::reinterpret_as_float(self : UInt) -> Float = "%i32.to_f32_reinterpret"
#|#deprecated("Use `Float::from_byte` instead")
#|pub fn Byte::to_float(self : Byte) -> Float = "%byte.to_f32"
#|pub fn Byte::to_double(self : Byte) -> Double {
#| self.to_int().to_double()
#|}
#|#deprecated("Use `Float::from_double` instead", skip_current_package=true)
#|pub fn Double::to_float(self : Double) -> Float = "%f64.to_f32"
#|#deprecated("Use `Float::from_uint` instead")
#|pub fn UInt::to_float(self : UInt) -> Float = "%u32.to_f32"
#|pub fn Float::Float(self : Float) -> Float = "%identity"
#|pub fn Int16::Int16(self : Int16) -> Int16 = "%identity"
#|#deprecated("Use `Int16::from_int` instead")
#|pub fn Int::to_int16(self : Int) -> Int16 = "%i32_to_i16"
#|#deprecated("Use `Int16::from_byte` instead")
#|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 UInt::to_uint16(self : UInt) -> UInt16 {
#| self.reinterpret_as_int().to_uint16()
#|}
#|pub fn Int::to_uint16(self : Int) -> UInt16 = "%i32_to_u16"
#|pub fn Byte::to_uint16(self : Byte) -> UInt16 = "%byte_to_u16"
),
"iter.mbt": (
#|pub fn Int::until(
#| self : Int,
#| end : Int,
#| step? : Int = 1,
#| inclusive? : Bool = false,
#|) -> Iter[Int] {
#| until_impl(self, end, step, inclusive)
#|}
#|pub fn Int64::until(
#| self : Int64,
#| end : Int64,
#| step? : Int64 = 1L,
#| inclusive? : Bool = false,
#|) -> Iter[Int64] {
#| until_impl(self, end, step, inclusive)
#|}
#|pub fn Double::until(
#| self : Double,
#| end : Double,
#| step? : Double = 1.0,
#| inclusive? : Bool = false,
#|) -> Iter[Double] {
#| until_impl(self, end, step, inclusive)
#|}
),
"iterator.mbt": (
#|#alias(Iterator, deprecated="The name `Iterator` is deprecated, use `Iter` instead. Note that if you have defined `iterator()` method to support `for .. in` loop, you should also rename `iterator()` to `iter()`. See https://github.com/moonbitlang/core/pull/3127 for more details.")
#|struct Iter[X] {
#| f : () -> X?
#| mut size_hint : Int?
#|}
#|priv enum IntersperseState[X] {
#| IntersperseInit
#| IntersperseElem(X)
#| IntersperseSep
#|}
#|#alias(peek, deprecated)
#|#alias(head)
#|pub fn[X] Iter::next(self : Iter[X]) -> X? {
#| let result = (self.f)()
#| match (result, self.size_hint) {
#| (Some(_), Some(n)) =>
#| self.size_hint = if n > 0 { Some(n - 1) } else { Some(0) }
#| (None, _) => self.size_hint = Some(0)
#| _ => ()
#| }
#| result
#|}
#|pub fn[X] Iter::size_hint(self : Iter[X]) -> Int? {
#| self.size_hint
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show] Show for Iter[X]
#|pub impl[X : Show] Show for Iter[X] with fn output(self, logger) {
#| logger <+ "["
#| if self.next() is Some(x) {
#| logger.write_object(x)
#| while self.next() is Some(x) {
#| logger <+ ", \{cb => cb.write_object(x)}"
#| }
#| }
#| logger <+ "]"
#|}
#|pub impl[X : ToJson] ToJson for Iter[X] with fn to_json(self) {
#| [
#| for x in self => x
#| ]
#|}
#|#locals(f)
#|pub fn[X] Iter::each(self : Iter[X], f : (X) -> Unit raise?) -> Unit raise? {
#| while self.next() is Some(x) {
#| f(x)
#| }
#|}
#|#locals(f)
#|pub fn[X] Iter::any(self : Iter[X], f : (X) -> Bool) -> Bool {
#| while self.next() is Some(x) {
#| if f(x) {
#| break true
#| }
#| } nobreak {
#| false
#| }
#|}
#|#locals(f)
#|pub fn[X] Iter::all(self : Iter[X], f : (X) -> Bool) -> Bool {
#| while self.next() is Some(x) {
#| guard f(x) else { break false }
#| } nobreak {
#| true
#| }
#|}
#|#locals(f)
#|pub fn[X] Iter::eachi(
#| self : Iter[X],
#| f : (Int, X) -> Unit raise?,
#|) -> Unit raise? {
#| let mut i = 0
#| while self.next() is Some(x) {
#| f(i, x)
#| i += 1
#| }
#|}
#|#locals(f)
#|pub fn[X, R] Iter::fold(
#| self : Iter[X],
#| init~ : R,
#| f : (R, X) -> R raise?,
#|) -> R raise? {
#| let mut acc = init
#| while self.next() is Some(x) {
#| acc = f(acc, x)
#| }
#| acc
#|}
#|#alias(length)
#|pub fn[X] Iter::count(self : Iter[X]) -> Int {
#| for _ in self; count = 0 {
#| continue count + 1
#| } nobreak {
#| count
#| }
#|}
#|#locals(f)
#|pub fn[X] Iter::count_if(self : Iter[X], f : (X) -> Bool) -> Int {
#| for x in self; count = 0 {
#| if f(x) {
#| continue count + 1
#| }
#| continue count
#| } nobreak {
#| count
#| }
#|}
#|#owned(f)
#|pub fn[X] Iter::new(f : () -> X?, size_hint? : Int) -> Iter[X] {
#| let size_hint = match size_hint {
#| Some(n) if n > 0 => Some(n)
#| Some(_) => Some(0)
#| None => None
#| }
#| { f, size_hint, }
#|}
#|pub fn[X] Iter::empty() -> Iter[X] {
#| Iter::new(() => None, size_hint=0)
#|}
#|pub fn[X] Iter::singleton(elem : X) -> Iter[X] {
#| let mut consumed = false
#| Iter::new(
#| fn() {
#| if consumed {
#| None
#| } else {
#| consumed = true
#| Some(elem)
#| }
#| },
#| size_hint=1,
#| )
#|}
#|pub fn[X] Iter::repeat(x : X) -> Iter[X] {
#| Iter::new(() => Some(x))
#|}
#|pub fn[X] Iter::filter(self : Iter[X], f : (X) -> Bool) -> Iter[X] {
#| Iter::new(fn() {
#| while self.next() is Some(x) {
#| if f(x) {
#| break Some(x)
#| }
#| } nobreak {
#| None
#| }
#| })
#|}
#|pub fn[X, Y] Iter::map(self : Iter[X], f : (X) -> Y) -> Iter[Y] {
#| {
#| f: fn() {
#| match self.next() {
#| Some(x) => Some(f(x))
#| None => None
#| }
#| },
#| size_hint: self.size_hint,
#| }
#|}
#|pub fn[X, Y] Iter::mapi(self : Iter[X], f : (Int, X) -> Y) -> Iter[Y] {
#| let mut i = 0
#| {
#| f: fn() {
#| match self.next() {
#| Some(x) => {
#| let result = f(i, x)
#| i += 1
#| Some(result)
#| }
#| None => None
#| }
#| },
#| size_hint: self.size_hint,
#| }
#|}
#|pub fn[X, Y] Iter::filter_map(self : Iter[X], f : (X) -> Y?) -> Iter[Y] {
#| Iter::new(fn() {
#| while self.next() is Some(x) {
#| guard f(x) is (Some(_) as y) else { () }
#| break y
#| } nobreak {
#| None
#| }
#| })
#|}
#|pub fn[X, Y] Iter::flat_map(self : Iter[X], f : (X) -> Iter[Y]) -> Iter[Y] {
#| let mut current_iter = Some([||])
#| Iter::new(fn() {
#| guard current_iter is Some(iter) else { None }
#| for x = iter.next() {
#| match x {
#| Some(_) as elem => break elem
#| None => {
#| guard self.next() is Some(x) else { break None }
#| let iter = f(x)
#| current_iter = Some(iter)
#| continue iter.next()
#| }
#| }
#| }
#| })
#|}
#|pub fn[X] Iter::flatten(self : Iter[Iter[X]]) -> Iter[X] {
#| self.flat_map(it => it)
#|}
#|pub fn[A : ToStringView] Iter::join(self : Iter[A], sep : StringView) -> String {
#| let result = StringBuilder()
#| if self.next() is Some(x) {
#| result.write_view(x.to_string_view())
#| while self.next() is Some(x) {
#| result.write_view(sep)
#| result.write_view(x.to_string_view())
#| }
#| }
#| result.to_string()
#|}
#|pub fn[X] Iter::tap(self : Iter[X], f : (X) -> Unit) -> Iter[X] {
#| {
#| f: fn() {
#| let result = self.next()
#| if result is Some(x) {
#| f(x)
#| }
#| result
#| },
#| size_hint: self.size_hint,
#| }
#|}
#|pub fn[X] Iter::take(self : Iter[X], n : Int) -> Iter[X] {
#| let mut remaining = n
#| let size_hint = match self.size_hint {
#| Some(_) if n <= 0 => Some(0)
#| Some(len) if n < len => Some(n)
#| Some(len) => Some(len)
#| None if n <= 0 => Some(0)
#| None => None
#| }
#| {
#| f: fn() {
#| guard remaining > 0 else { None }
#| let result = self.next()
#| if result is Some(_) {
#| remaining -= 1
#| }
#| result
#| },
#| size_hint,
#| }
#|}
#|pub fn[X] Iter::take_while(self : Iter[X], f : (X) -> Bool) -> Iter[X] {
#| let mut still_running = true
#| Iter::new(fn() {
#| guard still_running else { None }
#| let result = self.next()
#| if result is Some(x) && !f(x) {
#| still_running = false
#| None
#| } else {
#| result
#| }
#| })
#|}
#|pub fn[X, Y] Iter::map_while(self : Iter[X], f : (X) -> Y?) -> Iter[Y] {
#| let mut still_running = true
#| Iter::new(fn() {
#| guard still_running else { None }
#| let src = self.next()
#| guard src is Some(x) else { None }
#| let result = f(x)
#| if result is None {
#| still_running = false
#| }
#| result
#| })
#|}
#|pub fn[X] Iter::drop(self : Iter[X], n : Int) -> Iter[X] {
#| let mut remaining = n
#| let size_hint = match self.size_hint {
#| Some(len) if n <= 0 => Some(len)
#| Some(len) if n < len => Some(len - n)
#| Some(_) => Some(0)
#| None => None
#| }
#| {
#| f: fn() {
#| while remaining > 0 {
#| guard self.next() is Some(_) else { break None }
#| remaining -= 1
#| } nobreak {
#| self.next()
#| }
#| },
#| size_hint,
#| }
#|}
#|pub fn[X] Iter::drop_while(self : Iter[X], f : (X) -> Bool) -> Iter[X] {
#| let mut dropped = false
#| Iter::new(fn() {
#| if !dropped {
#| dropped = true
#| for x = self.next() {
#| match x {
#| Some(x) if f(x) => continue self.next()
#| result => break result
#| }
#| }
#| } else {
#| self.next()
#| }
#| })
#|}
#|pub fn[X] Iter::find_first(self : Iter[X], f : (X) -> Bool) -> X? {
#| while self.next() is Some(x) {
#| if f(x) {
#| break Some(x)
#| }
#| } nobreak {
#| None
#| }
#|}
#|pub fn[X] Iter::concat(self : Iter[X], other : Iter[X]) -> Iter[X] {
#| let mut in_first = true
#| let size_hint = match (self.size_hint, other.size_hint) {
#| (Some(n), Some(m)) => Some(n + m)
#| _ => None
#| }
#| {
#| f: fn() {
#| if in_first {
#| let result = self.next()
#| if result is None {
#| in_first = false
#| other.next()
#| } else {
#| result
#| }
#| } else {
#| other.next()
#| }
#| },
#| size_hint,
#| }
#|}
#|#alias(combine)
#|pub fn[X, Y] Iter::zip(self : Iter[X], other : Iter[Y]) -> Iter[(X, Y)] {
#| let size_hint = match (self.size_hint, other.size_hint) {
#| (Some(n), Some(m)) if n < m => Some(n)
#| (Some(_), Some(m)) | ((Some(0), _) | (_, Some(0)) with m = 0) => Some(m)
#| _ => None
#| }
#| {
#| f: fn() {
#| guard self.next() is Some(x) else { None }
#| guard other.next() is Some(y) else { None }
#| Some((x, y))
#| },
#| size_hint,
#| }
#|}
#|pub impl[T] Add for Iter[T] with fn add(self, other) {
#| self.concat(other)
#|}
#|#alias(collect)
#|pub fn[X] Iter::to_array(self : Iter[X]) -> Array[X] {
#| let result = match self.size_hint {
#| Some(n) => Array::Array(capacity=n)
#| None => []
#| }
#| while self.next() is Some(x) {
#| result.push(x)
#| }
#| result
#|}
#|#alias(iterator)
#|pub fn[X] Iter::iter(self : Iter[X]) -> Iter[X] {
#| self
#|}
#|#alias(iterator2)
#|pub fn[X] Iter::iter2(self : Iter[X]) -> Iter2[Int, X] {
#| let mut i = 0
#| Iter2({
#| f: () => {
#| guard self.next() is Some(elem) else { None }
#| let result = Some((i, elem))
#| i += 1
#| result
#| },
#| size_hint: self.size_hint,
#| })
#|}
#|pub fn[X] Iter::last(self : Iter[X]) -> X? {
#| for x = (None : X?), y = self.next() {
#| match (x, y) {
#| (last, None) => break last
#| (_, Some(_) as x) => continue x, self.next()
#| }
#| }
#|}
#|pub fn[X] Iter::intersperse(self : Iter[X], sep : X) -> Iter[X] {
#| let mut state : IntersperseState[X] = IntersperseInit
#| let size_hint = match self.size_hint {
#| Some(0) => Some(0)
#| Some(n) => Some(n * 2 - 1)
#| None => None
#| }
#| {
#| f: fn() {
#| match state {
#| IntersperseInit => {
#| let result = self.next()
#| state = IntersperseSep
#| result
#| }
#| IntersperseElem(x) => {
#| state = IntersperseSep
#| Some(x)
#| }
#| IntersperseSep =>
#| match self.next() {
#| Some(x) => {
#| state = IntersperseElem(x)
#| Some(sep)
#| }
#| None => None
#| }
#| }
#| },
#| size_hint,
#| }
#|}
#|#alias("_[_:_]")
#|#alias(view, deprecated="Use `clamped_view` instead")
#|#alias(sub, deprecated="Use `clamped_view` instead")
#|pub fn[X] Iter::clamped_view(
#| self : Iter[X],
#| start? : Int = 0,
#| end? : Int,
#|) -> Iter[X] {
#| match (start, end) {
#| (_..=0, None) => self
#| (_..=0, Some(end)) => self.take(end)
#| (start, None) => self.drop(start)
#| (start, Some(end)) => {
#| let mut index = 0
#| let size_hint = match self.size_hint {
#| Some(_) if end <= start => Some(0)
#| Some(len) if start >= len => Some(0)
#| Some(len) if end < len => Some(end - start)
#| Some(len) => Some(len - start)
#| None if end <= start => Some(0)
#| None => None
#| }
#| {
#| f: fn() {
#| if index >= end {
#| return None
#| }
#| while index < start {
#| guard self.next() is Some(_) else { return None }
#| index += 1
#| }
#| if index >= end {
#| return None
#| }
#| let result = self.next()
#| if result is Some(_) {
#| index += 1
#| }
#| result
#| },
#| size_hint,
#| }
#| }
#| }
#|}
#|pub fn[X : Eq] Iter::contains(self : Iter[X], value : X) -> Bool {
#| while self.next() is Some(x) {
#| if x == value {
#| break true
#| }
#| } nobreak {
#| false
#| }
#|}
#|pub fn[X] Iter::nth(self : Iter[X], n : Int) -> X? {
#| guard n >= 0 else { None }
#| for _ in 0.. X? {
#| guard self.next() is Some(x) else { return None }
#| let mut res = x
#| while self.next() is Some(x) {
#| if x > res {
#| res = x
#| }
#| }
#| Some(res)
#|}
#|pub fn[X : Compare] Iter::minimum(self : Iter[X]) -> X? {
#| guard self.next() is Some(x) else { return None }
#| let mut res = x
#| while self.next() is Some(x) {
#| if x < res {
#| res = x
#| }
#| }
#| Some(res)
#|}
#|#alias(Iterator2, deprecated="The name `Iterator2` is deprecated, use `Iter2` instead. Note that if you have defined `iterator2()` method to support `for .. in` loop, you should also rename `iterator2()` to `iter2()`. See https://github.com/moonbitlang/core/pull/3127 for more details.")
#|pub(all) struct Iter2[X, Y](Iter[(X, Y)])
#|#owned(f)
#|pub fn[X, Y] Iter2::new(f : () -> (X, Y)?, size_hint? : Int) -> Iter2[X, Y] {
#| let size_hint = match size_hint {
#| Some(n) if n > 0 => Some(n)
#| Some(_) => Some(0)
#| None => None
#| }
#| Iter2({ f, size_hint, })
#|}
#|#alias(iterator)
#|pub fn[X, Y] Iter2::iter(self : Iter2[X, Y]) -> Iter[(X, Y)] {
#| self.0
#|}
#|#alias(iterator2)
#|pub fn[X, Y] Iter2::iter2(self : Iter2[X, Y]) -> Iter2[X, Y] {
#| self
#|}
#|pub fn[X, Y] Iter2::next(self : Iter2[X, Y]) -> (X, Y)? {
#| self.0.next()
#|}
#|pub fn[X, Y] Iter2::each(self : Iter2[X, Y], f : (X, Y) -> Unit) -> Unit {
#| self.0.each(pair => f(pair.0, pair.1))
#|}
#|pub fn[X, Y] Iter2::concat(
#| self : Iter2[X, Y],
#| other : Iter2[X, Y],
#|) -> Iter2[X, Y] {
#| Iter2(self.0.concat(other.0))
#|}
#|pub fn[X, Y] Iter2::to_array(self : Iter2[X, Y]) -> Array[(X, Y)] {
#| self.0.to_array()
#|}
),
"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 fn equal(a, b) {
#| match (a, b) {
#| (Null, Null) | (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::empty_object() -> Json {
#| Object(Map([]))
#|}
#|#owned(repr)
#|pub fn Json::number(number : Double, repr? : String) -> Json {
#| return Number(number, repr~)
#|}
#|#owned(string)
#|pub fn Json::string(string : String) -> Json {
#| return String(string)
#|}
#|pub fn Json::boolean(boolean : Bool) -> Json {
#| if boolean {
#| True
#| } else {
#| False
#| }
#|}
#|#owned(array)
#|pub fn Json::array(array : Array[Json]) -> Json {
#| return Array(array)
#|}
#|#owned(object)
#|pub fn Json::object(object : Map[String, Json]) -> Json {
#| return Object(object)
#|}
#|pub fn[T : ToJson] Json::Json(value : T) -> Json {
#| ToJson::to_json(value)
#|}
#|pub(open) trait ToJson {
#| fn to_json(Self) -> Json
#|}
#|pub impl ToJson for Bool with fn to_json(self : Bool) -> Json {
#| if self {
#| true
#| } else {
#| false
#| }
#|}
#|pub impl ToJson for Byte with fn to_json(self : Byte) -> Json {
#| Json::number(self.to_double())
#|}
#|pub impl ToJson for Int with fn to_json(self : Int) -> Json {
#| Json::number(self.to_double())
#|}
#|pub impl ToJson for Int64 with fn to_json(self : Int64) -> Json {
#| String::to_json(self.to_string())
#|}
#|pub impl ToJson for UInt with fn to_json(self : UInt) -> Json {
#| Json::number(self.to_uint64().to_double())
#|}
#|pub impl ToJson for UInt64 with fn to_json(self : UInt64) -> Json {
#| String::to_json(self.to_string())
#|}
#|pub impl ToJson for Double with fn 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 String with fn to_json(self : String) -> Json {
#| String(self)
#|}
#|pub impl[X : ToJson] ToJson for Array[X] with fn to_json(self) {
#| Array(self.map(x => x.to_json()))
#|}
#|pub impl[X : ToJson] ToJson for FixedArray[X] with fn to_json(self) {
#| let len = self.length()
#| if len == 0 {
#| return []
#| }
#| let res = Array::unsafe_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 fn to_json(self) {
#| let len = self.length()
#| if len == 0 {
#| return []
#| }
#| let res = Array::unsafe_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 fn to_json(self) {
#| let object = Map([], 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 fn to_json(self) {
#| match self {
#| None => Null
#| Some(value) => [value]
#| }
#|}
#|pub impl[Ok : ToJson, Err : ToJson] ToJson for Result[Ok, Err] with fn to_json(
#| self : Result[Ok, Err],
#|) -> Json {
#| match self {
#| Ok(ok) => { "Ok": ok }
#| Err(err) => { "Err": err }
#| }
#|}
#|pub impl ToJson for Unit with fn to_json(_self) {
#| Null
#|}
#|pub impl Default for Json with fn default() {
#| false
#|}
),
"linked_hash_map.mbt": (
#|#unsafe_cycle_free
#|priv struct Entry[K, V] {
#| mut prev : Int
#| mut next : Entry[K, V]?
#| mut psl : Int
#| hash : Int
#| key : K
#| mut value : V
#|}
#|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
#|}
#|let default_init_capacity = 8
#|fn[K, V] new_map(capacity : Int) -> 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,
#| }
#|}
#|fn capacity_for_length(length : Int) -> Int {
#| let mut capacity = length.next_power_of_two()
#| if length > calc_grow_threshold(capacity) {
#| capacity *= 2
#| }
#| capacity
#|}
#|#alias(from_array)
#|pub fn[K : Hash + Eq, V] Map::Map(
#| arr : ArrayView[(K, V)],
#| capacity? : Int,
#|) -> Map[K, V] {
#| let length = arr.length()
#| let capacity = match capacity {
#| Some(capacity) => capacity.max(capacity_for_length(length))
#| None =>
#| if length == 0 {
#| default_init_capacity
#| } else {
#| capacity_for_length(length)
#| }
#| }
#| let m = new_map(capacity)
#| for e in arr {
#| m.set(e.0, e.1)
#| }
#| m
#|}
#|#alias("_[_]=_")
#|#owned(value)
#|pub fn[K : Hash + Eq, V] Map::set(self : Map[K, V], key : K, value : V) -> Unit {
#| self.set_with_hash(key, value, Hash::hash(key))
#|}
#|#owned(value)
#|fn[K : Eq, V] Map::set_with_hash(
#| self : Map[K, V],
#| key : K,
#| value : V,
#| hash : Int,
#|) -> Unit {
#| for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries.unsafe_get(idx) {
#| None => {
#| if self.size >= self.grow_at {
#| self.grow()
#| continue 0, hash & self.capacity_mask
#| }
#| let entry = { prev: self.tail, next: None, psl, key, value, hash, }
#| self.add_entry_to_tail(idx, entry)
#| return
#| }
#| Some(curr_entry) => {
#| if curr_entry.hash == hash && curr_entry.key == key {
#| curr_entry.value = value
#| return
#| }
#| if psl > curr_entry.psl {
#| if self.size >= self.grow_at {
#| self.grow()
#| continue 0, hash & self.capacity_mask
#| }
#| self.push_away(idx, curr_entry)
#| let entry = { prev: self.tail, next: None, psl, key, value, hash, }
#| self.add_entry_to_tail(idx, entry)
#| return
#| }
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| }
#| }
#|}
#|#owned(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.unsafe_get(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
#| }
#| }
#| }
#|}
#|#owned(entry)
#|fn[K, V] Map::set_entry(
#| self : Map[K, V],
#| entry : Entry[K, V],
#| new_idx : Int,
#|) -> Unit {
#| match entry.next {
#| None => self.tail = new_idx
#| Some(next) => next.prev = new_idx
#| }
#| self.entries.unsafe_set(new_idx, Some(entry))
#|}
#|pub fn[K : Hash + Eq, V] Map::get(self : Map[K, V], key : K) -> V? {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(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
#| }
#|}
#|#alias("_[_]")
#|pub fn[K : Hash + Eq, V] Map::at(self : Map[K, V], key : K) -> V {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard! self.entries.unsafe_get(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 = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| match self.entries.unsafe_get(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 = Hash::hash(key)
#| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash &
#| self.capacity_mask {
#| match self.entries.unsafe_get(idx) {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| return entry.value
#| }
#| if psl > entry.psl {
#| let new_value = default()
#| 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::update_or_default(
#| self : Map[K, V],
#| key : K,
#| default : V,
#| f : (V) -> V,
#|) -> Unit {
#| let hash = Hash::hash(key)
#| let (idx, psl, push_away) = for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries.unsafe_get(idx) {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| entry.value = f(entry.value)
#| return
#| }
#| if psl > entry.psl {
#| break (idx, psl, Some(entry))
#| }
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| None => break (idx, psl, None)
#| }
#| }
#| if self.size >= self.grow_at {
#| self.grow()
#| self.set_with_hash(key, default, hash)
#| } else {
#| if push_away is Some(entry) {
#| self.push_away(idx, entry)
#| }
#| let entry = { prev: self.tail, next: None, psl, hash, key, value: default, }
#| self.add_entry_to_tail(idx, entry)
#| }
#|}
#|pub fn[K : Hash + Eq, V] Map::contains(self : Map[K, V], key : K) -> Bool {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(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 = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(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, Hash::hash(key))
#|}
#|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.unsafe_get(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
#| }
#|}
#|#owned(entry)
#|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.unsafe_set(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 {
#| for cur = idx {
#| let next = (cur + 1) & self.capacity_mask
#| match self.entries.unsafe_get(next) {
#| None | Some({ psl: 0, .. }) => {
#| self.entries.unsafe_set(cur, None)
#| break
#| }
#| Some(entry) => {
#| entry.psl -= 1
#| self.set_entry(entry, cur)
#| continue next
#| }
#| }
#| }
#|}
#|fn[K, 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
#| for x = old_head {
#| match x {
#| None => break
#| Some(e) => {
#| let next_in_chain = e.next
#| e.next = None
#| self.rehash_place_entry(e)
#| continue next_in_chain
#| }
#| }
#| }
#|}
#|#owned(outer)
#|fn[K, V] Map::rehash_place_entry(self : Map[K, V], outer : Entry[K, V]) -> Unit {
#| let hash = outer.hash
#| for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries.unsafe_get(idx) {
#| None => {
#| outer.psl = psl
#| outer.prev = self.tail
#| self.add_entry_to_tail(idx, outer)
#| return
#| }
#| Some(curr) =>
#| if psl > curr.psl {
#| self.push_away(idx, curr)
#| outer.psl = psl
#| outer.prev = self.tail
#| self.add_entry_to_tail(idx, outer)
#| return
#| } else {
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| }
#| }
#|}
#|fn calc_grow_threshold(capacity : Int) -> Int {
#| capacity * 13 / 16
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[K : Show, V : Show] Show for Map[K, V]
#|pub impl[K : Show, V : Show] Show for Map[K, V] with fn output(self, logger) {
#| logger <+ "{"
#| for x = 0, y = self.head {
#| match (x, y) {
#| (_, None) => break logger <+ "}"
#| (i, Some({ key, value, next, .. })) => {
#| if i > 0 {
#| logger <+ ", "
#| }
#| logger <+
#| "\{cb => cb.write_object(key)}: \{cb => cb.write_object(value)}"
#| continue i + 1, next
#| }
#| }
#| }
#|}
#|#alias(size, deprecated)
#|pub fn[K, V] Map::length(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? {
#| for x = self.head {
#| match x {
#| 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? {
#| for x = 0, y = self.head {
#| match (x, y) {
#| (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
#|}
#|#alias(iterator, deprecated)
#|pub fn[K, V] Map::iter(self : Map[K, V]) -> Iter[(K, V)] {
#| let mut curr_entry = self.head
#| let len = self.size
#| let mut remaining = len
#| Iter::new(
#| fn() {
#| guard remaining > 0 && curr_entry is Some({ key, value, next, .. }) else {
#| None
#| }
#| curr_entry = next
#| remaining -= 1
#| Some((key, value))
#| },
#| size_hint=len,
#| )
#|}
#|#alias(iterator2, deprecated)
#|pub fn[K, V] Map::iter2(self : Map[K, V]) -> Iter2[K, V] {
#| self.iter()
#|}
#|pub fn[K, V] Map::keys(self : Map[K, V]) -> Iter[K] {
#| let mut curr_entry = self.head
#| let len = self.size
#| let mut remaining = len
#| Iter::new(
#| fn() {
#| guard remaining > 0 && curr_entry is Some({ key, next, .. }) else { None }
#| curr_entry = next
#| remaining -= 1
#| Some(key)
#| },
#| size_hint=len,
#| )
#|}
#|pub fn[K, V] Map::values(self : Map[K, V]) -> Iter[V] {
#| let mut curr_entry = self.head
#| let len = self.size
#| let mut remaining = len
#| Iter::new(
#| fn() {
#| guard remaining > 0 && curr_entry is Some({ value, next, .. }) else {
#| None
#| }
#| curr_entry = next
#| remaining -= 1
#| Some(value)
#| },
#| size_hint=len,
#| )
#|}
#|pub fn[K, V] Map::to_array(self : Map[K, V]) -> Array[(K, V)] {
#| let arr = Array::unsafe_make_uninit(self.size)
#| let mut i = 0
#| for x = self.head {
#| match x {
#| 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 fn 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 }
#| } nobreak {
#| true
#| }
#|}
#|#deprecated("Use `Map([(k, v), ...])` or `Map::from_array` instead")
#|pub fn[K : Hash + Eq, V] Map::of(arr : FixedArray[(K, V)]) -> Map[K, V] {
#| let length = arr.length()
#| let m = new_map(capacity_for_length(length))
#| for e in arr {
#| m.set(e.0, e.1)
#| }
#| m
#|}
#|#alias(from_iterator, deprecated)
#|pub fn[K : Hash + Eq, V] Map::from_iter(iter : Iter[(K, V)]) -> Map[K, V] {
#| let m = Map([])
#| while iter.next() is Some((k, v)) {
#| m.set(k, v)
#| }
#| m
#|}
#|pub impl[K, V] Default for Map[K, V] with fn default() {
#| new_map(default_init_capacity)
#|}
#|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)
#| for entry = last, idx = self.tail, next = (None : Entry[K, V2]?) {
#| let { prev, psl, hash, key, value, .. } = entry
#| 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)
#| break
#| }
#| }
#| other
#|}
#|#alias(clone, deprecated)
#|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)
#| for entry = last, idx = self.tail, next = (None : Entry[K, V]?) {
#| let { prev, psl, hash, key, value, .. } = entry
#| 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)
#| break
#| }
#| }
#| other
#|}
#|pub fn[K : Eq, V] Map::merge(self : Map[K, V], other : Map[K, V]) -> Map[K, V] {
#| let result = self.copy()
#| result.merge_in_place(other)
#| result
#|}
#|pub fn[K : Eq, V] Map::merge_in_place(
#| self : Map[K, V],
#| other : Map[K, V],
#|) -> Unit {
#| if physical_equal(self, other) {
#| return
#| }
#| for x = other.head {
#| match x {
#| Some({ key, value, next, hash, .. }) => {
#| self.set_with_hash(key, value, hash)
#| continue next
#| }
#| None => break
#| }
#| }
#|}
#|#locals(f)
#|pub fn[K, V] Map::retain(self : Map[K, V], f : (K, V) -> Bool) -> Unit {
#| for x = self.head, y = false {
#| match (x, y) {
#| (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
#| }
#| break
#| }
#| }
#| }
#|}
#|pub fn[K : Hash + Eq, V] Map::update(
#| self : Map[K, V],
#| key : K,
#| f : (V?) -> V?,
#|) -> Unit {
#| let hash = Hash::hash(key)
#| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash &
#| self.capacity_mask {
#| match self.entries.unsafe_get(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)
#| }
#|}
#|pub fn[V] Map::get_from_bytes(map : Self[Bytes, V], key : BytesView) -> V? {
#| let hash = key.hash()
#| for i = 0, idx = hash & map.capacity_mask {
#| guard map.entries.unsafe_get(idx) is Some(entry) else { break None }
#| if entry.hash == hash && key.equal_to_bytes(entry.key) {
#| break Some(entry.value)
#| }
#| if i > entry.psl {
#| break None
#| }
#| continue i + 1, (idx + 1) & map.capacity_mask
#| }
#|}
#|pub fn[V] Map::get_from_string(map : Self[String, V], key : StringView) -> V? {
#| let hash = key.hash()
#| for i = 0, idx = hash & map.capacity_mask {
#| guard map.entries.unsafe_get(idx) is Some(entry) else { break None }
#| if entry.hash == hash && key.equal_to_string(entry.key) {
#| break Some(entry.value)
#| }
#| if i > entry.psl {
#| break None
#| }
#| continue i + 1, (idx + 1) & map.capacity_mask
#| }
#|}
),
"mutarrayview.mbt": (
#|#builtin.valtype
#|type MutArrayView[T]
#|fn[T] MutArrayView::buf(self : MutArrayView[T]) -> UninitializedArray[T] = "%arrayview.buf"
#|fn[T] MutArrayView::start(self : MutArrayView[T]) -> Int = "%arrayview.start"
#|fn[T] MutArrayView::len(self : MutArrayView[T]) -> Int = "%arrayview.len"
#|fn[T] MutArrayView::make(
#| buf : UninitializedArray[T],
#| start : Int,
#| len : Int,
#|) -> MutArrayView[T] = "%arrayview.make"
#|#intrinsic("%mutarrayview.length")
#|pub fn[T] MutArrayView::length(self : MutArrayView[T]) -> Int {
#| self.len()
#|}
#|pub fn[T] MutArrayView::is_empty(self : MutArrayView[T]) -> Bool {
#| self.length() == 0
#|}
#|pub fn[T] MutArrayView::start_offset(self : MutArrayView[T]) -> Int {
#| self.start()
#|}
#|#intrinsic("%mutarrayview.get")
#|#alias("_[_]")
#|pub fn[T] MutArrayView::at(self : MutArrayView[T], index : Int) -> T {
#| guard index >= 0 && index < self.len() else {
#| index_out_of_bounds(self.len(), index)
#| }
#| self.buf().unsafe_get(self.start() + index)
#|}
#|#intrinsic("%mutarrayview.unsafe_get")
#|#internal(unsafe, "Panic if index is out of bounds")
#|pub fn[T] MutArrayView::unsafe_get(self : MutArrayView[T], index : Int) -> T {
#| self.buf()[self.start() + index]
#|}
#|#intrinsic("%mutarrayview.set")
#|#alias("_[_]=_")
#|#owned(value)
#|pub fn[T] MutArrayView::set(
#| self : MutArrayView[T],
#| index : Int,
#| value : T,
#|) -> Unit {
#| guard index >= 0 && index < self.len() else {
#| index_out_of_bounds(self.len(), index)
#| }
#| self.buf().unsafe_set(self.start() + index, value)
#|}
#|#intrinsic("%mutarrayview.unsafe_set")
#|#internal(unsafe, "Panic if index is out of bounds")
#|#owned(value)
#|pub fn[T] MutArrayView::unsafe_set(
#| self : MutArrayView[T],
#| index : Int,
#| value : T,
#|) -> Unit {
#| self.buf()[self.start() + index] = value
#|}
#|#intrinsic("%array.mut_view")
#|pub fn[T] Array::mut_view(
#| self : Array[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> MutArrayView[T] {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else {
#| abort("View index out of bounds")
#| }
#| MutArrayView::make(self.buffer(), start, end - start)
#|}
#|#intrinsic("%mutarrayview.mut_view")
#|pub fn[T] MutArrayView::mut_view(
#| self : MutArrayView[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> MutArrayView[T] {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else {
#| abort("View index out of bounds")
#| }
#| MutArrayView::make(self.buf(), self.start() + start, end - start)
#|}
#|#intrinsic("%fixedarray.mut_view")
#|pub fn[T] FixedArray::mut_view(
#| self : FixedArray[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> MutArrayView[T] {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else {
#| abort("View index out of bounds")
#| }
#| MutArrayView::make(
#| unsafe_cast_fixedarray_to_uninitializedarray(self),
#| start,
#| end - start,
#| )
#|}
#|#intrinsic("%mutarrayview.view")
#|#alias(view, deprecated="Use `exact_view` instead")
#|#alias(sub, deprecated="Use `exact_view` instead")
#|pub fn[T] MutArrayView::exact_view(
#| self : MutArrayView[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else {
#| abort("View index out of bounds")
#| }
#| ArrayView::make(self.buf(), self.start() + start, end - start)
#|}
#|#alias("_[_:_]")
#|pub fn[T] MutArrayView::clamped_view(
#| self : MutArrayView[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let len = self.length()
#| let lo = clamp_offset(start, len)
#| let hi = match end {
#| None => len
#| Some(end) => clamp_offset(end, len)
#| }
#| let count = if hi > lo { hi - lo } else { 0 }
#| ArrayView::make(self.buf(), self.start() + lo, count)
#|}
#|#alias(to_array, deprecated)
#|pub fn[T] MutArrayView::to_owned(self : MutArrayView[T]) -> Array[T] {
#| self[:].to_owned()
#|}
#|#alias(iterator, deprecated)
#|pub fn[X] MutArrayView::iter(self : MutArrayView[X]) -> Iter[X] {
#| let mut i = 0
#| let len = self.length()
#| Iter::new(
#| fn() {
#| guard i < len else { None }
#| let elem = self.unsafe_get(i)
#| i += 1
#| Some(elem)
#| },
#| size_hint=len,
#| )
#|}
#|#alias(rev_iterator, deprecated)
#|pub fn[X] MutArrayView::rev_iter(self : MutArrayView[X]) -> Iter[X] {
#| let len = self.length()
#| let mut i = len
#| Iter::new(
#| fn() {
#| guard i > 0 else { None }
#| i -= 1
#| Some(self.unsafe_get(i))
#| },
#| size_hint=len,
#| )
#|}
#|#alias(iterator2, deprecated)
#|pub fn[X] MutArrayView::iter2(self : MutArrayView[X]) -> Iter2[Int, X] {
#| let mut i = 0
#| let len = self.length()
#| Iter2::new(
#| fn() {
#| guard i < len else { None }
#| let result = Some((i, self.unsafe_get(i)))
#| i += 1
#| result
#| },
#| size_hint=len,
#| )
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show] Show for MutArrayView[X]
#|#warnings("-deprecated")
#|pub impl[X : Show] Show for MutArrayView[X] with fn output(self, logger) {
#| self[:].output(logger)
#|}
#|pub impl[T : Eq] Eq for MutArrayView[T] with fn equal(self, other) -> Bool {
#| self[:] == other
#|}
#|pub impl[T : Compare] Compare for MutArrayView[T] with fn compare(self, other) -> Int {
#| self[:].compare(other)
#|}
#|pub impl[A : Hash] Hash for MutArrayView[A] with fn hash_combine(self, hasher) {
#| self[:].hash_combine(hasher)
#|}
),
"op.mbt": (
#|#coverage.skip
#|#deprecated
#|#doc(hidden)
#|pub fn[T : Compare] op_lt(self_ : T, other : T) -> Bool {
#| Compare::op_lt(self_, other)
#|}
#|#coverage.skip
#|#deprecated
#|#doc(hidden)
#|pub fn[T : Compare] op_gt(self_ : T, other : T) -> Bool {
#| Compare::op_gt(self_, other)
#|}
#|#coverage.skip
#|#deprecated
#|#doc(hidden)
#|pub fn[T : Compare] op_le(self_ : T, other : T) -> Bool {
#| Compare::op_le(self_, other)
#|}
#|#coverage.skip
#|#deprecated
#|#doc(hidden)
#|pub fn[T : Compare] op_ge(self_ : T, other : T) -> Bool {
#| Compare::op_ge(self_, other)
#|}
#|#coverage.skip
#|pub fn[T : Eq] op_notequal(x : T, y : T) -> Bool {
#| !(x == y)
#|}
),
"operators.mbt": (
#|pub(open) trait Add {
#| fn add(Self, Self) -> Self
#|}
#|pub(open) trait Sub {
#| fn sub(Self, Self) -> Self
#|}
#|pub(open) trait Mul {
#| fn mul(Self, Self) -> Self
#|}
#|pub(open) trait Div {
#| fn div(Self, Self) -> Self
#|}
#|pub(open) trait Neg {
#| fn neg(Self) -> Self
#|}
#|pub(open) trait Mod {
#| fn mod(Self, Self) -> Self
#|}
#|pub(open) trait BitAnd {
#| fn land(Self, Self) -> Self
#|}
#|pub(open) trait BitOr {
#| fn lor(Self, Self) -> Self
#|}
#|pub(open) trait BitXOr {
#| fn lxor(Self, Self) -> Self
#|}
#|pub(open) trait Shl {
#| fn shl(Self, Int) -> Self
#|}
#|pub(open) trait Shr {
#| fn shr(Self, Int) -> Self
#|}
),
"option.mbt": (
#|pub impl[X : Eq] Eq for X? with fn equal(self, other) {
#| match (self, other) {
#| (None, None) => true
#| (Some(x), Some(y)) => x == y
#| _ => false
#| }
#|}
#|#deprecated("Option does not have a meaningful string representation")
#|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
#| }
#|}
#|#alias(or, deprecated)
#|pub fn[T] Option::unwrap_or(self : T?, default : T) -> T {
#| match self {
#| Some(t) | (None with t = default) => t
#| }
#|}
#|#alias(or_else, deprecated)
#|pub fn[T] Option::unwrap_or_else(
#| self : T?,
#| default : () -> T raise?,
#|) -> T raise? {
#| match self {
#| None => default()
#| Some(t) => t
#| }
#|}
#|#alias(or_default, deprecated)
#|pub fn[T : Default] Option::unwrap_or_default(self : T?) -> T {
#| match self {
#| Some(t) | (None with t = T::default()) => t
#| }
#|}
#|pub impl[X : Compare] Compare for X? with fn compare(self, other) {
#| match (self, other) {
#| (Some(x), Some(y)) => x.compare(y)
#| (Some(_), None) => 1
#| (None, Some(_)) => -1
#| (None, None) => 0
#| }
#|}
#|#alias(or_error, deprecated)
#|pub fn[T, Err : Error] Option::unwrap_or_error(
#| self : T?,
#| err : Err,
#|) -> T raise Err {
#| guard self is Some(v) else { raise err }
#| v
#|}
#|pub impl[X] Default for X? with fn default() {
#| None
#|}
#|#alias(iterator, deprecated)
#|pub fn[T] Option::iter(self : T?) -> Iter[T] {
#| match self {
#| Some(v) => [|v|]
#| None => [||]
#| }
#|}
#|pub fn[T, U] Option::map(self : T?, f : (T) -> U raise?) -> U? raise? {
#| match self {
#| Some(t) => Some(f(t))
#| None => None
#| }
#|}
#|pub fn[T, U] Option::map_or(
#| self : T?,
#| default : U,
#| f : (T) -> U raise?,
#|) -> U raise? {
#| match self {
#| None => default
#| Some(x) => f(x)
#| }
#|}
#|pub fn[T, U] Option::map_or_else(
#| self : T?,
#| default : () -> U raise?,
#| f : (T) -> U raise?,
#|) -> U raise? {
#| match self {
#| None => default()
#| Some(x) => f(x)
#| }
#|}
#|pub fn[T, U] Option::bind(self : T?, f : (T) -> U? raise?) -> U? raise? {
#| match self {
#| Some(t) => f(t)
#| None => None
#| }
#|}
#|#deprecated("use `option.bind(x => x)` instead")
#|pub fn[T] Option::flatten(self : T??) -> T? {
#| match self {
#| Some(inner) => inner
#| None => None
#| }
#|}
#|#deprecated("use `x is None` instead")
#|pub fn[T] Option::is_empty(self : T?) -> Bool {
#| self is None
#|}
#|pub fn[T] Option::filter(self : T?, f : (T) -> Bool raise?) -> T? raise? {
#| match self {
#| Some(t) => if f(t) { self } else { None }
#| None => None
#| }
#|}
#|#deprecated("use `x is Some(_)` instead")
#|pub fn[T] Option::is_some(self : T?) -> Bool {
#| self is Some(_)
#|}
#|#deprecated("use `x is None` instead")
#|pub fn[T] Option::is_none(self : T?) -> Bool {
#| self is None
#|}
),
"range.mbt": (
#|fn[T : Add + Compare + Default] until_impl(
#| start : T,
#| end : T,
#| step : T,
#| inclusive : Bool,
#|) -> Iter[T] {
#| let zero = Default::default()
#| if step == zero {
#| return [||]
#| }
#| let mut i = start
#| let mut done = false
#| Iter::new(() => {
#| guard !done else { None }
#| guard (step > zero && i < end) ||
#| (step < zero && i > end) ||
#| (inclusive && i == end) else {
#| None
#| }
#| let value = i
#| let next = i + step
#| if (step > zero && next >= i) || (step < zero && next <= i) {
#| i = next
#| } else {
#| done = true
#| }
#| Some(value)
#| })
#|}
),
"readonlyarray.mbt": (
#|fn[T] ReadOnlyArray::unsafe_reinterpret_to_fixed_array(
#| self : ReadOnlyArray[T],
#|) -> FixedArray[T] = "%identity"
#|fn[T] unsafe_reinterpret_from_fixed_array(
#| arr : FixedArray[T],
#|) -> ReadOnlyArray[T] = "%identity"
#|#alias("_[_]")
#|pub fn[T] ReadOnlyArray::at(self : ReadOnlyArray[T], index : Int) -> T {
#| self.unsafe_reinterpret_to_fixed_array()[index]
#|}
#|pub fn[T] ReadOnlyArray::from_array(array : ArrayView[T]) -> ReadOnlyArray[T] {
#| unsafe_reinterpret_from_fixed_array(FixedArray::from_array(array))
#|}
#|#alias(from_iterator, deprecated)
#|pub fn[T] ReadOnlyArray::from_iter(iter : Iter[T]) -> ReadOnlyArray[T] {
#| unsafe_reinterpret_from_fixed_array(FixedArray::from_iter(iter))
#|}
#|pub fn[T] ReadOnlyArray::makei(
#| length : Int,
#| value : (Int) -> T raise?,
#|) -> ReadOnlyArray[T] raise? {
#| unsafe_reinterpret_from_fixed_array(FixedArray::makei(length, value))
#|}
#|#intrinsic("%readonlyarray.get_opt")
#|pub fn[T] ReadOnlyArray::get(self : ReadOnlyArray[T], index : Int) -> T? {
#| self.unsafe_reinterpret_to_fixed_array().get(index)
#|}
#|#internal(unsafe, "Undefined behavior if index is out of bounds")
#|#doc(hidden)
#|pub fn[T] ReadOnlyArray::unsafe_get(self : ReadOnlyArray[T], index : Int) -> T {
#| self.unsafe_reinterpret_to_fixed_array().unsafe_get(index)
#|}
#|pub fn[T] ReadOnlyArray::length(self : ReadOnlyArray[T]) -> Int {
#| self.unsafe_reinterpret_to_fixed_array().length()
#|}
#|pub fn[T] ReadOnlyArray::is_empty(self : ReadOnlyArray[T]) -> Bool {
#| self.unsafe_reinterpret_to_fixed_array().is_empty()
#|}
#|pub fn[T] ReadOnlyArray::last(self : ReadOnlyArray[T]) -> T? {
#| self.unsafe_reinterpret_to_fixed_array().last()
#|}
#|#alias(iterator, deprecated)
#|pub fn[T] ReadOnlyArray::iter(self : ReadOnlyArray[T]) -> Iter[T] {
#| self.unsafe_reinterpret_to_fixed_array().iter()
#|}
#|pub fn[T] ReadOnlyArray::iter2(self : ReadOnlyArray[T]) -> Iter2[Int, T] {
#| self.unsafe_reinterpret_to_fixed_array().iter2()
#|}
#|pub fn[T] ReadOnlyArray::rev_iter(self : ReadOnlyArray[T]) -> Iter[T] {
#| self[:].rev_iter()
#|}
#|pub fn[T] ReadOnlyArray::each(
#| self : ReadOnlyArray[T],
#| f : (T) -> Unit raise?,
#|) -> Unit raise? {
#| self.unsafe_reinterpret_to_fixed_array().each(f)
#|}
#|pub fn[T] ReadOnlyArray::eachi(
#| self : ReadOnlyArray[T],
#| f : (Int, T) -> Unit raise?,
#|) -> Unit raise? {
#| self.unsafe_reinterpret_to_fixed_array().eachi(f)
#|}
#|pub fn[T] ReadOnlyArray::rev_each(
#| self : ReadOnlyArray[T],
#| f : (T) -> Unit raise?,
#|) -> Unit raise? {
#| self.unsafe_reinterpret_to_fixed_array().rev_each(f)
#|}
#|pub fn[T] ReadOnlyArray::rev_eachi(
#| self : ReadOnlyArray[T],
#| f : (Int, T) -> Unit raise?,
#|) -> Unit raise? {
#| self.unsafe_reinterpret_to_fixed_array().rev_eachi(f)
#|}
#|pub fn[T, U] ReadOnlyArray::map(
#| self : ReadOnlyArray[T],
#| f : (T) -> U raise?,
#|) -> ReadOnlyArray[U] raise? {
#| unsafe_reinterpret_from_fixed_array(
#| self.unsafe_reinterpret_to_fixed_array().map(f),
#| )
#|}
#|pub fn[T, U] ReadOnlyArray::mapi(
#| self : ReadOnlyArray[T],
#| f : (Int, T) -> U raise?,
#|) -> ReadOnlyArray[U] raise? {
#| unsafe_reinterpret_from_fixed_array(
#| self.unsafe_reinterpret_to_fixed_array().mapi(f),
#| )
#|}
#|pub fn[T] ReadOnlyArray::filter(
#| self : ReadOnlyArray[T],
#| f : (T) -> Bool raise?,
#|) -> ReadOnlyArray[T] raise? {
#| ReadOnlyArray::from_array(self[:].filter(f))
#|}
#|pub fn[A, B] ReadOnlyArray::filter_map(
#| self : ReadOnlyArray[A],
#| f : (A) -> B? raise?,
#|) -> ReadOnlyArray[B] raise? {
#| ReadOnlyArray::from_array(self[:].filter_map(f))
#|}
#|pub fn[A, B] ReadOnlyArray::fold(
#| self : ReadOnlyArray[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| self.unsafe_reinterpret_to_fixed_array().fold(init~, f)
#|}
#|pub fn[A, B] ReadOnlyArray::rev_fold(
#| self : ReadOnlyArray[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| self.unsafe_reinterpret_to_fixed_array().rev_fold(init~, f)
#|}
#|pub fn[A, B] ReadOnlyArray::foldi(
#| self : ReadOnlyArray[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| self.unsafe_reinterpret_to_fixed_array().foldi(init~, f)
#|}
#|pub fn[A, B] ReadOnlyArray::rev_foldi(
#| self : ReadOnlyArray[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| self.unsafe_reinterpret_to_fixed_array().rev_foldi(init~, f)
#|}
#|pub fn[T] ReadOnlyArray::rev(self : ReadOnlyArray[T]) -> ReadOnlyArray[T] {
#| unsafe_reinterpret_from_fixed_array(
#| self.unsafe_reinterpret_to_fixed_array().rev(),
#| )
#|}
#|pub fn[T : Eq] ReadOnlyArray::search(
#| self : ReadOnlyArray[T],
#| value : T,
#|) -> Int? {
#| self.unsafe_reinterpret_to_fixed_array().search(value)
#|}
#|pub fn[T] ReadOnlyArray::search_by(
#| self : ReadOnlyArray[T],
#| f : (T) -> Bool raise?,
#|) -> Int? raise? {
#| self[:].search_by(f)
#|}
#|pub fn[T : Eq] ReadOnlyArray::contains(
#| self : ReadOnlyArray[T],
#| value : T,
#|) -> Bool {
#| self.unsafe_reinterpret_to_fixed_array().contains(value)
#|}
#|pub fn[T : Compare] ReadOnlyArray::is_sorted(self : ReadOnlyArray[T]) -> Bool {
#| self.unsafe_reinterpret_to_fixed_array().is_sorted()
#|}
#|pub fn[T : Eq] ReadOnlyArray::starts_with(
#| self : ReadOnlyArray[T],
#| prefix : ArrayView[T],
#|) -> Bool {
#| self[:].starts_with(prefix)
#|}
#|pub fn[T : Eq] ReadOnlyArray::ends_with(
#| self : ReadOnlyArray[T],
#| suffix : ArrayView[T],
#|) -> Bool {
#| self[:].ends_with(suffix)
#|}
#|pub fn[T : Eq] ReadOnlyArray::strip_prefix(
#| self : ReadOnlyArray[T],
#| prefix : ArrayView[T],
#|) -> ArrayView[T]? {
#| self[:].strip_prefix(prefix)
#|}
#|pub fn[T : Eq] ReadOnlyArray::strip_suffix(
#| self : ReadOnlyArray[T],
#| suffix : ArrayView[T],
#|) -> ArrayView[T]? {
#| self[:].strip_suffix(suffix)
#|}
#|#alias(every)
#|pub fn[T] ReadOnlyArray::all(
#| self : ReadOnlyArray[T],
#| f : (T) -> Bool raise?,
#|) -> Bool raise? {
#| self.unsafe_reinterpret_to_fixed_array().all(f)
#|}
#|#alias(exists)
#|pub fn[T] ReadOnlyArray::any(
#| self : ReadOnlyArray[T],
#| f : (T) -> Bool raise?,
#|) -> Bool raise? {
#| self.unsafe_reinterpret_to_fixed_array().any(f)
#|}
#|pub fn[T : Compare] ReadOnlyArray::binary_search(
#| self : ReadOnlyArray[T],
#| value : T,
#|) -> Result[Int, Int] {
#| self.unsafe_reinterpret_to_fixed_array().binary_search(value)
#|}
#|pub fn[T] ReadOnlyArray::binary_search_by(
#| self : ReadOnlyArray[T],
#| cmp : (T) -> Int raise?,
#|) -> Result[Int, Int] raise? {
#| self.unsafe_reinterpret_to_fixed_array().binary_search_by(cmp)
#|}
#|pub fn[T] ReadOnlyArray::chunks(
#| self : ReadOnlyArray[T],
#| size : Int,
#|) -> Array[ArrayView[T]] {
#| self[:].chunks(size)
#|}
#|pub fn[T] ReadOnlyArray::windows(
#| self : ReadOnlyArray[T],
#| size : Int,
#|) -> Array[ArrayView[T]] {
#| self[:].windows(size)
#|}
#|pub fn[T] ReadOnlyArray::chunk_by(
#| self : ReadOnlyArray[T],
#| pred : (T, T) -> Bool raise?,
#|) -> Array[ArrayView[T]] raise? {
#| self[:].chunk_by(pred)
#|}
#|pub fn[T] ReadOnlyArray::suffixes(
#| self : ReadOnlyArray[T],
#| include_empty? : Bool = false,
#|) -> Iter[ArrayView[T]] {
#| self[:].suffixes(include_empty~)
#|}
#|pub fn[T : Compare] ReadOnlyArray::lexical_compare(
#| self : ReadOnlyArray[T],
#| other : ReadOnlyArray[T],
#|) -> Int {
#| self[:].lexical_compare(other)
#|}
#|#intrinsic("%readonlyarray.view")
#|#alias(view, deprecated="Use `exact_view` instead")
#|#alias(sub, deprecated="Use `exact_view` instead")
#|pub fn[T] ReadOnlyArray::exact_view(
#| self : ReadOnlyArray[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let fixed = self.unsafe_reinterpret_to_fixed_array()
#| match end {
#| None => fixed.exact_view(start~)
#| Some(end) => fixed.exact_view(start~, end~)
#| }
#|}
#|pub fn[T] ReadOnlyArray::get_view(
#| self : ReadOnlyArray[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T]? {
#| let fixed = self.unsafe_reinterpret_to_fixed_array()
#| match end {
#| None => fixed.get_view(start~)
#| Some(end) => fixed.get_view(start~, end~)
#| }
#|}
#|#alias("_[_:_]")
#|pub fn[T] ReadOnlyArray::clamped_view(
#| self : ReadOnlyArray[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let fixed = self.unsafe_reinterpret_to_fixed_array()
#| match end {
#| None => fixed.clamped_view(start~)
#| Some(end) => fixed.clamped_view(start~, end~)
#| }
#|}
#|pub fn[A : ToStringView] ReadOnlyArray::join(
#| self : ReadOnlyArray[A],
#| separator : StringView,
#|) -> String {
#| self[:].join(separator)
#|}
#|pub impl[T] Default for ReadOnlyArray[T] with fn default() {
#| unsafe_reinterpret_from_fixed_array(([] : FixedArray[_]))
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[T : Show] Show for ReadOnlyArray[T]
#|#warnings("-deprecated")
#|pub impl[T : Show] Show for ReadOnlyArray[T] with fn output(self, logger) {
#| self.unsafe_reinterpret_to_fixed_array().output(logger)
#|}
#|pub impl[T : ToJson] ToJson for ReadOnlyArray[T] with fn to_json(self) {
#| self.unsafe_reinterpret_to_fixed_array().to_json()
#|}
#|pub impl[T : Eq] Eq for ReadOnlyArray[T] with fn equal(self, other) {
#| self
#| .unsafe_reinterpret_to_fixed_array()
#| .equal(other.unsafe_reinterpret_to_fixed_array())
#|}
#|pub impl[T : Hash] Hash for ReadOnlyArray[T] with fn hash_combine(self, hasher) {
#| self.unsafe_reinterpret_to_fixed_array().hash_combine(hasher)
#|}
#|pub impl[T : Compare] Compare for ReadOnlyArray[T] with fn compare(self, other) {
#| self
#| .unsafe_reinterpret_to_fixed_array()
#| .compare(other.unsafe_reinterpret_to_fixed_array())
#|}
),
"result.mbt": (
#|pub fn[T, E, U] Result::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_true(y == Ok(42))
#| assert_true(w == Err(3))
#|}
#|pub fn[T, E, F] Result::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_true(y == Err("error!"))
#| assert_true(w == Ok(6))
#|}
#|#alias(or)
#|pub fn[T, E] Result::unwrap_or(self : Result[T, E], default : T) -> T {
#| match self {
#| Ok(value) | (Err(_) with value = default) => value
#| }
#|}
#|test "unwrap_or" {
#| let x : Result[Int, String] = Ok(3)
#| let y : Result[Int, String] = Err("error")
#| assert_true(x.unwrap_or(5) == 3)
#| assert_true(y.unwrap_or(5) == 5)
#|}
#|#alias(or_else)
#|pub fn[T, E] Result::unwrap_or_else(
#| self : Result[T, E],
#| default : () -> T raise?,
#|) -> T raise? {
#| match self {
#| Ok(value) => value
#| Err(_) => default()
#| }
#|}
#|test "unwrap_or_else" {
#| let x : Result[Int, String] = Ok(3)
#| let y : Result[Int, String] = Err("error")
#| assert_true(x.unwrap_or_else(() => 5) == 3)
#| assert_true(y.unwrap_or_else(() => 5) == 5)
#|}
#|pub fn[T, E] Result::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_true(y == Ok(6))
#| assert_true(w == Err("error"))
#|}
#|pub fn[T, E, U] Result::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_true(y == Ok(42))
#|}
#|pub fn[T, E] Result::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_true(z == Some(6))
#| assert_true(w == None)
#|}
#|pub impl[T : Compare, E : Compare] Compare for Result[T, E] with fn 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_true(0 == ok1.compare(ok1))
#| assert_true(0 == err2.compare(Err(2)))
#| assert_true(-1 == ok1.compare(ok2))
#| assert_true(1 == ok2.compare(ok1))
#| assert_true(-1 == err1.compare(err2))
#| assert_true(1 == err2.compare(err1))
#| assert_true(-1 == ok2.compare(err1))
#| assert_true(1 == err1.compare(ok2))
#|}
#|pub fn[T, E] Result::unwrap(self : Result[T, E]) -> T {
#| match self {
#| Ok(x) => x
#| Err(_) => abort("called `Result::unwrap()` on an `Err` value")
#| }
#|}
#|pub fn[T, E] Result::unwrap_err(self : Result[T, E]) -> E {
#| match self {
#| Ok(_) => abort("called `Result::unwrap_err()` on an `Ok` value")
#| Err(e) => e
#| }
#|}
#|#warnings("-deprecated")
#|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 : Default, E] Result::unwrap_or_default(self : Result[T, E]) -> T {
#| match self {
#| Ok(value) | (Err(_) with value = T::default()) => value
#| }
#|}
#|test "unwrap_or_default" {
#| let x : Result[Int, String] = Ok(3)
#| let y : Result[Int, String] = Err("error")
#| assert_true(x.unwrap_or_default() == 3)
#| assert_true(y.unwrap_or_default() == 0)
#|}
#|pub fn[T, E : Error] Result::unwrap_or_error(self : Result[T, E]) -> T raise E {
#| match self {
#| Ok(x) => x
#| Err(e) => raise e
#| }
#|}
#|test "unwrap exn" {
#| let result = try
#| (Err(Failure("This is serious")) : Result[Unit, Failure]).unwrap_or_error()
#| |> Ok
#| catch {
#| Failure(msg) => Err(msg)
#| }
#| assert_true(result == Err("This is serious"))
#|}
#|pub impl[T : Eq, E : Eq] Eq for Result[T, E] with fn 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 fn output(_self, logger) {
#| logger.write_string("()")
#|}
#|pub impl Show for Unit with fn to_string(_self) {
#| "()"
#|}
#|pub impl Show for Bool with fn to_string(self) {
#| if self {
#| "true"
#| } else {
#| "false"
#| }
#|}
#|pub impl Show for Int with fn to_string(self) {
#| Int::to_string(self)
#|}
#|pub impl Show for Int64 with fn to_string(self) {
#| Int64::to_string(self)
#|}
#|pub impl Show for UInt with fn to_string(self) {
#| UInt::to_string(self)
#|}
#|pub impl Show for UInt64 with fn to_string(self) {
#| UInt64::to_string(self)
#|}
#|pub impl Show for Byte with fn to_string(self) {
#| Byte::to_string(self)
#|}
#|pub impl Show for UInt16 with fn to_string(self) {
#| UInt16::to_string(self)
#|}
#|pub fn Byte::to_hex(b : Byte) -> String {
#| fn to_hex_digit(i : Byte) -> Char {
#| if i < 10 {
#| (i + b'0').to_char()
#| } else {
#| (i + b'a' - 10).to_char()
#| }
#| }
#| [to_hex_digit(b / 16), to_hex_digit(b % 16)]
#|}
#|test "to_hex_digit" {
#| inspect(Byte::to_hex(b'\xee'), content="ee")
#| inspect(Byte::to_hex(b'\xf3'), content="f3")
#|}
#|pub fn String::escape(self : String, quote? : Bool = true) -> String {
#| let buf = StringBuilder()
#| self[:].escape_to(buf, quote~)
#| buf.to_string()
#|}
#|pub fn StringView::escape(
#| self : StringView,
#| quote? : Bool = true,
#|) -> StringView {
#| let buf = StringBuilder()
#| self.escape_to(buf, quote~)
#| buf.to_string()
#|}
#|fn StringView::escape_to(
#| self : StringView,
#| logger : &Logger,
#| quote? : Bool = true,
#|) -> Unit {
#| if quote {
#| logger.write_char('"')
#| }
#| let len = self.length()
#| fn flush_segment(seg : Int, i : Int) {
#| if i > seg {
#| logger.write_view(self[seg:i])
#| }
#| }
#| for i = 0, seg = 0 {
#| if i >= len {
#| flush_segment(seg, i)
#| break
#| }
#| let code = self.unsafe_get(i)
#| match code {
#| '"' | '\\' as c => {
#| flush_segment(seg, i)
#| logger.write_char('\\')
#| logger.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 <+ "\\u{\{cb => cb.write_string(code.to_byte().to_hex())}}"
#| continue i + 1, i + 1
#| } else {
#| continue i + 1, seg
#| }
#| }
#| }
#| if quote {
#| logger.write_char('"')
#| }
#|}
#|pub impl Show for String with fn to_string(self) {
#| self
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show] Show for X?
#|pub impl[X : Show] Show for X? with fn output(self, logger) {
#| match self {
#| None => logger.write_string("None")
#| Some(arg) =>
#| logger <+
#| $|Some(\{arg})
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[T : Show, E : Show] Show for Result[T, E]
#|pub impl[T : Show, E : Show] Show for Result[T, E] with fn output(self, logger) {
#| match self {
#| Ok(x) =>
#| logger <+
#| $|Ok(\{x})
#| Err(e) =>
#| logger <+
#| $|Err(\{e})
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show] Show for FixedArray[X]
#|pub impl[X : Show] Show for FixedArray[X] with fn output(self, logger) {
#| logger.write_iter(self.iter())
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show] Show for Array[X]
#|pub impl[X : Show] Show for Array[X] with fn output(self, logger) {
#| logger.write_iter(self.iter())
#|}
),
"simd.mbt": (
#|fn v128_make(lo : UInt64, hi : UInt64) -> V128 = "%v128.make"
#|#cfg(any(target="native", target="wasm"))
#|fn v128_lo(value : V128) -> UInt64 = "%v128.lo"
#|#cfg(any(target="native", target="wasm"))
#|fn v128_hi(value : V128) -> UInt64 = "%v128.hi"
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.i8x16_splat")
#|fn i8x16_splat(value : Byte) -> V128 {
#| let lane = value.to_uint64() * (0x0101010101010101 : UInt64)
#| v128_make(lane, lane)
#|}
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.i16x8_splat")
#|fn i16x8_splat(value : UInt16) -> V128 {
#| let lane = value.to_uint64() * (0x0001000100010001 : UInt64)
#| v128_make(lane, lane)
#|}
#|#borrow(bytes)
#|#intrinsic("%v128.v128_load")
#|fn v128_load(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| v128_make(
#| fixedarray_read_uint64_le(bytes, offset),
#| fixedarray_read_uint64_le(bytes, offset + 8),
#| )
#|}
#|#borrow(str)
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.v128_load_i16x8")
#|fn v128_load_i16x8(str : String, offset : Int) -> V128 {
#| let lo = for i in 0..<4; word = (0 : UInt64) {
#| continue word | (str.unsafe_get(offset + i).to_uint64() << (16 * i))
#| } nobreak {
#| word
#| }
#| let hi = for i in 0..<4; word = (0 : UInt64) {
#| continue word | (str.unsafe_get(offset + 4 + i).to_uint64() << (16 * i))
#| } nobreak {
#| word
#| }
#| v128_make(lo, hi)
#|}
#|#borrow(data)
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.v128_load_i16x8")
#|fn v128_load_fixedarray_i16x8(data : FixedArray[UInt16], offset : Int) -> V128 {
#| let lo = for i in 0..<4; word = (0 : UInt64) {
#| continue word | (data.unsafe_get(offset + i).to_uint64() << (16 * i))
#| } nobreak {
#| word
#| }
#| let hi = for i in 0..<4; word = (0 : UInt64) {
#| continue word | (data.unsafe_get(offset + 4 + i).to_uint64() << (16 * i))
#| } nobreak {
#| word
#| }
#| v128_make(lo, hi)
#|}
#|#borrow(data)
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.v128_store_i16x8")
#|fn v128_store_i16x8(
#| data : FixedArray[UInt16],
#| offset : Int,
#| value : V128,
#|) -> Unit {
#| for i in 0..<4 {
#| data.unsafe_set(offset + i, (v128_lo(value) >> (16 * i)).to_uint16())
#| }
#| for i in 0..<4 {
#| data.unsafe_set(offset + 4 + i, (v128_hi(value) >> (16 * i)).to_uint16())
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.v128_and")
#|fn v128_and(a : V128, b : V128) -> V128 {
#| v128_make(v128_lo(a) & v128_lo(b), v128_hi(a) & v128_hi(b))
#|}
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.v128_or")
#|fn v128_or(a : V128, b : V128) -> V128 {
#| v128_make(v128_lo(a) | v128_lo(b), v128_hi(a) | v128_hi(b))
#|}
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.v128_any_true")
#|fn v128_any_true(value : V128) -> Bool {
#| v128_lo(value) != 0 || v128_hi(value) != 0
#|}
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.i16x8_add")
#|fn i16x8_add(a : V128, b : V128) -> V128 {
#| v128_make(
#| u64_u16x4_add(v128_lo(a), v128_lo(b)),
#| u64_u16x4_add(v128_hi(a), v128_hi(b)),
#| )
#|}
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.i16x8_sub")
#|fn i16x8_sub(a : V128, b : V128) -> V128 {
#| v128_make(
#| u64_u16x4_sub(v128_lo(a), v128_lo(b)),
#| u64_u16x4_sub(v128_hi(a), v128_hi(b)),
#| )
#|}
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.i16x8_le_u")
#|fn i16x8_le_u(a : V128, b : V128) -> V128 {
#| v128_make(
#| u64_u16x4_le_mask(v128_lo(a), v128_lo(b)),
#| u64_u16x4_le_mask(v128_hi(a), v128_hi(b)),
#| )
#|}
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.i8x16_eq")
#|fn i8x16_eq(a : V128, b : V128) -> V128 {
#| v128_make(
#| u64_byte_eq_mask(v128_lo(a), v128_lo(b)),
#| u64_byte_eq_mask(v128_hi(a), v128_hi(b)),
#| )
#|}
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.i16x8_eq")
#|fn i16x8_eq(a : V128, b : V128) -> V128 {
#| v128_make(
#| u64_u16_eq_mask(v128_lo(a), v128_lo(b)),
#| u64_u16_eq_mask(v128_hi(a), v128_hi(b)),
#| )
#|}
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.i8x16_bitmask")
#|fn i8x16_bitmask(value : V128) -> Int {
#| u64_high_bits(v128_lo(value)) | (u64_high_bits(v128_hi(value)) << 8)
#|}
#|#cfg(any(target="native", target="wasm"))
#|#intrinsic("%v128.i16x8_bitmask")
#|fn i16x8_bitmask(value : V128) -> Int {
#| u64_u16_high_bits(v128_lo(value)) | (u64_u16_high_bits(v128_hi(value)) << 4)
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn u64_byte_eq_mask(a : UInt64, b : UInt64) -> UInt64 {
#| for i in 0..<8; result = (0 : UInt64) {
#| let shift = 8 * i
#| let mask = if ((a >> shift) & 0xFF) == ((b >> shift) & 0xFF) {
#| (0xFF : UInt64)
#| } else {
#| 0
#| }
#| continue result | (mask << shift)
#| } nobreak {
#| result
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn u64_u16_eq_mask(a : UInt64, b : UInt64) -> UInt64 {
#| for i in 0..<4; result = (0 : UInt64) {
#| let shift = 16 * i
#| let mask = if ((a >> shift) & 0xFFFF) == ((b >> shift) & 0xFFFF) {
#| (0xFFFF : UInt64)
#| } else {
#| 0
#| }
#| continue result | (mask << shift)
#| } nobreak {
#| result
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn u64_u16x4_add(a : UInt64, b : UInt64) -> UInt64 {
#| for i in 0..<4; result = (0 : UInt64) {
#| let shift = 16 * i
#| let lane = (a >> shift).to_uint16() + (b >> shift).to_uint16()
#| continue result | (lane.to_uint64() << shift)
#| } nobreak {
#| result
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn u64_u16x4_sub(a : UInt64, b : UInt64) -> UInt64 {
#| for i in 0..<4; result = (0 : UInt64) {
#| let shift = 16 * i
#| let lane = (a >> shift).to_uint16() - (b >> shift).to_uint16()
#| continue result | (lane.to_uint64() << shift)
#| } nobreak {
#| result
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn u64_u16x4_le_mask(a : UInt64, b : UInt64) -> UInt64 {
#| for i in 0..<4; result = (0 : UInt64) {
#| let shift = 16 * i
#| let mask = if (a >> shift).to_uint16() <= (b >> shift).to_uint16() {
#| (0xFFFF : UInt64)
#| } else {
#| 0
#| }
#| continue result | (mask << shift)
#| } nobreak {
#| result
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn u64_high_bits(value : UInt64) -> Int {
#| for i in 0..<8; result = 0 {
#| let bit = ((value >> (8 * i + 7)) & 1).to_int()
#| continue result | (bit << i)
#| } nobreak {
#| result
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn u64_u16_high_bits(value : UInt64) -> Int {
#| for i in 0..<4; result = 0 {
#| let bit = ((value >> (16 * i + 15)) & 1).to_int()
#| continue result | (bit << i)
#| } nobreak {
#| result
#| }
#|}
),
"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(size_hint=2 * length)
#| for _ in 0.. Char {
#| ((leading - 0xD800) * 0x400 + trailing - 0xDC00 + 0x10000).unsafe_to_char()
#|}
#|#alias(codepoint_length, deprecated)
#|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_get(utf16_index)
#| if c1.is_leading_surrogate() && utf16_index + 1 < end_offset {
#| let c2 = self.unsafe_get(utf16_index + 1)
#| if c2.is_trailing_surrogate() {
#| continue utf16_index + 2, char_count + 1
#| } else {
#| abort("invalid surrogate pair")
#| }
#| }
#| } nobreak {
#| char_count
#| }
#|}
#|#intrinsic("%string.substring")
#|pub fn String::unsafe_substring(
#| str : String,
#| start~ : Int,
#| end~ : Int,
#|) -> String {
#| if start == 0 && end == str.length() {
#| return str
#| }
#| let len = end - start
#| let bytes = FixedArray::make(len * 2, b'\x00')
#| bytes.blit_from_string(0, str, start, len)
#| bytes.unsafe_reinterpret_as_bytes().to_unchecked_string()
#|}
#|#borrow(self, other)
#|#intrinsic("%string.unsafe_range_equal")
#|fn String::unsafe_range_equal(
#| self : String,
#| self_off~ : Int,
#| other : String,
#| other_off~ : Int,
#| len~ : Int,
#|) -> Bool {
#| for i in 0.. String {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard! start >= 0 && start <= end && end <= len
#| self.unsafe_substring(start~, end~)
#|}
#|pub fn String::suffixes(
#| self : String,
#| include_empty? : Bool = false,
#|) -> Iter[StringView] {
#| self[:].suffixes(include_empty~)
#|}
#|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))
#|}
#|pub impl Compare for String with fn compare(self, other) {
#| let len = self.length()
#| match len.compare(other.length()) {
#| 0 => {
#| for i in 0.. order
#| }
#|}
#|pub impl Default for String with fn default() {
#| ""
#|}
#|#deprecated("Check `@encoding/utf8.encode`")
#|pub fn String::to_bytes(self : String) -> Bytes {
#| let array = FixedArray::make(self.length() * 2, b'\x00')
#| array.blit_from_string(0, self, 0, self.length())
#| array |> unsafe_to_bytes
#|}
#|fn unsafe_to_bytes(array : FixedArray[Byte]) -> Bytes = "%identity"
#|pub fn String::to_array(self : String) -> Array[Char] {
#| self
#| .iter()
#| .fold(init=Array(capacity=self.length()), (rv, c) => {
#| rv.push(c)
#| rv
#| })
#|}
#|#intrinsic("%string.code_units")
#|pub fn String::code_units(self : String) -> ArrayView[UInt16] {
#| FixedArray::makei(self.length(), i => self.unsafe_get(i))
#|}
#|#alias(iterator, deprecated)
#|pub fn String::iter(self : String) -> Iter[Char] {
#| let len = self.length()
#| let mut index = 0
#| Iter::new(fn() {
#| guard index < len else { None }
#| let c1 = self.unsafe_get(index)
#| if c1.is_leading_surrogate() && index + 1 < len {
#| let c2 = self.unsafe_get(index + 1)
#| if c2.is_trailing_surrogate() {
#| let c = code_point_of_surrogate_pair(c1.to_int(), c2.to_int())
#| index += 2
#| return Some(c)
#| }
#| }
#| index += 1
#| Some(c1.unsafe_to_char())
#| })
#|}
#|#alias(iterator2, deprecated)
#|pub fn String::iter2(self : String) -> Iter2[Int, Char] {
#| self.iter().iter2()
#|}
#|#locals(f)
#|#alias(every)
#|pub fn String::all(self : String, f : (Char) -> Bool raise?) -> Bool raise? {
#| for c in self {
#| if !f(c) {
#| return false
#| }
#| }
#| true
#|}
#|#locals(f)
#|#alias(exists)
#|pub fn String::any(self : String, f : (Char) -> Bool raise?) -> Bool raise? {
#| for c in self {
#| if f(c) {
#| return true
#| }
#| }
#| false
#|}
#|#alias(rev_iterator, deprecated)
#|pub fn String::rev_iter(self : String) -> Iter[Char] {
#| self[:].rev_iter()
#|}
#|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 (utf16_offset, char_count) = for utf16_offset = start_offset, char_count = 0; utf16_offset <
#| end_offset &&
#| char_count < n; {
#| let c = self.unsafe_get(utf16_offset)
#| if c.is_leading_surrogate() {
#| continue utf16_offset + 2, char_count + 1
#| } else {
#| continue utf16_offset + 1, char_count + 1
#| }
#| } nobreak {
#| (utf16_offset, char_count)
#| }
#| 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 (utf16_offset, char_count) = for utf16_offset = end_offset, char_count = 0; utf16_offset -
#| 1 >=
#| start_offset &&
#| char_count < n; {
#| let c = self.unsafe_get(utf16_offset - 1)
#| if c.is_trailing_surrogate() {
#| continue utf16_offset - 2, char_count + 1
#| } else {
#| continue utf16_offset - 1, char_count + 1
#| }
#| } nobreak {
#| (utf16_offset, char_count)
#| }
#| 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_get(index)
#| if c1.is_leading_surrogate() && index + 1 < end_offset {
#| let c2 = self.unsafe_get(index + 1)
#| if c2.is_trailing_surrogate() {
#| continue index + 2, count + 1
#| } else {
#| abort("invalid surrogate pair")
#| }
#| }
#| } nobreak {
#| 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_get(index)
#| if c1.is_leading_surrogate() && index + 1 < end_offset {
#| let c2 = self.unsafe_get(index + 1)
#| if c2.is_trailing_surrogate() {
#| continue index + 2, count + 1
#| } else {
#| abort("invalid surrogate pair")
#| }
#| }
#| } nobreak {
#| count >= len
#| }
#|}
#|pub fn String::lexical_compare(self : String, other : String) -> Int {
#| self[:].lexical_compare(other)
#|}
#|pub fn String::compare_ignore_ascii_case(self : String, other : String) -> Int {
#| self[:].compare_ignore_ascii_case(other)
#|}
#|pub fn String::equal_ignore_ascii_case(self : String, other : String) -> Bool {
#| self[:].equal_ignore_ascii_case(other)
#|}
#|pub fn String::from_array(chars : ArrayView[Char]) -> String {
#| let buf = StringBuilder(size_hint=chars.length() * 4)
#| for c in chars {
#| buf.write_char(c)
#| }
#| buf.to_string()
#|}
#|#alias(from_iterator, deprecated)
#|pub fn String::from_iter(iter : Iter[Char]) -> String {
#| let buf = StringBuilder()
#| for c in iter {
#| buf.write_char(c)
#| }
#| buf.to_string()
#|}
),
"string_find_code_unit.mbt": (
#|fn find_code_unit_from_view(
#| target : StringView,
#| start : Int,
#| end : Int,
#| code : UInt16,
#|) -> Int {
#| let target_start = target.start_offset()
#| let found = find_code_unit_from_string(
#| target.data(),
#| target_start + start,
#| target_start + end,
#| code,
#| )
#| if found < 0 {
#| -1
#| } else {
#| found - target_start
#| }
#|}
#|fn rev_find_code_unit_from_view(
#| target : StringView,
#| start : Int,
#| end : Int,
#| code : UInt16,
#|) -> Int {
#| let target_start = target.start_offset()
#| let found = rev_find_code_unit_from_string(
#| target.data(),
#| target_start + start,
#| target_start + end,
#| code,
#| )
#| if found < 0 {
#| -1
#| } else {
#| found - target_start
#| }
#|}
#|#inline
#|fn find_code_unit_scalar(
#| data : String,
#| start : Int,
#| end : Int,
#| code : UInt16,
#|) -> Int {
#| for pos in start.. Int {
#| for pos = end - 1; pos >= start; {
#| if data.unsafe_get(pos) == code {
#| break pos
#| }
#| continue pos - 1
#| } nobreak {
#| -1
#| }
#|}
#|#cfg(not(any(target="native", target="wasm")))
#|fn find_code_unit_from_string(
#| data : String,
#| start : Int,
#| end : Int,
#| code : UInt16,
#|) -> Int {
#| find_code_unit_scalar(data, start, end, code)
#|}
#|#cfg(not(any(target="native", target="wasm")))
#|fn rev_find_code_unit_from_string(
#| data : String,
#| start : Int,
#| end : Int,
#| code : UInt16,
#|) -> Int {
#| rev_find_code_unit_scalar(data, start, end, code)
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn find_code_unit_from_string(
#| data : String,
#| start : Int,
#| end : Int,
#| code : UInt16,
#|) -> Int {
#| guard start < end else { return -1 }
#| if data.unsafe_get(start) == code {
#| return start
#| }
#| let code_v = i16x8_splat(code)
#| let tail_start = for pos = start; pos + 8 <= end; {
#| let mask = i16x8_bitmask(i16x8_eq(v128_load_i16x8(data, pos), code_v))
#| if mask != 0 {
#| return pos + mask.ctz()
#| }
#| continue pos + 8
#| } nobreak {
#| pos
#| }
#| find_code_unit_scalar(data, tail_start, end, code)
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn rev_find_code_unit_from_string(
#| data : String,
#| start : Int,
#| end : Int,
#| code : UInt16,
#|) -> Int {
#| guard start < end else { return -1 }
#| if data.unsafe_get(end - 1) == code {
#| return end - 1
#| }
#| let code_v = i16x8_splat(code)
#| let head_end = for pos = end; pos - 8 >= start; {
#| let chunk_start = pos - 8
#| let mask = i16x8_bitmask(
#| i16x8_eq(v128_load_i16x8(data, chunk_start), code_v),
#| )
#| if mask != 0 {
#| return chunk_start + 31 - mask.clz()
#| }
#| continue chunk_start
#| } nobreak {
#| pos
#| }
#| rev_find_code_unit_scalar(data, start, head_end, code)
#|}
#|fn find_by_two_anchors(target : StringView, pattern : StringView) -> Int? {
#| let target_len = target.length()
#| let pattern_len = pattern.length()
#| let target_start = target.start_offset()
#| let pattern_start = pattern.start_offset()
#| let last_offset = pattern_len - 1
#| let candidate_end = target_start + target_len - pattern_len + 1
#| let first = pattern.unsafe_get(0)
#| let last = pattern.unsafe_get(last_offset)
#| let middle_len = last_offset - 1
#| for pos = target_start, failures = 0; pos < candidate_end; {
#| let found = find_two_anchor_candidate_from_string(
#| target.data(),
#| pos,
#| candidate_end,
#| first,
#| last_offset,
#| last,
#| )
#| if found < 0 {
#| break None
#| }
#| if string_ranges_equal(
#| target.data(),
#| found + 1,
#| pattern.data(),
#| pattern_start + 1,
#| middle_len,
#| ) {
#| break Some(found - target_start)
#| }
#| let failures = failures + 1
#| let scanned = found - target_start
#| if two_anchor_should_fallback(failures, scanned) {
#| break find_pattern_kmp_from(target, pattern, scanned + 1)
#| }
#| continue found + 1, failures
#| } nobreak {
#| None
#| }
#|}
#|fn rev_find_by_two_anchors(target : StringView, pattern : StringView) -> Int? {
#| let target_len = target.length()
#| let pattern_len = pattern.length()
#| let target_start = target.start_offset()
#| let pattern_start = pattern.start_offset()
#| let last_offset = pattern_len - 1
#| let first = pattern.unsafe_get(0)
#| let last = pattern.unsafe_get(last_offset)
#| let middle_len = last_offset - 1
#| let last_candidate = target_len - pattern_len
#| for candidate_end = target_start + last_candidate + 1, failures = 0; candidate_end >
#| target_start; {
#| let found = rev_find_two_anchor_candidate_from_string(
#| target.data(),
#| target_start,
#| candidate_end,
#| first,
#| last_offset,
#| last,
#| )
#| if found < 0 {
#| break None
#| }
#| if string_ranges_equal(
#| target.data(),
#| found + 1,
#| pattern.data(),
#| pattern_start + 1,
#| middle_len,
#| ) {
#| break Some(found - target_start)
#| }
#| let candidate = found - target_start
#| let failures = failures + 1
#| let scanned = last_candidate - candidate
#| if two_anchor_should_fallback(failures, scanned) {
#| break rev_find_pattern_kmp_before(target, pattern, candidate)
#| }
#| continue found, failures
#| } nobreak {
#| None
#| }
#|}
#|#inline
#|fn two_anchor_should_fallback(failures : Int, scanned : Int) -> Bool {
#| failures > 64 || failures > 4 + scanned / 8
#|}
#|fn kmp_failure_table(pattern : StringView) -> FixedArray[Int] {
#| let m = pattern.length()
#| let table = FixedArray::make(m, 0)
#| let mut k = 0
#| for i in 1.. 0 && c != pattern.unsafe_get(k) {
#| k = table[k - 1]
#| }
#| if c == pattern.unsafe_get(k) {
#| k += 1
#| }
#| table[i] = k
#| }
#| table
#|}
#|fn find_pattern_kmp_from(
#| target : StringView,
#| pattern : StringView,
#| start : Int,
#|) -> Int? {
#| let n = target.length()
#| let m = pattern.length()
#| let table = kmp_failure_table(pattern)
#| let mut k = 0
#| for i in start.. 0 && c != pattern.unsafe_get(k) {
#| k = table[k - 1]
#| }
#| if c == pattern.unsafe_get(k) {
#| k += 1
#| }
#| if k == m {
#| return Some(i - m + 1)
#| }
#| }
#| None
#|}
#|fn rev_find_pattern_kmp_before(
#| target : StringView,
#| pattern : StringView,
#| candidate_end : Int,
#|) -> Int? {
#| guard candidate_end > 0 else { return None }
#| let m = pattern.length()
#| let table = kmp_failure_table(pattern)
#| let scan_end = candidate_end + m - 1
#| let mut k = 0
#| let mut best = -1
#| for i in 0.. 0 && c != pattern.unsafe_get(k) {
#| k = table[k - 1]
#| }
#| if c == pattern.unsafe_get(k) {
#| k += 1
#| }
#| if k == m {
#| best = i - m + 1
#| k = table[k - 1]
#| }
#| }
#| if best >= 0 {
#| Some(best)
#| } else {
#| None
#| }
#|}
#|test "kmp fallbacks handle periodic and overlapping patterns" {
#| let t : StringView = "aaaaaa"
#| assert_true(find_pattern_kmp_from(t, "aaa", 0) is Some(0))
#| assert_true(find_pattern_kmp_from(t, "aaa", 2) is Some(2))
#| assert_true(find_pattern_kmp_from(t, "aaa", 4) is None)
#| assert_true(rev_find_pattern_kmp_before(t, "aaa", 4) is Some(3))
#| assert_true(rev_find_pattern_kmp_before(t, "aaa", 1) is Some(0))
#| let u : StringView = "ababcababab"
#| assert_true(find_pattern_kmp_from(u, "abab", 0) is Some(0))
#| assert_true(find_pattern_kmp_from(u, "abab", 1) is Some(5))
#| assert_true(rev_find_pattern_kmp_before(u, "abab", 8) is Some(7))
#| assert_true(rev_find_pattern_kmp_before(u, "ababc", 7) is Some(0))
#| assert_true(find_pattern_kmp_from(u, "abcabc", 0) is None)
#| assert_true(rev_find_pattern_kmp_before(u, "abab", 0) is None)
#|}
#|#inline
#|fn string_ranges_equal(
#| left : String,
#| left_start : Int,
#| right : String,
#| right_start : Int,
#| length : Int,
#|) -> Bool {
#| for i in 0.. Int {
#| for pos in start.. Int {
#| for pos = candidate_end - 1; pos >= start; {
#| if data.unsafe_get(pos) == first &&
#| data.unsafe_get(pos + last_offset) == last {
#| break pos
#| }
#| continue pos - 1
#| } nobreak {
#| -1
#| }
#|}
#|#cfg(not(any(target="native", target="wasm")))
#|fn find_two_anchor_candidate_from_string(
#| data : String,
#| start : Int,
#| candidate_end : Int,
#| first : UInt16,
#| last_offset : Int,
#| last : UInt16,
#|) -> Int {
#| find_two_anchor_candidate_scalar(
#| data, start, candidate_end, first, last_offset, last,
#| )
#|}
#|#cfg(not(any(target="native", target="wasm")))
#|fn rev_find_two_anchor_candidate_from_string(
#| data : String,
#| start : Int,
#| candidate_end : Int,
#| first : UInt16,
#| last_offset : Int,
#| last : UInt16,
#|) -> Int {
#| rev_find_two_anchor_candidate_scalar(
#| data, start, candidate_end, first, last_offset, last,
#| )
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn find_two_anchor_candidate_from_string(
#| data : String,
#| start : Int,
#| candidate_end : Int,
#| first : UInt16,
#| last_offset : Int,
#| last : UInt16,
#|) -> Int {
#| guard start < candidate_end else { return -1 }
#| if data.unsafe_get(start) == first &&
#| data.unsafe_get(start + last_offset) == last {
#| return start
#| }
#| let first_v = i16x8_splat(first)
#| let last_v = i16x8_splat(last)
#| let tail_start = for pos = start; pos + 8 <= candidate_end; {
#| let mask = v128_and(
#| i16x8_eq(v128_load_i16x8(data, pos), first_v),
#| i16x8_eq(v128_load_i16x8(data, pos + last_offset), last_v),
#| )
#| let bits = i16x8_bitmask(mask)
#| if bits != 0 {
#| return pos + bits.ctz()
#| }
#| continue pos + 8
#| } nobreak {
#| pos
#| }
#| find_two_anchor_candidate_scalar(
#| data, tail_start, candidate_end, first, last_offset, last,
#| )
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn rev_find_two_anchor_candidate_from_string(
#| data : String,
#| start : Int,
#| candidate_end : Int,
#| first : UInt16,
#| last_offset : Int,
#| last : UInt16,
#|) -> Int {
#| guard start < candidate_end else { return -1 }
#| let final_candidate = candidate_end - 1
#| if data.unsafe_get(final_candidate) == first &&
#| data.unsafe_get(final_candidate + last_offset) == last {
#| return final_candidate
#| }
#| let first_v = i16x8_splat(first)
#| let last_v = i16x8_splat(last)
#| let head_end = for pos = candidate_end; pos - 8 >= start; {
#| let chunk_start = pos - 8
#| let mask = v128_and(
#| i16x8_eq(v128_load_i16x8(data, chunk_start), first_v),
#| i16x8_eq(v128_load_i16x8(data, chunk_start + last_offset), last_v),
#| )
#| let bits = i16x8_bitmask(mask)
#| if bits != 0 {
#| return chunk_start + 31 - bits.clz()
#| }
#| continue chunk_start
#| } nobreak {
#| pos
#| }
#| rev_find_two_anchor_candidate_scalar(
#| data, start, head_end, first, last_offset, last,
#| )
#|}
),
"string_like.mbt": (
#|pub trait ToStringView {
#| fn to_string_view(Self) -> StringView
#|}
#|pub impl ToStringView for String with fn to_string_view(self) -> StringView {
#| self
#|}
#|pub impl ToStringView for StringView with fn to_string_view(self) -> StringView {
#| self
#|}
),
"string_methods.mbt": (
#|pub fn StringView::find(self : StringView, str : StringView) -> Int? {
#| let pattern_len = str.length()
#| match pattern_len {
#| 0 => Some(0)
#| 1 => {
#| let found = find_code_unit_from_view(
#| self,
#| 0,
#| self.length(),
#| str.unsafe_get(0),
#| )
#| if found < 0 {
#| None
#| } else {
#| Some(found)
#| }
#| }
#| _ =>
#| if pattern_len > self.length() {
#| None
#| } else {
#| find_by_two_anchors(self, str)
#| }
#| }
#|}
#|pub fn String::find(self : String, str : StringView) -> Int? {
#| self[:].find(str)
#|}
#|test "find" {
#| assert_true("hello".find("o") == Some(4))
#| assert_true("hello".find("l") == Some(2))
#| assert_true("hello".find("hello") == Some(0))
#| assert_true("hello".find("h") == Some(0))
#| assert_true("hello".find("") == Some(0))
#| assert_true("hello".find("world") == None)
#| assert_true("".find("") == Some(0))
#| assert_true("".find("a") == None)
#| assert_true("hello hello".find("hello") == Some(0))
#| assert_true("aaa".find("aa") == Some(0))
#| assert_true("😀😀".find("😀") == Some(0))
#| assert_true(
#| ("😀😀aa".repeat(20) + "😀😀😀😀").find("😀😀😀😀") ==
#| Some(120),
#| )
#| assert_true(
#| ("😀😀😀😀" + "😀😀aa".repeat(20)).find("😀😀😀😀") ==
#| Some(0),
#| )
#|}
#|#locals(pred)
#|pub fn StringView::find_by(self : StringView, pred : (Char) -> Bool) -> Int? {
#| for c in self; offset = 0 {
#| if pred(c) {
#| break Some(offset)
#| }
#| continue offset + c.utf16_len()
#| } nobreak {
#| None
#| }
#|}
#|pub fn String::find_by(self : String, pred : (Char) -> Bool) -> Int? {
#| self[:].find_by(pred)
#|}
#|test "find_by" {
#| assert_true("hello".find_by(c => c == 'o') == Some(4))
#| assert_true("hello".find_by(c => c == 'l') == Some(2))
#| assert_true("hello".find_by(c => c == 'z') == None)
#| assert_true("".find_by(c => c == 'a') == None)
#| assert_true("hello".find_by(c => c is ('0'..='9')) == None)
#| assert_true("hello123".find_by(c => c is ('0'..='9')) == Some(5))
#| assert_true("hello".find_by(c => c is ('A'..='Z')) == None)
#| assert_true("Hello".find_by(c => c is ('A'..='Z')) == Some(0))
#| assert_true("αβγ".find_by(c => c == 'β') == Some(1))
#|}
#|test "find_by returns UTF-16 code-unit offsets" {
#| assert_true("😀X".find_by(c => c == 'X') == Some(2))
#| assert_true("😀😁😂".find_by(c => c == '😂') == Some(4))
#| let view = "a😀Xz"[1:4]
#| assert_true(view.find_by(c => c == 'X') == Some(2))
#|}
#|pub fn StringView::rev_find(self : StringView, str : StringView) -> Int? {
#| let pattern_len = str.length()
#| match pattern_len {
#| 0 => Some(self.length())
#| 1 => {
#| let found = rev_find_code_unit_from_view(
#| self,
#| 0,
#| self.length(),
#| str.unsafe_get(0),
#| )
#| if found < 0 {
#| None
#| } else {
#| Some(found)
#| }
#| }
#| _ =>
#| if pattern_len > self.length() {
#| None
#| } else {
#| rev_find_by_two_anchors(self, str)
#| }
#| }
#|}
#|pub fn String::rev_find(self : String, str : StringView) -> Int? {
#| self[:].rev_find(str)
#|}
#|test "rev_find" {
#| assert_true("hello".rev_find("o") == Some(4))
#| assert_true("hello".rev_find("l") == Some(3))
#| assert_true("hello".rev_find("hello") == Some(0))
#| assert_true("hello".rev_find("h") == Some(0))
#| assert_true("hello".rev_find("") == Some(5))
#| assert_true("hello".rev_find("world") == None)
#| assert_true("".rev_find("") == Some(0))
#| assert_true("".rev_find("a") == None)
#| assert_true("hello hello".rev_find("hello") == Some(6))
#| assert_true("aaa".rev_find("aa") == Some(1))
#| assert_true("😀😀".rev_find("😀") == Some(2))
#| assert_true(
#| ("😀😀aa".repeat(20) + "😀😀😀😀").rev_find("😀😀😀😀") ==
#| Some(120),
#| )
#| assert_true(
#| ("😀😀😀😀" + "😀😀aa".repeat(20)).rev_find("😀😀😀😀") ==
#| Some(4),
#| )
#|}
#|#alias(ends_with, deprecated)
#|pub fn StringView::has_suffix(self : StringView, str : StringView) -> Bool {
#| let self_len = self.length()
#| let str_len = str.length()
#| guard str_len <= self_len else { return false }
#| let start = self_len - str_len
#| guard str_len == 0 || self.unsafe_get(start) == str.unsafe_get(0) else {
#| return false
#| }
#| self
#| .str()
#| .unsafe_range_equal(
#| str.str(),
#| self_off=self.start() + start,
#| other_off=str.start(),
#| len=str_len,
#| )
#|}
#|#alias(ends_with, deprecated)
#|pub fn String::has_suffix(self : String, str : StringView) -> 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")
#|}
#|#alias(starts_with, deprecated)
#|pub fn StringView::has_prefix(self : StringView, str : StringView) -> Bool {
#| let str_len = str.length()
#| guard str_len <= self.length() else { return false }
#| guard str_len == 0 || self.unsafe_get(0) == str.unsafe_get(0) else {
#| return false
#| }
#| self
#| .str()
#| .unsafe_range_equal(
#| str.str(),
#| self_off=self.start(),
#| other_off=str.start(),
#| len=str_len,
#| )
#|}
#|#alias(starts_with, deprecated)
#|pub fn String::has_prefix(self : String, str : StringView) -> 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")
#|}
#|test "StringView has_prefix and has_suffix" {
#| let view = "x😀hello worldy"[1:14]
#| assert_true(view.has_prefix("😀hello"))
#| assert_false(view.has_prefix("world"))
#| assert_false(view.has_prefix("😀hello world!"))
#| assert_true(view.has_suffix("world"))
#| assert_false(view.has_suffix("😀hello"))
#| assert_false(view.has_suffix("😀hello world!"))
#|}
#|#alias(chop_suffix)
#|pub fn String::strip_suffix(self : String, suffix : StringView) -> StringView? {
#| self[:].strip_suffix(suffix)
#|}
#|test "strip_prefix" {
#| assert_true("hello world".strip_prefix("hello ") == Some("world"))
#| assert_true("hello world".strip_prefix("hi ") == None)
#| assert_true("hello".strip_prefix("hello") == Some(""))
#| assert_true("".strip_prefix("") == Some(""))
#| assert_true("".strip_prefix("a") == None)
#| assert_true("abc".strip_prefix("") == Some("abc"))
#| assert_true("😀hello".strip_prefix("😀") == Some("hello"))
#| assert_true("😀😃hello".strip_prefix("😀😃") == Some("hello"))
#|}
#|test "strip_suffix" {
#| assert_true("hello world".strip_suffix(" world") == Some("hello"))
#| assert_true("hello world".strip_suffix(" moon") == None)
#| assert_true("hello".strip_suffix("hello") == Some(""))
#| assert_true("".strip_suffix("") == Some(""))
#| assert_true("".strip_suffix("a") == None)
#| assert_true("abc".strip_suffix("") == Some("abc"))
#| assert_true("hello😀".strip_suffix("😀") == Some("hello"))
#| assert_true("hello😀😃".strip_suffix("😀😃") == Some("hello"))
#|}
#|#alias(chop_prefix)
#|pub fn String::strip_prefix(self : String, prefix : StringView) -> StringView? {
#| self[:].strip_prefix(prefix)
#|}
#|#alias(chop_prefix)
#|pub fn StringView::strip_prefix(
#| self : StringView,
#| prefix : StringView,
#|) -> StringView? {
#| let prefix_len = prefix.length()
#| if self.length() >= prefix_len && self.view(end_offset=prefix_len) == prefix {
#| Some(self.view(start_offset=prefix_len))
#| } else {
#| None
#| }
#|}
#|#alias(chop_suffix)
#|pub fn StringView::strip_suffix(
#| self : StringView,
#| suffix : StringView,
#|) -> StringView? {
#| let self_len = self.length()
#| let suffix_len = suffix.length()
#| if self_len >= suffix_len &&
#| self.view(start_offset=self_len - suffix_len) == suffix {
#| Some(self.view(end_offset=self_len - suffix_len))
#| } else {
#| None
#| }
#|}
#|pub fn StringView::to_array(self : StringView) -> Array[Char] {
#| self
#| .iter()
#| .fold(init=Array(capacity=self.length()), (rv, c) => {
#| rv.push(c)
#| rv
#| })
#|}
#|#deprecated("Check `@encoding/utf8.encode`")
#|#coverage.skip
#|pub fn StringView::to_bytes(self : StringView) -> Bytes {
#| let array = FixedArray::make(self.length() * 2, b'\x00')
#| array.blit_from_string(0, self.data(), self.start_offset(), self.length())
#| array |> unsafe_to_bytes
#|}
#|test "View::strip_prefix" {
#| let view = "hello world"[:]
#| assert_true(view.strip_prefix("hello ") == Some("world"))
#| assert_true(view.strip_prefix("hi ") == None)
#| assert_true(view.strip_prefix("hello world") == Some(""))
#| assert_true(view.strip_prefix("") == Some("hello world"))
#| let empty_view = ""[:]
#| assert_true(empty_view.strip_prefix("") == Some(""))
#| assert_true(empty_view.strip_prefix("a") == None)
#| let unicode_view = "😀hello😃"[:]
#| assert_true(unicode_view.strip_prefix("😀") == Some("hello😃"))
#| assert_true(unicode_view.strip_prefix("😃") == None)
#|}
#|test "View::strip_suffix" {
#| let view = "hello world"[:]
#| assert_true(view.strip_suffix(" world") == Some("hello"))
#| assert_true(view.strip_suffix(" moon") == None)
#| assert_true(view.strip_suffix("hello world") == Some(""))
#| assert_true(view.strip_suffix("") == Some("hello world"))
#| let empty_view = ""[:]
#| assert_true(empty_view.strip_suffix("") == Some(""))
#| assert_true(empty_view.strip_suffix("a") == None)
#| let unicode_view = "😀hello😃"[:]
#| assert_true(unicode_view.strip_suffix("😃") == Some("😀hello"))
#| assert_true(unicode_view.strip_suffix("😀") == None)
#|}
#|test "View::to_array" {
#| let view = "Hello🤣"[:]
#| let chars = view.to_array()
#| assert_true(chars == ['H', 'e', 'l', 'l', 'o', '🤣'])
#| let empty_view = ""[:]
#| let empty_chars = empty_view.to_array()
#| assert_true(empty_chars == [])
#| let sub_view = "Hello World"[6:11] // "World"
#| let sub_chars = sub_view.to_array()
#| assert_true(sub_chars == ['W', 'o', 'r', 'l', 'd'])
#|}
#|pub fn StringView::contains_code_unit(self : StringView, code : UInt16) -> Bool {
#| string_contains_code_unit(self.str(), self.start(), self.end(), code)
#|}
#|#inline
#|fn string_contains_code_unit_scalar(
#| str : String,
#| start : Int,
#| end : Int,
#| code : UInt16,
#|) -> Bool {
#| for i in start.. Bool {
#| string_contains_code_unit_scalar(str, start, end, code)
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn string_contains_code_unit(
#| str : String,
#| start : Int,
#| end : Int,
#| code : UInt16,
#|) -> Bool {
#| guard start + 8 <= end else {
#| return string_contains_code_unit_scalar(str, start, end, code)
#| }
#| let needle = i16x8_splat(code)
#| let tail_start = for pos = start; pos + 8 <= end; {
#| if v128_any_true(i16x8_eq(v128_load_i16x8(str, pos), needle)) {
#| return true
#| }
#| continue pos + 8
#| } nobreak {
#| pos
#| }
#| string_contains_code_unit_scalar(str, tail_start, end, code)
#|}
#|pub fn StringView::contains(self : StringView, str : StringView) -> Bool {
#| match str.length() {
#| 0 => true
#| 1 => self.contains_code_unit(str.unsafe_get(0))
#| _ => self.find(str) is Some(_)
#| }
#|}
#|pub fn String::contains(self : String, str : StringView) -> Bool {
#| self[:].contains(str)
#|}
#|pub fn String::contains_code_unit(self : String, code : UInt16) -> Bool {
#| string_contains_code_unit(self, 0, self.length(), code)
#|}
#|const ASCII_CHAR_SET_LIMIT : UInt = 128U
#|const ASCII_CHAR_SET_WORD_MASK : UInt = 31U
#|const ASCII_CHAR_SET_WORD_SHIFT = 5
#|#cfg(any(target="native", target="wasm"))
#|const ASCII_CHAR_SET_SIMD_MAX_CHARS = 8
#|#inline
#|fn build_ascii_char_set(chars : StringView) -> (UInt, UInt, UInt, UInt)? {
#| let mut bits0 = 0U
#| let mut bits1 = 0U
#| let mut bits2 = 0U
#| let mut bits3 = 0U
#| for c in chars {
#| let code = c.to_uint()
#| guard code < ASCII_CHAR_SET_LIMIT else { return None }
#| let bit = 1U << (code & ASCII_CHAR_SET_WORD_MASK).reinterpret_as_int()
#| match code >> ASCII_CHAR_SET_WORD_SHIFT {
#| 0 => bits0 = bits0 | bit
#| 1 => bits1 = bits1 | bit
#| 2 => bits2 = bits2 | bit
#| _ => bits3 = bits3 | bit
#| }
#| }
#| Some((bits0, bits1, bits2, bits3))
#|}
#|#inline
#|fn ascii_char_set_contains(
#| bits0 : UInt,
#| bits1 : UInt,
#| bits2 : UInt,
#| bits3 : UInt,
#| code : UInt,
#|) -> Bool {
#| guard code < ASCII_CHAR_SET_LIMIT else { return false }
#| let bit = 1U << (code & ASCII_CHAR_SET_WORD_MASK).reinterpret_as_int()
#| match code >> ASCII_CHAR_SET_WORD_SHIFT {
#| 0 => (bits0 & bit) != 0U
#| 1 => (bits1 & bit) != 0U
#| 2 => (bits2 & bit) != 0U
#| _ => (bits3 & bit) != 0U
#| }
#|}
#|#cfg(not(target="js"))
#|#inline
#|fn string_contains_any_ascii_scalar(
#| str : String,
#| start : Int,
#| end : Int,
#| bits0 : UInt,
#| bits1 : UInt,
#| bits2 : UInt,
#| bits3 : UInt,
#|) -> Bool {
#| for i in start.. Int {
#| for pos = start {
#| if pos < end &&
#| ascii_char_set_contains(
#| bits0,
#| bits1,
#| bits2,
#| bits3,
#| str.unsafe_get(pos).to_uint(),
#| ) {
#| continue pos + 1
#| } else {
#| break pos
#| }
#| }
#|}
#|#inline
#|fn string_trim_end_ascii_scalar(
#| str : String,
#| start : Int,
#| end : Int,
#| bits0 : UInt,
#| bits1 : UInt,
#| bits2 : UInt,
#| bits3 : UInt,
#|) -> Int {
#| for pos = end {
#| if pos > start &&
#| ascii_char_set_contains(
#| bits0,
#| bits1,
#| bits2,
#| bits3,
#| str.unsafe_get(pos - 1).to_uint(),
#| ) {
#| continue pos - 1
#| } else {
#| break pos
#| }
#| }
#|}
#|#cfg(any(target="native", target="wasm"))
#|#inline
#|fn ascii_char_set_splat(chars : StringView, count : Int, index : Int) -> V128 {
#| i16x8_splat(chars.unsafe_get(if index < count { index } else { 0 }))
#|}
#|#cfg(any(target="native", target="wasm"))
#|#inline
#|fn ascii_char_set_block_mask(
#| block : V128,
#| s0 : V128,
#| s1 : V128,
#| s2 : V128,
#| s3 : V128,
#| s4 : V128,
#| s5 : V128,
#| s6 : V128,
#| s7 : V128,
#|) -> V128 {
#| v128_or(
#| v128_or(
#| v128_or(i16x8_eq(block, s0), i16x8_eq(block, s1)),
#| v128_or(i16x8_eq(block, s2), i16x8_eq(block, s3)),
#| ),
#| v128_or(
#| v128_or(i16x8_eq(block, s4), i16x8_eq(block, s5)),
#| v128_or(i16x8_eq(block, s6), i16x8_eq(block, s7)),
#| ),
#| )
#|}
#|#cfg(target="js")
#|fn string_contains_any_ascii(
#| str : String,
#| start : Int,
#| end : Int,
#| _chars : StringView,
#| bits0 : UInt,
#| bits1 : UInt,
#| bits2 : UInt,
#| bits3 : UInt,
#|) -> Bool {
#| StringView::make_view(str, start, end).contains_any_ascii_chars(
#| bits0, bits1, bits2, bits3,
#| )
#|}
#|#cfg(target="js")
#|fn StringView::contains_any_ascii_chars(
#| self : StringView,
#| bits0 : UInt,
#| bits1 : UInt,
#| bits2 : UInt,
#| bits3 : UInt,
#|) -> Bool {
#| for c in self {
#| if ascii_char_set_contains(bits0, bits1, bits2, bits3, c.to_uint()) {
#| return true
#| }
#| }
#| false
#|}
#|#cfg(not(any(target="native", target="wasm", target="js")))
#|fn string_contains_any_ascii(
#| str : String,
#| start : Int,
#| end : Int,
#| _chars : StringView,
#| bits0 : UInt,
#| bits1 : UInt,
#| bits2 : UInt,
#| bits3 : UInt,
#|) -> Bool {
#| string_contains_any_ascii_scalar(str, start, end, bits0, bits1, bits2, bits3)
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn string_contains_any_ascii(
#| str : String,
#| start : Int,
#| end : Int,
#| chars : StringView,
#| bits0 : UInt,
#| bits1 : UInt,
#| bits2 : UInt,
#| bits3 : UInt,
#|) -> Bool {
#| let count = chars.length()
#| guard count >= 1 && count <= ASCII_CHAR_SET_SIMD_MAX_CHARS && start + 8 <= end else {
#| return string_contains_any_ascii_scalar(
#| str, start, end, bits0, bits1, bits2, bits3,
#| )
#| }
#| let s0 = ascii_char_set_splat(chars, count, 0)
#| let s1 = ascii_char_set_splat(chars, count, 1)
#| let s2 = ascii_char_set_splat(chars, count, 2)
#| let s3 = ascii_char_set_splat(chars, count, 3)
#| let s4 = ascii_char_set_splat(chars, count, 4)
#| let s5 = ascii_char_set_splat(chars, count, 5)
#| let s6 = ascii_char_set_splat(chars, count, 6)
#| let s7 = ascii_char_set_splat(chars, count, 7)
#| let tail_start = for pos = start; pos + 8 <= end; {
#| let block = v128_load_i16x8(str, pos)
#| if v128_any_true(
#| ascii_char_set_block_mask(block, s0, s1, s2, s3, s4, s5, s6, s7),
#| ) {
#| return true
#| }
#| continue pos + 8
#| } nobreak {
#| pos
#| }
#| string_contains_any_ascii_scalar(
#| str, tail_start, end, bits0, bits1, bits2, bits3,
#| )
#|}
#|#cfg(not(any(target="native", target="wasm")))
#|fn string_trim_start_ascii(
#| str : String,
#| start : Int,
#| end : Int,
#| _chars : StringView,
#| bits0 : UInt,
#| bits1 : UInt,
#| bits2 : UInt,
#| bits3 : UInt,
#|) -> Int {
#| string_trim_start_ascii_scalar(str, start, end, bits0, bits1, bits2, bits3)
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn string_trim_start_ascii(
#| str : String,
#| start : Int,
#| end : Int,
#| chars : StringView,
#| bits0 : UInt,
#| bits1 : UInt,
#| bits2 : UInt,
#| bits3 : UInt,
#|) -> Int {
#| let count = chars.length()
#| guard count >= 1 && count <= ASCII_CHAR_SET_SIMD_MAX_CHARS && start + 8 <= end else {
#| return string_trim_start_ascii_scalar(
#| str, start, end, bits0, bits1, bits2, bits3,
#| )
#| }
#| let s0 = ascii_char_set_splat(chars, count, 0)
#| let s1 = ascii_char_set_splat(chars, count, 1)
#| let s2 = ascii_char_set_splat(chars, count, 2)
#| let s3 = ascii_char_set_splat(chars, count, 3)
#| let s4 = ascii_char_set_splat(chars, count, 4)
#| let s5 = ascii_char_set_splat(chars, count, 5)
#| let s6 = ascii_char_set_splat(chars, count, 6)
#| let s7 = ascii_char_set_splat(chars, count, 7)
#| let boundary = for pos = start; pos + 8 <= end; {
#| let block = v128_load_i16x8(str, pos)
#| let mask = ascii_char_set_block_mask(block, s0, s1, s2, s3, s4, s5, s6, s7)
#| if i16x8_bitmask(mask) != 0xFF {
#| break pos
#| }
#| continue pos + 8
#| } nobreak {
#| pos
#| }
#| string_trim_start_ascii_scalar(str, boundary, end, bits0, bits1, bits2, bits3)
#|}
#|#cfg(not(any(target="native", target="wasm")))
#|fn string_trim_end_ascii(
#| str : String,
#| start : Int,
#| end : Int,
#| _chars : StringView,
#| bits0 : UInt,
#| bits1 : UInt,
#| bits2 : UInt,
#| bits3 : UInt,
#|) -> Int {
#| string_trim_end_ascii_scalar(str, start, end, bits0, bits1, bits2, bits3)
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn string_trim_end_ascii(
#| str : String,
#| start : Int,
#| end : Int,
#| chars : StringView,
#| bits0 : UInt,
#| bits1 : UInt,
#| bits2 : UInt,
#| bits3 : UInt,
#|) -> Int {
#| let count = chars.length()
#| guard count >= 1 && count <= ASCII_CHAR_SET_SIMD_MAX_CHARS && start + 8 <= end else {
#| return string_trim_end_ascii_scalar(
#| str, start, end, bits0, bits1, bits2, bits3,
#| )
#| }
#| let s0 = ascii_char_set_splat(chars, count, 0)
#| let s1 = ascii_char_set_splat(chars, count, 1)
#| let s2 = ascii_char_set_splat(chars, count, 2)
#| let s3 = ascii_char_set_splat(chars, count, 3)
#| let s4 = ascii_char_set_splat(chars, count, 4)
#| let s5 = ascii_char_set_splat(chars, count, 5)
#| let s6 = ascii_char_set_splat(chars, count, 6)
#| let s7 = ascii_char_set_splat(chars, count, 7)
#| let boundary = for pos = end; pos - 8 >= start; {
#| let block = v128_load_i16x8(str, pos - 8)
#| let mask = ascii_char_set_block_mask(block, s0, s1, s2, s3, s4, s5, s6, s7)
#| if i16x8_bitmask(mask) != 0xFF {
#| break pos
#| }
#| continue pos - 8
#| } nobreak {
#| pos
#| }
#| string_trim_end_ascii_scalar(str, start, boundary, bits0, bits1, bits2, bits3)
#|}
#|fn StringView::trim_start_with_chars(
#| self : StringView,
#| chars : StringView,
#|) -> StringView {
#| for x = self {
#| match x {
#| [] as v => break v
#| [c, .. rest] as v =>
#| if chars.contains_char(c) {
#| continue rest
#| } else {
#| break v
#| }
#| }
#| }
#|}
#|fn StringView::trim_end_with_chars(
#| self : StringView,
#| chars : StringView,
#|) -> StringView {
#| for x = self {
#| match x {
#| [] as v => break v
#| [.. rest, c] as v =>
#| if chars.contains_char(c) {
#| continue rest
#| } else {
#| break v
#| }
#| }
#| }
#|}
#|pub fn StringView::contains_any(self : StringView, chars~ : StringView) -> Bool {
#| match chars {
#| [] => false
#| [c] => self.contains_char(c) // specialize for single character
#| _ =>
#| match build_ascii_char_set(chars) {
#| Some((bits0, bits1, bits2, bits3)) =>
#| string_contains_any_ascii(
#| self.str(),
#| self.start(),
#| self.end(),
#| chars,
#| bits0,
#| bits1,
#| bits2,
#| bits3,
#| )
#| None =>
#| for c in self {
#| if chars.contains_char(c) {
#| break true
#| }
#| } nobreak {
#| false
#| }
#| }
#| }
#|}
#|pub fn String::contains_any(self : String, chars~ : StringView) -> Bool {
#| self[:].contains_any(chars~)
#|}
#|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")
#| let leading_surrogate = String::from_array([(0xD800).unsafe_to_char()])
#| inspect(leading_surrogate.contains(leading_surrogate), content="true")
#|}
#|test "contains_code_unit" {
#| inspect("hello".contains_code_unit(('h' : UInt16)), content="true")
#| inspect("hello".contains_code_unit(('x' : UInt16)), content="false")
#| inspect("xhello"[1:].contains_code_unit(('h' : UInt16)), content="true")
#| inspect("xhello"[1:].contains_code_unit(('x' : UInt16)), content="false")
#| inspect("😀".contains_code_unit(0xD83D), content="true")
#| inspect("😀".contains_code_unit(0xDE00), content="true")
#| let leading_surrogate = String::from_array([(0xD800).unsafe_to_char()])
#| inspect(leading_surrogate.contains_code_unit(0xD800), content="true")
#|}
#|test "contains_code_unit SIMD blocks and view bounds" {
#| let str = "01234567abcdefghZ"
#| inspect(str.contains_code_unit(('0' : UInt16)), content="true")
#| inspect(str.contains_code_unit(('7' : UInt16)), content="true")
#| inspect(str.contains_code_unit(('a' : UInt16)), content="true")
#| inspect(str.contains_code_unit(('h' : UInt16)), content="true")
#| inspect(str.contains_code_unit(('Z' : UInt16)), content="true")
#| inspect(str.contains_code_unit(('x' : UInt16)), content="false")
#| let view = ("x" + str + "y")[1:18]
#| inspect(view.contains_code_unit(('x' : UInt16)), content="false")
#| inspect(view.contains_code_unit(('a' : UInt16)), content="true")
#| inspect(view.contains_code_unit(('Z' : UInt16)), content="true")
#| inspect(view.contains_code_unit(('y' : UInt16)), content="false")
#| let wide = "01234567abcd😀efgh"
#| inspect(wide.contains_code_unit(0xD83D), content="true")
#| inspect(wide.contains_code_unit(0xDE00), content="true")
#|}
#|test "contains_any" {
#| inspect("hello".contains_any(chars="h"), content="true")
#| inspect("hello".contains_any(chars="xyz"), content="false")
#| inspect("hello".contains_any(chars=""), content="false")
#| inspect("".contains_any(chars="abc"), content="false")
#| inspect("😀😃".contains_any(chars="😄😀"), content="true")
#| inspect("hello"[:].contains_any(chars="eo"), content="true")
#|}
#|test "contains_any and trim ASCII character sets" {
#| assert_true("😀a".contains_any(chars="az"))
#| assert_false("😀".contains_any(chars="az"))
#| assert_true("😀".contains_any(chars="a😀"))
#| let view = "x hello \ty"[1:10]
#| assert_true(view.trim(chars=" \t") == "hello")
#|}
#|test "build ASCII character set" {
#| match build_ascii_char_set("a z") {
#| Some((bits0, bits1, bits2, bits3)) => {
#| assert_true(
#| ascii_char_set_contains(bits0, bits1, bits2, bits3, 'a'.to_uint()),
#| )
#| assert_true(
#| ascii_char_set_contains(bits0, bits1, bits2, bits3, 'z'.to_uint()),
#| )
#| assert_true(
#| ascii_char_set_contains(bits0, bits1, bits2, bits3, ' '.to_uint()),
#| )
#| assert_false(
#| ascii_char_set_contains(bits0, bits1, bits2, bits3, 'b'.to_uint()),
#| )
#| }
#| None => assert_false(true)
#| }
#| assert_true(build_ascii_char_set("a😀") is None)
#|}
#|pub fn StringView::contains_char(self : StringView, c : Char) -> Bool {
#| let len = self.length()
#| guard len > 0 else { return false }
#| let c = c.to_int()
#| if c >= 0 && c <= 0xFFFF {
#| return self.contains_code_unit(c.to_uint16())
#| } else if c < 0 {
#| return false
#| } else {
#| guard len >= 2 else { return false }
#| let adj = c - 0x10000
#| let high = 0xD800 + (adj >> 10)
#| guard high <= 0xFFFF else { return false }
#| let high = high.to_uint16()
#| let low = (0xDC00 + (adj & 0x3FF)).to_uint16()
#| for i = 0; i < len - 1; {
#| if self.unsafe_get(i) == high {
#| if self.unsafe_get(i + 1) == low {
#| return true
#| }
#| continue i + 2
#| }
#| continue i + 1
#| }
#| }
#| false
#|}
#|pub fn String::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('h'), content="true")
#| let leading_surrogate = String::from_array([(0xD800).unsafe_to_char()])
#| inspect(
#| leading_surrogate.contains_char((0xD800).unsafe_to_char()),
#| content="true",
#| )
#| let max_code_unit = String::from_array([(0xFFFF).unsafe_to_char()])
#| inspect(max_code_unit.contains_char((-1).unsafe_to_char()), content="false")
#|}
#|#label_migration(chars, alias=char_set)
#|pub fn StringView::trim_start(
#| self : StringView,
#| chars? : StringView = "\t\n\r ",
#|) -> StringView {
#| match build_ascii_char_set(chars) {
#| Some((bits0, bits1, bits2, bits3)) => {
#| let start = string_trim_start_ascii(
#| self.str(),
#| self.start(),
#| self.end(),
#| chars,
#| bits0,
#| bits1,
#| bits2,
#| bits3,
#| )
#| StringView::make_view(self.str(), start, self.end())
#| }
#| None => self.trim_start_with_chars(chars)
#| }
#|}
#|#label_migration(chars, alias=char_set)
#|pub fn String::trim_start(
#| self : String,
#| chars? : StringView = "\t\n\r ",
#|) -> StringView {
#| self[:].trim_start(chars~)
#|}
#|test "trim_start" {
#| inspect("hello".trim_start(chars="h"), content="ello")
#| inspect("hello".trim_start(chars="he"), content="llo")
#| inspect("hello".trim_start(chars="eh"), content="llo")
#| inspect("hello".trim_start(chars="x"), content="hello")
#| inspect("hello".trim_start(chars=""), content="hello")
#| inspect("".trim_start(chars="a"), content="")
#| inspect(" hello".trim_start(chars=" "), content="hello")
#| inspect("hello world".trim_start(chars="helo"), content=" world")
#| inspect("😀😀hello".trim_start(chars="😀"), content="hello")
#| inspect("😀😃hello".trim_start(chars="😀😃"), content="hello")
#| inspect("aaaabc".trim_start(chars="a"), content="bc")
#| inspect("aaaa".trim_start(chars="a"), content="")
#|}
#|#label_migration(chars, alias=char_set)
#|pub fn StringView::trim_end(
#| self : StringView,
#| chars? : StringView = "\t\n\r ",
#|) -> StringView {
#| match build_ascii_char_set(chars) {
#| Some((bits0, bits1, bits2, bits3)) => {
#| let end = string_trim_end_ascii(
#| self.str(),
#| self.start(),
#| self.end(),
#| chars,
#| bits0,
#| bits1,
#| bits2,
#| bits3,
#| )
#| StringView::make_view(self.str(), self.start(), end)
#| }
#| None => self.trim_end_with_chars(chars)
#| }
#|}
#|#label_migration(chars, alias=char_set)
#|pub fn String::trim_end(
#| self : String,
#| chars? : StringView = "\t\n\r ",
#|) -> StringView {
#| self[:].trim_end(chars~)
#|}
#|test "trim_end" {
#| inspect("hello".trim_end(chars="o"), content="hell")
#| inspect("hello".trim_end(chars="lo"), content="he")
#| inspect("hello".trim_end(chars="x"), content="hello")
#| inspect("hello".trim_end(chars=""), content="hello")
#| inspect("".trim_end(chars="a"), content="")
#| inspect("hello ".trim_end(chars=" "), content="hello")
#| inspect("hello world".trim_end(chars="dlrow "), content="he")
#| inspect("hello😀😀".trim_end(chars="😀"), content="hello")
#| inspect("hello😀😃".trim_end(chars="😀😃"), content="hello")
#| inspect("abcccc".trim_end(chars="c"), content="ab")
#| inspect("cccc".trim_end(chars="c"), content="")
#|}
#|#label_migration(chars, alias=char_set)
#|pub fn StringView::trim(
#| self : StringView,
#| chars? : StringView = "\t\n\r ",
#|) -> StringView {
#| match build_ascii_char_set(chars) {
#| Some((bits0, bits1, bits2, bits3)) => {
#| let start = string_trim_start_ascii(
#| self.str(),
#| self.start(),
#| self.end(),
#| chars,
#| bits0,
#| bits1,
#| bits2,
#| bits3,
#| )
#| let end = string_trim_end_ascii(
#| self.str(),
#| start,
#| self.end(),
#| chars,
#| bits0,
#| bits1,
#| bits2,
#| bits3,
#| )
#| StringView::make_view(self.str(), start, end)
#| }
#| None => self.trim_start_with_chars(chars).trim_end_with_chars(chars)
#| }
#|}
#|#label_migration(chars, alias=char_set)
#|pub fn String::trim(
#| self : String,
#| chars? : StringView = "\t\n\r ",
#|) -> StringView {
#| self[:].trim(chars~)
#|}
#|test "trim" {
#| inspect("hello".trim(chars="h"), content="ello")
#| inspect("hello".trim(chars="o"), content="hell")
#| inspect("hello".trim(chars="ho"), content="ell")
#| inspect("hello".trim(chars="oh"), content="ell")
#| inspect("hello".trim(chars="x"), content="hello")
#| inspect("hello".trim(chars=""), content="hello")
#| inspect("".trim(chars="a"), content="")
#| inspect(" hello ".trim(chars=" "), content="hello")
#| inspect("hello world".trim(chars="hd"), content="ello worl")
#| inspect("😀hello😀".trim(chars="😀"), content="hello")
#| inspect("😀😃hello😀😃".trim(chars="😀😃"), content="hello")
#| inspect("aaaabcaaa".trim(chars="a"), content="bc")
#| inspect("aaaa".trim(chars="a"), content="")
#| inspect(" hello world ".trim(chars=" "), content="hello world")
#| inspect("abcabc".trim(chars="abc"), content="")
#|}
#|#deprecated("Use `trim` with default whitespace characters instead")
#|pub fn StringView::trim_space(self : StringView) -> StringView {
#| self.trim()
#|}
#|#deprecated("Use `trim` with default whitespace characters instead")
#|pub fn String::trim_space(self : String) -> StringView {
#| self.trim()
#|}
#|test "trim whitespace for string" {
#| inspect("hello".trim(), content="hello")
#| inspect(" hello ".trim(), content="hello")
#| inspect("hello ".trim(), content="hello")
#| inspect(" hello".trim(), content="hello")
#| inspect("\t\nhello\r\n".trim(), content="hello")
#| inspect(" hello world ".trim(), content="hello world")
#| inspect(" ".trim(), content="")
#| inspect("\n\r\t".trim(), content="")
#| inspect("".trim(), content="")
#| inspect(" hello\nworld\t".trim(), content="hello\nworld")
#|}
#|pub fn StringView::is_empty(self : StringView) -> Bool {
#| self.length() == 0
#|}
#|pub fn String::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 StringView::is_blank(self : StringView) -> Bool {
#| self.trim().is_empty()
#|}
#|pub fn String::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 StringView::pad_start(
#| self : StringView,
#| total_width : Int,
#| padding_char : Char,
#|) -> String {
#| let len = self.length()
#| guard len < total_width else { return self.to_owned() }
#| let padding = String::make(total_width - len, padding_char)
#| [..padding, ..self]
#|}
#|pub fn String::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 StringView::pad_end(
#| self : StringView,
#| total_width : Int,
#| padding_char : Char,
#|) -> String {
#| let len = self.length()
#| guard len < total_width else { return self.to_owned() }
#| 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 StringView::repeat(self : StringView, n : Int) -> StringView {
#| match n {
#| _..<0 => abort("negative repeat count")
#| 0 => ""
#| 1 => self
#| _ => {
#| let len = self.length()
#| let total = len * n
#| guard len == 0 || total / n == len else {
#| abort("repeat result too large")
#| }
#| let buf = StringBuilder(size_hint=total)
#| let str = self.to_owned()
#| for _ in 0.. String {
#| match n {
#| _..<0 => abort("negative repeat count")
#| 0 => ""
#| 1 => self
#| _ => {
#| let len = self.length()
#| let total = len * n
#| guard len == 0 || total / n == len else {
#| abort("repeat result too large")
#| }
#| let buf = StringBuilder(size_hint=total)
#| let str = self.to_string()
#| for _ in 0.. String {
#| let buf = StringBuilder(size_hint=self.length())
#| for c in self.rev_iter() {
#| buf.write_char(c)
#| }
#| buf.to_string()
#|}
#|pub fn String::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 StringView::split(
#| self : StringView,
#| sep : StringView,
#|) -> Iter[StringView] {
#| let sep_len = sep.length()
#| if sep_len == 0 {
#| return self.iter().map(c => c.to_string().view())
#| }
#| let mut remaining = Some(self)
#| Iter::new(() => {
#| guard remaining is Some(view) else { None }
#| guard view.find(sep) is Some(end) else {
#| remaining = None
#| Some(view)
#| }
#| remaining = Some(view.view(start_offset=end + sep_len))
#| Some(view.view(end_offset=end))
#| })
#|}
#|pub fn String::split(self : String, sep : StringView) -> Iter[StringView] {
#| self[:].split(sep)
#|}
#|pub fn StringView::split_once(
#| self : StringView,
#| needle : StringView,
#|) -> (StringView, StringView)? {
#| match self.find(needle) {
#| Some(index) =>
#| Some(
#| (
#| self.view(end_offset=index),
#| self.view(start_offset=index + needle.length()),
#| ),
#| )
#| None => None
#| }
#|}
#|pub fn String::split_once(
#| self : String,
#| needle : StringView,
#|) -> (StringView, StringView)? {
#| self[:].split_once(needle)
#|}
#|pub fn StringView::before(
#| self : StringView,
#| needle : StringView,
#|) -> StringView? {
#| match self.find(needle) {
#| Some(index) => Some(self.view(end_offset=index))
#| None => None
#| }
#|}
#|pub fn String::before(self : String, needle : StringView) -> StringView? {
#| self[:].before(needle)
#|}
#|pub fn StringView::after(self : StringView, needle : StringView) -> StringView? {
#| match self.find(needle) {
#| Some(index) => Some(self.view(start_offset=index + needle.length()))
#| None => None
#| }
#|}
#|pub fn String::after(self : String, needle : StringView) -> StringView? {
#| self[:].after(needle)
#|}
#|pub fn StringView::rev_split_once(
#| self : StringView,
#| needle : StringView,
#|) -> (StringView, StringView)? {
#| match self.rev_find(needle) {
#| Some(index) =>
#| Some(
#| (
#| self.view(end_offset=index),
#| self.view(start_offset=index + needle.length()),
#| ),
#| )
#| None => None
#| }
#|}
#|pub fn String::rev_split_once(
#| self : String,
#| needle : StringView,
#|) -> (StringView, StringView)? {
#| self[:].rev_split_once(needle)
#|}
#|pub fn StringView::rev_before(
#| self : StringView,
#| needle : StringView,
#|) -> StringView? {
#| match self.rev_find(needle) {
#| Some(index) => Some(self.view(end_offset=index))
#| None => None
#| }
#|}
#|pub fn String::rev_before(self : String, needle : StringView) -> StringView? {
#| self[:].rev_before(needle)
#|}
#|pub fn StringView::rev_after(
#| self : StringView,
#| needle : StringView,
#|) -> StringView? {
#| match self.rev_find(needle) {
#| Some(index) => Some(self.view(start_offset=index + needle.length()))
#| None => None
#| }
#|}
#|pub fn String::rev_after(self : String, needle : StringView) -> StringView? {
#| self[:].rev_after(needle)
#|}
#|test "split" {
#| assert_true(
#| "a,b,c".split(",").map(x => x.to_owned()).collect() == ["a", "b", "c"],
#| )
#| assert_true(
#| "a,b,c".split("").map(x => x.to_owned()).collect() ==
#| ["a", ",", "b", ",", "c"],
#| )
#| assert_true(
#| "apple::orange::banana".split("::").map(x => x.to_owned()).collect() ==
#| ["apple", "orange", "banana"],
#| )
#| assert_true(
#| "abc".split("").map(x => x.to_owned()).collect() == ["a", "b", "c"],
#| )
#| assert_true("hello".split(",").map(x => x.to_owned()).collect() == ["hello"])
#| assert_true(
#| ",a,b,c".split(",").map(x => x.to_owned()).collect() == ["", "a", "b", "c"],
#| )
#| assert_true(
#| "a,b,c,".split(",").map(x => x.to_owned()).collect() == ["a", "b", "c", ""],
#| )
#| assert_true(
#| "a,b,c".split("").map(x => x.to_owned()).collect() ==
#| ["a", ",", "b", ",", "c"],
#| )
#| assert_true("".split("").map(x => x.to_owned()).collect() == [])
#| assert_true("".split(",").map(x => x.to_owned()).collect() == [""])
#| assert_true(
#| "😀,😃,😄".split(",").map(x => x.to_owned()).collect() ==
#| ["😀", "😃", "😄"],
#| )
#| assert_true(
#| "a😀b😀c".split("😀").map(x => x.to_owned()).collect() ==
#| ["a", "b", "c"],
#| )
#|}
#|test "split_once before after" {
#| assert_true("a=b=c".split_once("=") == Some(("a", "b=c")))
#| assert_true("a=b=c".before("=") == Some("a"))
#| assert_true("a=b=c".after("=") == Some("b=c"))
#| assert_true("nope".split_once("=") == None)
#| assert_true("nope".before("=") == None)
#| assert_true("nope".after("=") == None)
#| assert_true("".split_once("") == Some(("", "")))
#| assert_true("".before("") == Some(""))
#| assert_true("".after("") == Some(""))
#| assert_true("hello".split_once("") == Some(("", "hello")))
#| assert_true("hello".before("") == Some(""))
#| assert_true("hello".after("") == Some("hello"))
#| assert_true("😊::🚀".split_once("::") == Some(("😊", "🚀")))
#|}
#|test "rev_split_once rev_before rev_after" {
#| assert_true("a=b=c".rev_split_once("=") == Some(("a=b", "c")))
#| assert_true("a=b=c".rev_before("=") == Some("a=b"))
#| assert_true("a=b=c".rev_after("=") == Some("c"))
#| assert_true("nope".rev_split_once("=") == None)
#| assert_true("nope".rev_before("=") == None)
#| assert_true("nope".rev_after("=") == None)
#| assert_true("a/b/c.txt".rev_before("/") == Some("a/b"))
#| assert_true("a/b/c.txt".rev_after("/") == Some("c.txt"))
#| assert_true("one=two".rev_split_once("=") == Some(("one", "two")))
#| assert_true(
#| "😊::🚀::⭐".rev_split_once("::") == Some(("😊::🚀", "⭐")),
#| )
#|}
#|pub fn StringView::replace(
#| self : StringView,
#| old~ : StringView,
#| new~ : StringView,
#|) -> StringView {
#| match self.find(old) {
#| Some(end) =>
#| [
#| ..self.view(end_offset=end),
#| ..new,
#| ..self.view(start_offset=end + old.length()),
#| ]
#| None => self
#| }
#|}
#|pub fn String::replace(
#| self : String,
#| old~ : StringView,
#| new~ : StringView,
#|) -> 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 StringView::replace_all(
#| self : StringView,
#| old~ : StringView,
#| new~ : StringView,
#|) -> StringView {
#| let len = self.length()
#| let buf = StringBuilder(size_hint=len)
#| let old_len = old.length()
#| let new = new.to_owned()
#| 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 String::replace_all(
#| self : String,
#| old~ : StringView,
#| new~ : StringView,
#|) -> String {
#| let len = self.length()
#| let buf = StringBuilder(size_hint=len)
#| let old_len = old.length()
#| let new = new.to_owned()
#| 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_true("hello".replace_all(old="o", new="a") == "hella")
#| assert_true("hello".replace_all(old="l", new="a") == "heaao")
#| assert_true("hello".replace_all(old="ll", new="rr") == "herro")
#| assert_true("hello".replace_all(old="hello", new="world") == "world")
#| assert_true(
#| "hello hello hello".replace_all(old="hello", new="hi") == "hi hi hi",
#| )
#| assert_true(
#| "hello hello helloi".replace_all(old="hello", new="hi") == "hi hi hii",
#| )
#| assert_true(
#| "hi hi hii".replace_all(old="hi", new="hello") == "hello hello helloi",
#| )
#| assert_true("hello".replace_all(old="", new="a") == "ahaealalaoa")
#| assert_true("hello".replace_all(old="world", new="a") == "hello")
#| assert_true("".replace_all(old="", new="a") == "a")
#| assert_true("aaa".replace_all(old="a", new="b") == "bbb")
#| assert_true("aaa".replace_all(old="a", new="bb") == "bbbbbb")
#| assert_true("aaa".replace_all(old="aa", new="b") == "ba")
#| assert_true(
#| "🤣🤣🤣".replace_all(old="🤣", new="😊") == "😊😊😊",
#| )
#| assert_true("abc123abc".replace_all(old="abc", new="xyz") == "xyz123xyz")
#| assert_true("abcabcabc".replace_all(old="abc", new="") == "")
#| assert_true("abc".replace_all(old="abc", new="") == "")
#| assert_true("abc".replace_all(old="", new="x") == "xaxbxcx")
#|}
#|test "String::replace_all boundary cases" {
#| assert_true("helloworld".replace_all(old="world", new="X") == "helloX")
#| assert_true("abcdef".replace_all(old="def", new="XYZ") == "abcXYZ")
#| assert_true("abcabc".replace_all(old="abc", new="X") == "XX")
#| assert_true("test".replace_all(old="test", new="done") == "done")
#| assert_true("remove_me".replace_all(old="_me", new="") == "remove")
#|}
#|test "View::replace_all" {
#| assert_true("hello"[:].replace_all(old="o", new="a") == "hella")
#| assert_true("hello"[:].replace_all(old="l", new="a") == "heaao")
#| assert_true("hello"[:].replace_all(old="ll", new="rr") == "herro")
#| assert_true("hello"[:].replace_all(old="hello", new="world") == "world")
#| assert_true(
#| "hello hello hello"[:].replace_all(old="hello", new="hi") == "hi hi hi",
#| )
#| assert_true(
#| "hello hello helloi"[:].replace_all(old="hello", new="hi") == "hi hi hii",
#| )
#| assert_true(
#| "hi hi hii"[:].replace_all(old="hi", new="hello") == "hello hello helloi",
#| )
#| assert_true("hello"[:].replace_all(old="", new="a") == "ahaealalaoa")
#| assert_true("hello"[:].replace_all(old="world", new="a") == "hello")
#| assert_true(""[:].replace_all(old="", new="a") == "a")
#| assert_true("aaa"[:].replace_all(old="a", new="b") == "bbb")
#| assert_true("aaa"[:].replace_all(old="a", new="bb") == "bbbbbb")
#| assert_true("aaa"[:].replace_all(old="aa", new="b") == "ba")
#| assert_true(
#| "🤣🤣🤣"[:].replace_all(old="🤣", new="😊") == "😊😊😊",
#| )
#| assert_true("abc123abc"[:].replace_all(old="abc", new="xyz") == "xyz123xyz")
#| assert_true("abcabcabc"[:].replace_all(old="abc", new="") == "")
#| assert_true("abc"[:].replace_all(old="abc", new="") == "")
#| assert_true("abc"[:].replace_all(old="", new="x") == "xaxbxcx")
#|}
#|test "View::replace_all boundary cases" {
#| assert_true("abcabc"[:].replace_all(old="abc", new="X") == "XX")
#| assert_true("aaaa"[:].replace_all(old="aa", new="b") == "bb")
#| assert_true("hello"[:].replace_all(old="lo", new="X") == "helX")
#| assert_true("a"[:].replace_all(old="a", new="") == "")
#| inspect("Testing boundary condition", content="Testing boundary condition")
#|}
#|#cfg(not(any(target="js", target="native", target="wasm")))
#|fn find_ascii_uppercase_code_unit(
#| data : String,
#| start : Int,
#| len : Int,
#|) -> Int? {
#| let end = start + len
#| for i in start.. Int? {
#| let end = start + len
#| if data.unsafe_get(start) is ('A'..='Z') {
#| return Some(0)
#| }
#| let ascii_a = i16x8_splat(0x41)
#| let ascii_range = i16x8_splat(0x5A - 0x41)
#| let tail_start = for pos = start; pos + 8 <= end; {
#| let code_units = v128_load_i16x8(data, pos)
#| let uppercase_mask = i16x8_le_u(i16x8_sub(code_units, ascii_a), ascii_range)
#| if v128_any_true(uppercase_mask) {
#| for i in pos..<(pos + 8) {
#| if data.unsafe_get(i) is ('A'..='Z') {
#| return Some(i - start)
#| }
#| }
#| }
#| continue pos + 8
#| } nobreak {
#| pos
#| }
#| for i in tail_start.. Int? {
#| if len < 24 {
#| let end = start + len
#| for i in start.. String {
#| let len = view.length()
#| let output : FixedArray[UInt16] = FixedArray::make(len, 0)
#| output.unsafe_blit_from_string(0, view.data(), view.start_offset(), len)
#| let ascii_a = i16x8_splat(0x41)
#| let ascii_range = i16x8_splat(0x5A - 0x41)
#| let lowercase_delta = i16x8_splat(0x20)
#| let tail_start = for pos = first_uppercase; pos + 8 <= len; {
#| let code_units = v128_load_fixedarray_i16x8(output, pos)
#| let uppercase_mask = i16x8_le_u(i16x8_sub(code_units, ascii_a), ascii_range)
#| let lowered = i16x8_add(
#| code_units,
#| v128_and(uppercase_mask, lowercase_delta),
#| )
#| v128_store_i16x8(output, pos, lowered)
#| continue pos + 8
#| } nobreak {
#| pos
#| }
#| for i in tail_start.. String {
#| let len = view.length()
#| let output : FixedArray[UInt16] = FixedArray::make(len, 0)
#| output.unsafe_blit_from_string(0, view.data(), view.start_offset(), len)
#| let tail = view.view(start_offset=first_uppercase)
#| for i, u in tail.code_units() {
#| if u is ('A'..='Z') {
#| output.unsafe_set(first_uppercase + i, (u.to_int() + 32).to_uint16())
#| }
#| }
#| unsafe_fixedarray_uint16_to_string(output)
#|}
#|#cfg(not(target="js"))
#|pub fn StringView::to_lower(self : StringView) -> StringView {
#| let data = self.data()
#| let start = self.start_offset()
#| let len = self.length()
#| guard find_ascii_uppercase_code_unit(data, start, len) is Some(idx) else {
#| return self
#| }
#| ascii_lowercase_copy(self, idx)
#|}
#|#cfg(not(target="js"))
#|pub fn String::to_lower(self : String) -> String {
#| let len = self.length()
#| guard find_ascii_uppercase_code_unit(self, 0, len) is Some(idx) else {
#| return self
#| }
#| ascii_lowercase_copy(self, idx)
#|}
#|#cfg(target="js")
#|pub fn StringView::to_lower(self : StringView) -> StringView {
#| guard self.find_by(c => c.is_ascii_uppercase()) is Some(idx) else {
#| return self
#| }
#| let buf = StringBuilder(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()
#|}
#|#cfg(target="js")
#|pub fn String::to_lower(self : String) -> String {
#| guard self.find_by(c => c.is_ascii_uppercase()) is Some(idx) else {
#| return self
#| }
#| let buf = StringBuilder(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_true("Hello".to_lower() == "hello")
#| assert_true("HELLO".to_lower() == "hello")
#| assert_true("Hello, World!".to_lower() == "hello, world!")
#| assert_true("xxA@Z[az09!".to_lower() == "xxa@z[az09!")
#| assert_true("🤣A".to_lower() == "🤣a")
#| assert_true("A🤣B".to_lower() == "a🤣b")
#| let unpaired = String::from_array([(0xD800).unsafe_to_char(), 'A'])
#| let lowered_unpaired = String::from_array([(0xD800).unsafe_to_char(), 'a'])
#| assert_true(unpaired.to_lower() == lowered_unpaired)
#|}
#|test "to_lower after a non-BMP character" {
#| inspect("😀X".to_lower(), content="😀x")
#| inspect("a😀Xz"[1:4].to_lower(), content="😀x")
#|}
#|test "to_lower SIMD search boundaries" {
#| for uppercase_at in 0..<40 {
#| let prefix = "x".repeat(uppercase_at)
#| let suffix = "x".repeat(40 - uppercase_at)
#| assert_true((prefix + "A" + suffix).to_lower() == prefix + "a" + suffix)
#| }
#| let source = "A" + "x".repeat(40) + "Z"
#| assert_true(source[1:41].to_lower() == "x".repeat(40))
#|}
#|test "View::to_lower" {
#| assert_true("Hello"[:].to_lower() == "hello")
#| assert_true("HELLO"[:].to_lower() == "hello")
#| assert_true("Hello, World!"[:].to_lower() == "hello, world!")
#| assert_true("x🤣ABy"[1:5].to_lower() == "🤣ab")
#| let unpaired = String::from_array([(0xD800).unsafe_to_char(), 'A'])
#| let lowered_unpaired = String::from_array([(0xD800).unsafe_to_char(), 'a'])
#| assert_true(unpaired[:].to_lower() == lowered_unpaired)
#|}
#|pub fn StringView::to_upper(self : StringView) -> StringView {
#| guard self.find_by(c => c.is_ascii_lowercase()) is Some(idx) else {
#| return self
#| }
#| let buf = StringBuilder(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 String::to_upper(self : String) -> String {
#| guard self.find_by(c => c.is_ascii_lowercase()) is Some(idx) else {
#| return self
#| }
#| let buf = StringBuilder(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_true("hello".to_upper() == "HELLO")
#| assert_true("HELLO".to_upper() == "HELLO")
#| assert_true("Hello, World!".to_upper() == "HELLO, WORLD!")
#|}
#|test "to_upper after a non-BMP character" {
#| inspect("😀x".to_upper(), content="😀X")
#| inspect("a😀xz"[1:4].to_upper(), content="😀X")
#|}
#|test "View::to_upper" {
#| assert_true("hello"[:].to_upper() == "HELLO")
#| assert_true("HELLO"[:].to_upper() == "HELLO")
#| assert_true("Hello, World!"[:].to_upper() == "HELLO, WORLD!")
#|}
#|#locals(f)
#|pub fn[A] StringView::fold(
#| self : StringView,
#| init~ : A,
#| f : (A, Char) -> A raise?,
#|) -> A raise? {
#| for c in self; rv = (init : A) {
#| continue f(rv, c)
#| } nobreak {
#| rv
#| }
#|}
#|pub fn[A] String::fold(
#| self : String,
#| init~ : A,
#| f : (A, Char) -> A raise?,
#|) -> A raise? {
#| self[:].fold(init~, f)
#|}
#|test "fold" {
#| assert_true(
#| "hello".fold(init=[], (acc, c) => {
#| acc.push(c)
#| acc
#| }) ==
#| ['h', 'e', 'l', 'l', 'o'],
#| )
#| assert_true(
#| "hello".fold(init=0, (acc, c) => acc + c.to_int()) ==
#| 104 + 101 + 108 + 108 + 111,
#| )
#|}
#|test "fold with raise" {
#| try
#| ignore(
#| "hello".fold(init=0, (acc, c) => {
#| if c == 'l' {
#| raise Failure("found l")
#| }
#| acc + 1
#| }),
#| )
#| catch {
#| e => assert_true(e is Failure("found l"))
#| } noraise {
#| _ => fail("expected fold to raise")
#| }
#|}
#|#locals(f)
#|pub fn[A] StringView::rev_fold(
#| self : StringView,
#| init~ : A,
#| f : (A, Char) -> A raise?,
#|) -> A raise? {
#| for c in self.rev_iter(); rv = (init : A) {
#| continue f(rv, c)
#| } nobreak {
#| rv
#| }
#|}
#|pub fn[A] String::rev_fold(
#| self : String,
#| init~ : A,
#| f : (A, Char) -> A raise?,
#|) -> A raise? {
#| self[:].rev_fold(init~, f)
#|}
#|test "rev_fold" {
#| assert_true(
#| "hello".rev_fold(init=[], (acc, c) => {
#| acc.push(c)
#| acc
#| }) ==
#| ['o', 'l', 'l', 'e', 'h'],
#| )
#| assert_true(
#| "hello".rev_fold(init=0, (acc, c) => acc + c.to_int()) ==
#| 111 + 108 + 108 + 101 + 104,
#| )
#|}
#|test "rev_fold with raise" {
#| try
#| ignore(
#| "hello".rev_fold(init=0, (acc, c) => {
#| if c == 'l' {
#| raise Failure("found l")
#| }
#| acc + 1
#| }),
#| )
#| catch {
#| e => assert_true(e is Failure("found l"))
#| } noraise {
#| _ => fail("expected rev_fold to raise")
#| }
#|}
#|#intrinsic("%string.get_opt")
#|pub fn String::get(self : String, idx : Int) -> UInt16? {
#| guard idx >= 0 && idx < self.length() else { return None }
#| Some(self.unsafe_get(idx))
#|}
#|#intrinsic("%stringview.get_opt")
#|pub fn StringView::get(self : StringView, idx : Int) -> UInt16? {
#| guard idx >= 0 && idx < self.length() else { return None }
#| Some(self.unsafe_get(idx))
#|}
#|test "String::get supports emoji (surrogate pair)" {
#| let s = "hello"
#| assert_true(s.get(0) is Some(104))
#| assert_true(s.get(4) is Some(111))
#| assert_true(s.get(5) is None)
#| assert_true(s.get(-1) is None)
#| let s = "a🤣b"
#| assert_true(s.get(0) is Some(97))
#| assert_true(s.get(1) is Some(55358))
#| assert_true(s.get(2) is Some(56611))
#| assert_true(s.get(3) is Some(98))
#| assert_true(s.get(4) is None)
#|}
#|test "View::get basic cases" {
#| let v = "hello"[1:4]
#| assert_true(v.get(0) is Some(101))
#| assert_true(v.get(2) is Some(108))
#| assert_true(v.get(3) is None)
#| assert_true(v.get(-1) is None)
#| let v = "ab🤣cd"[1:5]
#| assert_true(v.get(0) is Some(98))
#| assert_true(v.get(1) is Some(55358))
#| assert_true(v.get(2) is 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_get(idx)
#| if c.is_leading_surrogate() {
#| guard idx + 1 < self.length() else { return None }
#| let next = self.unsafe_get(idx + 1)
#| if next.is_trailing_surrogate() {
#| Some(code_point_of_surrogate_pair(c.to_int(), next.to_int()))
#| } else {
#| None
#| }
#| } else if c.is_trailing_surrogate() {
#| None
#| } else {
#| Some(c.unsafe_to_char())
#| }
#|}
#|pub fn StringView::get_char(self : StringView, idx : Int) -> Char? {
#| guard idx >= 0 && idx < self.length() else { return None }
#| let c = self.unsafe_get(idx)
#| if c.is_leading_surrogate() {
#| guard idx + 1 < self.length() else { return None }
#| let next = self.unsafe_get(idx + 1)
#| if next.is_trailing_surrogate() {
#| Some(code_point_of_surrogate_pair(c.to_int(), next.to_int()))
#| } else {
#| None
#| }
#| } else if c.is_trailing_surrogate() {
#| None
#| } else {
#| Some(c.unsafe_to_char())
#| }
#|}
#|test "String::get_char basic cases" {
#| let s = "hello"
#| assert_true(s.get_char(0) == Some('h'))
#| assert_true(s.get_char(1) == Some('e'))
#| assert_true(s.get_char(4) == Some('o'))
#| assert_true(s.get_char(5) == None)
#| assert_true(s.get_char(-1) == None)
#| let s = "a🤣b"
#| assert_true(s.get_char(0) == Some('a'))
#| assert_true(s.get_char(1) == Some('🤣'))
#| assert_true(s.get_char(2) == None) // Second half of surrogate pair is not a valid char
#| assert_true(s.get_char(3) == Some('b'))
#| assert_true(s.get_char(4) == None)
#|}
#|test "View::get_char basic cases" {
#| let s = "a🤣b"
#| let v = s[0:3]
#| assert_true(v.get_char(0) == Some('a'))
#| assert_true(v.get_char(1) == Some('🤣'))
#| assert_true(v.get_char(2) == None)
#| assert_true(v.get_char(3) == None)
#| assert_true(v.get_char(4) == None)
#| let v2 = s[1:3] // Only contains the emoji surrogate pair
#| assert_true(v2.get_char(0) == Some('🤣'))
#| assert_true(v2.get_char(1) == None)
#| assert_true(v2.get_char(2) == None)
#|}
),
"stringbuilder.mbt": (
#|#alias(write)
#|#alias(write_string_interpolation)
#|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)
#| }
#|}
#|pub fn StringBuilder::write_stringview(
#| self : StringBuilder,
#| view : StringView,
#|) -> Unit {
#| self.write_view(view)
#|}
),
"stringbuilder_concat.mbt": (
#|struct StringBuilder {
#| mut val : String
#|}
#|#alias(new, deprecated="Use `StringBuilder()` instead")
#|pub fn StringBuilder::StringBuilder(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 fn write_string(self, str) {
#| self.val += str
#|}
#|pub impl Logger for StringBuilder with fn write_char(self, ch) {
#| self.val += char_to_string(ch)
#|}
#|pub impl Logger for StringBuilder with fn write_view(
#| self : StringBuilder,
#| str : StringView,
#|) -> Unit {
#| self.val += str.to_owned()
#|}
#|pub impl Show for StringBuilder with fn 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 = ""
#|}
),
"stringview.mbt": (
#|fn StringView::str(self : StringView) -> String = "%stringview.str"
#|fn StringView::start(self : StringView) -> Int = "%stringview.start"
#|fn StringView::end(self : StringView) -> Int = "%stringview.end"
#|fn StringView::make_view(str : String, start : Int, end : Int) -> StringView = "%stringview.make"
#|#intrinsic("%stringview.get")
#|#alias("_[_]")
#|#alias(code_unit_at)
#|pub fn StringView::at(self : StringView, index : Int) -> UInt16 {
#| guard index >= 0 && index < self.length() else {
#| index_out_of_bounds(self.length(), index)
#| }
#| self.unsafe_get(index)
#|}
#|#intrinsic("%stringview.length")
#|pub fn StringView::length(self : StringView) -> Int {
#| self.end() - self.start()
#|}
#|pub fn StringView::suffixes(
#| self : StringView,
#| include_empty? : Bool = false,
#|) -> Iter[StringView] {
#| let str = self.str()
#| let end = self.end()
#| let mut next_start = self.start()
#| let mut finished = false
#| Iter::new(fn() -> StringView? {
#| if finished {
#| None
#| } else if next_start == end {
#| finished = true
#| if include_empty {
#| Some(StringView::make_view(str, next_start, end))
#| } else {
#| None
#| }
#| } else {
#| let suffix = StringView::make_view(str, next_start, end)
#| let code = str.unsafe_get(next_start)
#| if code.is_leading_surrogate() &&
#| next_start + 1 < end &&
#| str.unsafe_get(next_start + 1).is_trailing_surrogate() {
#| next_start += 2
#| } else {
#| next_start += 1
#| }
#| Some(suffix)
#| }
#| })
#|}
#|pub fn StringView::data(self : StringView) -> String {
#| self.str()
#|}
#|pub fn StringView::start_offset(self : StringView) -> Int {
#| self.start()
#|}
#|#intrinsic("%stringview.unsafe_get")
#|#internal(unsafe, "Undefined behavior if index is out of bounds.")
#|pub fn StringView::unsafe_get(self : StringView, index : Int) -> UInt16 {
#| self.str().unsafe_get(self.start() + index)
#|}
#|#intrinsic("%stringview.code_units")
#|pub fn StringView::code_units(self : StringView) -> ArrayView[UInt16] {
#| FixedArray::makei(self.str().length(), i => self.str().unsafe_get(i))[self.start():self.end()]
#|}
#|#deprecated("Use `StringView::unsafe_get` instead")
#|pub fn StringView::unsafe_charcode_at(self : StringView, index : Int) -> Int {
#| self.str().unsafe_get(self.start() + index).to_int()
#|}
#|pub fn StringView::char_length(self : StringView) -> Int {
#| self.str().char_length(start_offset=self.start(), end_offset=self.end())
#|}
#|#alias(to_string, deprecated="Use `to_owned` to allocate an owned String from a StringView; use `Show::to_string` or format strings for display")
#|pub fn StringView::to_owned(self : StringView) -> String {
#| self.str().unsafe_substring(start=self.start(), end=self.end())
#|}
#|pub impl Show for StringView with fn output(self, logger) {
#| logger.write_view(self)
#|}
#|pub impl Show for StringView with fn to_string(self) {
#| self.to_owned()
#|}
#|#alias(iterator, deprecated)
#|pub fn StringView::iter(self : StringView) -> Iter[Char] {
#| let start = self.start()
#| let end = self.end()
#| let mut index = start
#| Iter::new(fn() {
#| guard index < end else { None }
#| let c1 = self.str().unsafe_get(index)
#| if c1.is_leading_surrogate() && index + 1 < self.end() {
#| let c2 = self.str().unsafe_get(index + 1)
#| if c2.is_trailing_surrogate() {
#| index += 2
#| return Some(code_point_of_surrogate_pair(c1.to_int(), c2.to_int()))
#| }
#| }
#| index += 1
#| Some(c1.unsafe_to_char())
#| })
#|}
#|#alias(iterator2, deprecated)
#|pub fn StringView::iter2(self : StringView) -> Iter2[Int, Char] {
#| let start = self.start()
#| let end = self.end()
#| let mut index = start
#| let mut char_index = 0
#| Iter2::new(fn() {
#| guard index < end else { None }
#| let c1 = self.str().unsafe_get(index)
#| if c1.is_leading_surrogate() && index + 1 < self.end() {
#| let c2 = self.str().unsafe_get(index + 1)
#| if c2.is_trailing_surrogate() {
#| let result = (
#| char_index,
#| code_point_of_surrogate_pair(c1.to_int(), c2.to_int()),
#| )
#| index += 2
#| char_index += 1
#| return Some(result)
#| }
#| }
#| let result = (char_index, c1.unsafe_to_char())
#| index += 1
#| char_index += 1
#| Some(result)
#| })
#|}
#|#alias(rev_iterator, deprecated)
#|pub fn StringView::rev_iter(self : StringView) -> Iter[Char] {
#| let start = self.start()
#| let end = self.end()
#| let mut index = end
#| Iter::new(fn() {
#| guard index > start else { None }
#| index -= 1
#| let c1 = self.str().unsafe_get(index)
#| if c1.is_trailing_surrogate() && index - 1 >= 0 {
#| let c2 = self.str().unsafe_get(index - 1)
#| if c2.is_leading_surrogate() {
#| index -= 1
#| return Some(code_point_of_surrogate_pair(c2.to_int(), c1.to_int()))
#| }
#| }
#| Some(c1.unsafe_to_char())
#| })
#|}
#|#locals(f)
#|#alias(every)
#|pub fn StringView::all(
#| self : StringView,
#| f : (Char) -> Bool raise?,
#|) -> Bool raise? {
#| for c in self {
#| if !f(c) {
#| return false
#| }
#| }
#| true
#|}
#|#locals(f)
#|#alias(exists)
#|pub fn StringView::any(
#| self : StringView,
#| f : (Char) -> Bool raise?,
#|) -> Bool raise? {
#| for c in self {
#| if f(c) {
#| return true
#| }
#| }
#| false
#|}
#|pub impl Eq for StringView with fn 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
#| }
#| self
#| .str()
#| .unsafe_range_equal(
#| other.str(),
#| self_off=self.start(),
#| other_off=other.start(),
#| len~,
#| )
#|}
#|pub fn StringView::equal_to_string(self : StringView, other : String) -> Bool {
#| let len = self.length()
#| guard len == other.length() else { return false }
#| if physical_equal(self.str(), other) && self.start() == 0 {
#| return true
#| }
#| self.str().unsafe_range_equal(other, self_off=self.start(), other_off=0, len~)
#|}
#|pub impl Compare for StringView with fn compare(self, other) {
#| let self_len = self.length()
#| let other_len = other.length()
#| let cmp = self_len.compare(other_len)
#| guard cmp == 0 else { return cmp }
#| if physical_equal(self.str(), other.str()) && self.start() == other.start() {
#| return 0
#| }
#| for i in 0.. Int {
#| let self_len = self.length()
#| let other_len = other.length()
#| let min_len = if self_len < other_len { self_len } else { other_len }
#| for i in 0.. UInt16 {
#| if c >= ('A' : UInt16) && c <= ('Z' : UInt16) {
#| c + (32 : UInt16)
#| } else {
#| c
#| }
#|}
#|pub fn StringView::compare_ignore_ascii_case(
#| self : StringView,
#| other : StringView,
#|) -> Int {
#| let self_len = self.length()
#| let other_len = other.length()
#| let min_len = if self_len < other_len { self_len } else { other_len }
#| for i in 0.. Bool {
#| let len = self.length()
#| if len != other.length() {
#| return false
#| }
#| for i in 0.. StringView {
#| String::from_array(chars)
#|}
#|#alias(from_iterator, deprecated)
#|pub fn StringView::from_iter(iter : Iter[Char]) -> StringView {
#| String::from_iter(iter)
#|}
#|pub fn String::get_view(
#| self : String,
#| start? : Int = 0,
#| end? : Int,
#|) -> StringView? {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else { None }
#| if start < len && self.unsafe_get(start).is_trailing_surrogate() {
#| return None
#| }
#| if end < len && self.unsafe_get(end).is_trailing_surrogate() {
#| return None
#| }
#| Some(StringView::make_view(self, start, end))
#|}
#|pub fn StringView::get_view(
#| self : StringView,
#| start? : Int = 0,
#| end? : Int,
#|) -> StringView? {
#| let str_len = self.str().length()
#| let abs_end = match end {
#| None => self.end()
#| Some(end) => self.start() + end
#| }
#| let abs_start = self.start() + start
#| guard abs_start >= self.start() &&
#| abs_start <= abs_end &&
#| abs_end <= self.end() else {
#| None
#| }
#| if abs_start < str_len &&
#| self.str().unsafe_get(abs_start).is_trailing_surrogate() {
#| return None
#| }
#| if abs_end < str_len && self.str().unsafe_get(abs_end).is_trailing_surrogate() {
#| return None
#| }
#| Some(StringView::make_view(self.str(), abs_start, abs_end))
#|}
#|#alias("_[_:_]")
#|pub fn String::clamped_view(
#| self : String,
#| start? : Int = 0,
#| end? : Int,
#|) -> StringView {
#| let len = self.length()
#| let mut lo = if start < 0 { 0 } else if start > len { len } else { start }
#| let mut hi = match end {
#| None => len
#| Some(e) => if e < 0 { 0 } else if e > len { len } else { e }
#| }
#| if lo > 0 &&
#| lo < len &&
#| self.unsafe_get(lo).is_trailing_surrogate() &&
#| self.unsafe_get(lo - 1).is_leading_surrogate() {
#| lo += 1
#| }
#| if hi > 0 &&
#| hi < len &&
#| self.unsafe_get(hi).is_trailing_surrogate() &&
#| self.unsafe_get(hi - 1).is_leading_surrogate() {
#| hi -= 1
#| }
#| if lo >= hi {
#| StringView::make_view(self, lo, lo)
#| } else {
#| StringView::make_view(self, lo, hi)
#| }
#|}
#|#alias("_[_:_]")
#|pub fn StringView::clamped_view(
#| self : StringView,
#| start? : Int = 0,
#| end? : Int,
#|) -> StringView {
#| let len = self.length()
#| let mut lo = if start < 0 { 0 } else if start > len { len } else { start }
#| let mut hi = match end {
#| None => len
#| Some(e) => if e < 0 { 0 } else if e > len { len } else { e }
#| }
#| let str = self.str()
#| let base = self.start()
#| if lo > 0 &&
#| lo < len &&
#| str.unsafe_get(base + lo).is_trailing_surrogate() &&
#| str.unsafe_get(base + lo - 1).is_leading_surrogate() {
#| lo += 1
#| }
#| if hi > 0 &&
#| hi < len &&
#| str.unsafe_get(base + hi).is_trailing_surrogate() &&
#| str.unsafe_get(base + hi - 1).is_leading_surrogate() {
#| hi -= 1
#| }
#| if lo >= hi {
#| StringView::make_view(str, base + lo, base + lo)
#| } else {
#| StringView::make_view(str, base + lo, base + hi)
#| }
#|}
#|pub fn String::split_at(self : String, at : Int) -> (StringView, StringView) {
#| let len = self.length()
#| let mut cut = if at < 0 { 0 } else if at > len { len } else { at }
#| if cut > 0 &&
#| cut < len &&
#| self.unsafe_get(cut).is_trailing_surrogate() &&
#| self.unsafe_get(cut - 1).is_leading_surrogate() {
#| cut -= 1
#| }
#| (StringView::make_view(self, 0, cut), StringView::make_view(self, cut, len))
#|}
#|pub fn StringView::split_at(
#| self : StringView,
#| at : Int,
#|) -> (StringView, StringView) {
#| let len = self.length()
#| let mut cut = if at < 0 { 0 } else if at > len { len } else { at }
#| let str = self.str()
#| let base = self.start()
#| if cut > 0 &&
#| cut < len &&
#| str.unsafe_get(base + cut).is_trailing_surrogate() &&
#| str.unsafe_get(base + cut - 1).is_leading_surrogate() {
#| cut -= 1
#| }
#| (
#| StringView::make_view(str, base, base + cut),
#| StringView::make_view(str, base + cut, self.end()),
#| )
#|}
#|#alias(sub, deprecated="Use `exact_view` instead")
#|pub fn String::exact_view(
#| self : String,
#| start? : Int = 0,
#| end? : Int,
#|) -> StringView {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard! start >= 0 && start <= end && end <= len
#| if start < len {
#| guard! !self.unsafe_get(start).is_trailing_surrogate()
#| }
#| if end < len {
#| guard! !self.unsafe_get(end).is_trailing_surrogate()
#| }
#| StringView::make_view(self, start, end)
#|}
#|#alias(sub, deprecated="Use `exact_view` instead")
#|pub fn StringView::exact_view(
#| self : StringView,
#| start? : Int = 0,
#| end? : Int,
#|) -> StringView {
#| let str_len = self.str().length()
#| let abs_end = match end {
#| None => self.end()
#| Some(end) => self.start() + end
#| }
#| let abs_start = self.start() + start
#| guard! abs_start >= self.start() &&
#| abs_start <= abs_end &&
#| abs_end <= self.end()
#| if abs_start < str_len {
#| guard! !self.str().unsafe_get(abs_start).is_trailing_surrogate()
#| }
#| if abs_end < str_len {
#| guard! !self.str().unsafe_get(abs_end).is_trailing_surrogate()
#| }
#| StringView::make_view(self.str(), abs_start, abs_end)
#|}
#|pub fn StringView::char_length_eq(self : StringView, len : Int) -> Bool {
#| self
#| .str()
#| .char_length_eq(len, start_offset=self.start(), end_offset=self.end())
#|}
#|pub fn StringView::char_length_ge(self : StringView, len : Int) -> Bool {
#| self
#| .str()
#| .char_length_ge(len, start_offset=self.start(), end_offset=self.end())
#|}
#|pub fn StringView::offset_of_nth_char(self : StringView, 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 impl Default for StringView with fn default() {
#| ""
#|}
#|pub fn StringView::make(length : Int, value : Char) -> StringView {
#| String::make(length, value)
#|}
#|pub impl ToJson for StringView with fn to_json(self) {
#| String::to_json(self.to_owned())
#|}
#|pub impl Add for StringView with fn add(self, other) {
#| [..self, ..other]
#|}
#|pub fn StringView::view(
#| self : StringView,
#| start_offset? : Int = 0,
#| end_offset? : Int,
#|) -> StringView {
#| 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")
#| }
#| StringView::make_view(
#| self.str(),
#| self.start() + start_offset,
#| self.start() + end_offset,
#| )
#|}
#|pub fn String::view(
#| self : String,
#| start_offset? : Int = 0,
#| end_offset? : Int,
#|) -> StringView {
#| 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")
#| }
#| StringView::make_view(self, start_offset, end_offset)
#|}
),
"to_string.mbt": (
#|#cfg(not(target="js"))
#|const ALPHABET : String = "0123456789abcdefghijklmnopqrstuvwxyz"
#|#cfg(not(target="js"))
#|fn unsafe_fixedarray_uint16_to_string(buffer : FixedArray[UInt16]) -> String = "%string.unsafe_from_uint16_fixedarray"
#|#cfg(not(target="js"))
#|fn int_to_string_hex(
#| buffer : FixedArray[UInt16],
#| num : UInt,
#| digit_start : Int,
#| total_len : Int,
#|) -> Unit {
#| let (offset, n) = for offset = total_len - digit_start, n = num; offset >= 2; {
#| let byte_val = n.land(0xFFU).reinterpret_as_int()
#| let hi = byte_val / 16
#| let lo = byte_val % 16
#| buffer.unsafe_set(digit_start + offset - 2, ALPHABET.unsafe_get(hi))
#| buffer.unsafe_set(digit_start + offset - 1, ALPHABET.unsafe_get(lo))
#| continue offset - 2, n >> 8
#| } nobreak {
#| (offset, n)
#| }
#| if offset == 1 {
#| let nibble = n.land(0xFU).reinterpret_as_int()
#| buffer.unsafe_set(digit_start, ALPHABET.unsafe_get(nibble))
#| }
#|}
#|#cfg(not(target="js"))
#|fn int_to_string_generic(
#| buffer : FixedArray[UInt16],
#| num : UInt,
#| digit_start : Int,
#| total_len : Int,
#| radix : Int,
#|) -> Unit {
#| let base = radix.reinterpret_as_uint()
#| if (radix & (radix - 1)) == 0 {
#| let shift = radix.ctz()
#| let mask = base - 1U
#| for offset = total_len - digit_start, n = num; n > 0U; {
#| let digit = n.land(mask).reinterpret_as_int()
#| buffer.unsafe_set(digit_start + offset - 1, ALPHABET.unsafe_get(digit))
#| continue offset - 1, n >> shift
#| }
#| } else {
#| for offset = total_len - digit_start, n = num; n > 0U; {
#| let q = n / base
#| let digit = (n - q * base).reinterpret_as_int()
#| buffer.unsafe_set(digit_start + offset - 1, ALPHABET.unsafe_get(digit))
#| continue offset - 1, q
#| }
#| }
#|}
#|#cfg(not(target="js"))
#|fn int_to_string_dec(
#| buffer : FixedArray[UInt16],
#| num : UInt,
#| digit_start : Int,
#| total_len : Int,
#|) -> Unit {
#| let (num, offset) = for num = num, offset = total_len - digit_start; num >=
#| 10000U; {
#| let t = num / 10000U
#| let r = (num % 10000U).reinterpret_as_int()
#| let d1 = r / 100
#| let d2 = r % 100
#| let d1_hi = (0x30 + d1 / 10).to_uint16()
#| let d1_lo = (0x30 + d1 % 10).to_uint16()
#| let d2_hi = (0x30 + d2 / 10).to_uint16()
#| let d2_lo = (0x30 + d2 % 10).to_uint16()
#| buffer.unsafe_set(digit_start + offset - 4, d1_hi)
#| buffer.unsafe_set(digit_start + offset - 3, d1_lo)
#| buffer.unsafe_set(digit_start + offset - 2, d2_hi)
#| buffer.unsafe_set(digit_start + offset - 1, d2_lo)
#| continue t, offset - 4
#| } nobreak {
#| (num, offset)
#| }
#| let (remaining, offset) = for remaining = num.reinterpret_as_int(), offset = offset; remaining >=
#| 100; {
#| let t = remaining / 100
#| let d = remaining % 100
#| let d_hi = (0x30 + d / 10).to_uint16()
#| let d_lo = (0x30 + d % 10).to_uint16()
#| buffer.unsafe_set(digit_start + offset - 2, d_hi)
#| buffer.unsafe_set(digit_start + offset - 1, d_lo)
#| continue t, offset - 2
#| } nobreak {
#| (remaining, offset)
#| }
#| if remaining >= 10 {
#| let d_hi = (0x30 + remaining / 10).to_uint16()
#| let d_lo = (0x30 + remaining % 10).to_uint16()
#| buffer.unsafe_set(digit_start + offset - 2, d_hi)
#| buffer.unsafe_set(digit_start + offset - 1, d_lo)
#| } else {
#| buffer.unsafe_set(digit_start + offset - 1, (0x30 + remaining).to_uint16())
#| }
#|}
#|#cfg(not(target="js"))
#|fn dec_count32(value : UInt) -> Int {
#| if value >= 100000U { // >= 10^5 means 6+ digits
#| if value >= 10000000U { // >= 10^7 means 8+ digits
#| if value >= 1000000000U { // >= 10^9 means 10 digits
#| 10
#| } else if value >= 100000000U { // >= 10^8 means 9 digits
#| 9
#| } else {
#| 8
#| }
#| } else if value >= 1000000U { // >= 10^6 means 7 digits
#| 7
#| } else {
#| 6
#| }
#| } else if value >= 1000U { // >= 10^3 means 4+ digits
#| if value >= 10000U { // >= 10^4 means 5 digits
#| 5
#| } else {
#| 4
#| }
#| } else if value >= 100U { // >= 10^2 means 3 digits
#| 3
#| } else if value >= 10U { // >= 10^1 means 2 digits
#| 2
#| } else {
#| 1
#| }
#|}
#|#cfg(not(target="js"))
#|fn hex_count32(value : UInt) -> Int {
#| if value == 0U {
#| 1
#| } else {
#| let leading_zeros = value.clz()
#| (31 - leading_zeros) / 4 + 1
#| }
#|}
#|#cfg(not(target="js"))
#|fn radix_count32(value : UInt, radix : Int) -> Int {
#| if value == 0U {
#| return 1
#| }
#| let base = radix.reinterpret_as_uint()
#| for num = value, count = 0; num > 0U; {
#| continue num / base, count + 1
#| } nobreak {
#| count
#| }
#|}
#|#cfg(not(target="js"))
#|pub fn Int::to_string(self : Int, radix? : Int = 10) -> String {
#| if radix < 2 || radix > 36 {
#| abort("radix must be between 2 and 36")
#| }
#| if self == 0 {
#| return "0"
#| }
#| let is_negative = self < 0
#| let num : UInt = if is_negative {
#| (-self).reinterpret_as_uint()
#| } else {
#| self.reinterpret_as_uint()
#| }
#| let buffer = match radix {
#| 10 => {
#| let digit_len = dec_count32(num)
#| let total_len = digit_len + (if is_negative { 1 } else { 0 })
#| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0)
#| let digit_start = if is_negative { 1 } else { 0 }
#| int_to_string_dec(buffer, num, digit_start, total_len)
#| buffer
#| }
#| 16 => {
#| let digit_len = hex_count32(num)
#| let total_len = digit_len + (if is_negative { 1 } else { 0 })
#| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0)
#| let digit_start = if is_negative { 1 } else { 0 }
#| int_to_string_hex(buffer, num, digit_start, total_len)
#| buffer
#| }
#| _ => {
#| let digit_len = radix_count32(num, radix)
#| let total_len = digit_len + (if is_negative { 1 } else { 0 })
#| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0)
#| let digit_start = if is_negative { 1 } else { 0 }
#| int_to_string_generic(buffer, num, digit_start, total_len, radix)
#| buffer
#| }
#| }
#| if is_negative {
#| buffer.unsafe_set(0, 0x002D)
#| }
#| unsafe_fixedarray_uint16_to_string(buffer)
#|}
#|#cfg(not(target="js"))
#|pub fn UInt::to_string(self : UInt, radix? : Int = 10) -> String {
#| if radix < 2 || radix > 36 {
#| abort("radix must be between 2 and 36")
#| }
#| if self == 0U {
#| return "0"
#| }
#| let buffer = match radix {
#| 10 => {
#| let len = dec_count32(self)
#| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0)
#| int_to_string_dec(buffer, self, 0, len)
#| buffer
#| }
#| 16 => {
#| let len = hex_count32(self)
#| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0)
#| int_to_string_hex(buffer, self, 0, len)
#| buffer
#| }
#| _ => {
#| let len = radix_count32(self, radix)
#| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0)
#| int_to_string_generic(buffer, self, 0, len, radix)
#| buffer
#| }
#| }
#| unsafe_fixedarray_uint16_to_string(buffer)
#|}
#|#cfg(target="js")
#|pub fn Int::to_string(self : Int, radix? : Int = 10) -> String {
#| int_to_string_js(self, radix)
#|}
#|#cfg(target="js")
#|extern "js" fn int_to_string_js(i : Int, radix : Int) -> String =
#| #|(x, radix) => {
#| #| return x.toString(radix);
#| #|}
#|#cfg(target="js")
#|pub fn UInt::to_string(self : UInt, radix? : Int = 10) -> String {
#| uint_to_string_js(self, radix)
#|}
#|#cfg(target="js")
#|extern "js" fn uint_to_string_js(i : UInt, radix : Int) -> String =
#| #|(x, radix) => {
#| #| return (x >>> 0).toString(radix);
#| #|}
#|#cfg(not(target="js"))
#|fn dec_count64(value : UInt64) -> Int {
#| if value >= 10000000000UL { // >= 10^10 means 11+ digits
#| if value >= 100000000000000UL { // >= 10^14 means 15+ digits
#| if value >= 10000000000000000UL { // >= 10^16 means 17+ digits
#| if value >= 1000000000000000000UL { // >= 10^18 means 19+ digits
#| if value >= 10000000000000000000UL { // >= 10^19 means 20 digits
#| 20
#| } else {
#| 19
#| }
#| } else if value >= 100000000000000000UL { // >= 10^17 means 18 digits
#| 18
#| } else {
#| 17
#| }
#| } else if value >= 1000000000000000UL { // >= 10^15 means 16 digits
#| 16
#| } else {
#| 15
#| }
#| } else if value >= 1000000000000UL { // >= 10^12 means 13+ digits
#| if value >= 10000000000000UL { // >= 10^13 means 14 digits
#| 14
#| } else {
#| 13
#| }
#| } else if value >= 100000000000UL { // >= 10^11 means 12 digits
#| 12
#| } else {
#| 11
#| }
#| } else if value >= 100000UL { // >= 10^5 means 6+ digits
#| if value >= 10000000UL { // >= 10^7 means 8+ digits
#| if value >= 1000000000UL { // >= 10^9 means 10 digits
#| 10
#| } else if value >= 100000000UL { // >= 10^8 means 9 digits
#| 9
#| } else {
#| 8
#| }
#| } else if value >= 1000000UL { // >= 10^6 means 7 digits
#| 7
#| } else {
#| 6
#| }
#| } else if value >= 1000UL { // >= 10^3 means 4+ digits
#| if value >= 10000UL { // >= 10^4 means 5 digits
#| 5
#| } else {
#| 4
#| }
#| } else if value >= 100UL { // >= 10^2 means 3 digits
#| 3
#| } else if value >= 10UL { // >= 10^1 means 2 digits
#| 2
#| } else {
#| 1
#| }
#|}
#|#cfg(not(target="js"))
#|fn hex_count64(value : UInt64) -> Int {
#| if value == 0UL {
#| 1
#| } else {
#| let leading_zeros = value.clz()
#| (63 - leading_zeros) / 4 + 1
#| }
#|}
#|#cfg(not(target="js"))
#|fn radix_count64(value : UInt64, radix : Int) -> Int {
#| if value == 0UL {
#| return 1
#| }
#| let base = radix.to_uint64()
#| for num = value, count = 0; num > 0UL; {
#| continue num / base, count + 1
#| } nobreak {
#| count
#| }
#|}
#|#cfg(not(target="js"))
#|fn int64_to_string_hex(
#| buffer : FixedArray[UInt16],
#| num : UInt64,
#| digit_start : Int,
#| total_len : Int,
#|) -> Unit {
#| let (offset, n) = for offset = total_len - digit_start, n = num; offset >= 2; {
#| let byte_val = n.land(0xFFUL).to_int()
#| let hi = byte_val / 16
#| let lo = byte_val % 16
#| buffer.unsafe_set(digit_start + offset - 2, ALPHABET.unsafe_get(hi))
#| buffer.unsafe_set(digit_start + offset - 1, ALPHABET.unsafe_get(lo))
#| continue offset - 2, n >> 8
#| } nobreak {
#| (offset, n)
#| }
#| if offset == 1 {
#| let nibble = n.land(0xFUL).to_int()
#| buffer.unsafe_set(digit_start, ALPHABET.unsafe_get(nibble))
#| }
#|}
#|#cfg(not(target="js"))
#|fn int64_to_string_generic(
#| buffer : FixedArray[UInt16],
#| num : UInt64,
#| digit_start : Int,
#| total_len : Int,
#| radix : Int,
#|) -> Unit {
#| let base = radix.to_uint64()
#| if (radix & (radix - 1)) == 0 {
#| let shift = radix.ctz()
#| let mask = base - 1UL
#| for offset = total_len - digit_start, n = num; n > 0UL; {
#| let digit = n.land(mask).to_int()
#| buffer.unsafe_set(digit_start + offset - 1, ALPHABET.unsafe_get(digit))
#| continue offset - 1, n >> shift
#| }
#| } else {
#| for offset = total_len - digit_start, n = num; n > 0UL; {
#| let q = n / base
#| let digit = (n - q * base).to_int()
#| buffer.unsafe_set(digit_start + offset - 1, ALPHABET.unsafe_get(digit))
#| continue offset - 1, q
#| }
#| }
#|}
#|#cfg(not(target="js"))
#|fn int64_to_string_dec(
#| buffer : FixedArray[UInt16],
#| num : UInt64,
#| digit_start : Int,
#| total_len : Int,
#|) -> Unit {
#| let (num, offset) = for num = num, offset = total_len - digit_start; num >=
#| 10000UL; {
#| let t = num / 10000UL
#| let r = (num % 10000UL).to_int()
#| let d1 = r / 100
#| let d2 = r % 100
#| let d1_hi = (0x30 + d1 / 10).to_uint16()
#| let d1_lo = (0x30 + d1 % 10).to_uint16()
#| let d2_hi = (0x30 + d2 / 10).to_uint16()
#| let d2_lo = (0x30 + d2 % 10).to_uint16()
#| buffer.unsafe_set(digit_start + offset - 4, d1_hi)
#| buffer.unsafe_set(digit_start + offset - 3, d1_lo)
#| buffer.unsafe_set(digit_start + offset - 2, d2_hi)
#| buffer.unsafe_set(digit_start + offset - 1, d2_lo)
#| continue t, offset - 4
#| } nobreak {
#| (num, offset)
#| }
#| let (remaining, offset) = for remaining = num.to_int(), offset = offset; remaining >=
#| 100; {
#| let t = remaining / 100
#| let d = remaining % 100
#| let d_hi = (0x30 + d / 10).to_uint16()
#| let d_lo = (0x30 + d % 10).to_uint16()
#| buffer.unsafe_set(digit_start + offset - 2, d_hi)
#| buffer.unsafe_set(digit_start + offset - 1, d_lo)
#| continue t, offset - 2
#| } nobreak {
#| (remaining, offset)
#| }
#| if remaining >= 10 {
#| let d_hi = (0x30 + remaining / 10).to_uint16()
#| let d_lo = (0x30 + remaining % 10).to_uint16()
#| buffer.unsafe_set(digit_start + offset - 2, d_hi)
#| buffer.unsafe_set(digit_start + offset - 1, d_lo)
#| } else {
#| buffer.unsafe_set(digit_start + offset - 1, (0x30 + remaining).to_uint16())
#| }
#|}
#|#cfg(not(target="js"))
#|pub fn Int64::to_string(self : Int64, radix? : Int = 10) -> String {
#| if radix < 2 || radix > 36 {
#| abort("radix must be between 2 and 36")
#| }
#| if self == 0L {
#| return "0"
#| }
#| let is_negative = self < 0L
#| let num : UInt64 = if is_negative {
#| (-self).reinterpret_as_uint64()
#| } else {
#| self.reinterpret_as_uint64()
#| }
#| let buffer = match radix {
#| 10 => {
#| let digit_len = dec_count64(num)
#| let total_len = digit_len + (if is_negative { 1 } else { 0 })
#| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0)
#| let digit_start = if is_negative { 1 } else { 0 }
#| int64_to_string_dec(buffer, num, digit_start, total_len)
#| buffer
#| }
#| 16 => {
#| let digit_len = hex_count64(num)
#| let total_len = digit_len + (if is_negative { 1 } else { 0 })
#| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0)
#| let digit_start = if is_negative { 1 } else { 0 }
#| int64_to_string_hex(buffer, num, digit_start, total_len)
#| buffer
#| }
#| _ => {
#| let digit_len = radix_count64(num, radix)
#| let total_len = digit_len + (if is_negative { 1 } else { 0 })
#| let buffer : FixedArray[UInt16] = FixedArray::make(total_len, 0)
#| let digit_start = if is_negative { 1 } else { 0 }
#| int64_to_string_generic(buffer, num, digit_start, total_len, radix)
#| buffer
#| }
#| }
#| if is_negative {
#| buffer.unsafe_set(0, 0x002D)
#| }
#| unsafe_fixedarray_uint16_to_string(buffer)
#|}
#|#cfg(not(target="js"))
#|pub fn UInt64::to_string(self : UInt64, radix? : Int = 10) -> String {
#| if radix < 2 || radix > 36 {
#| abort("radix must be between 2 and 36")
#| }
#| if self == 0UL {
#| return "0"
#| }
#| let buffer = match radix {
#| 10 => {
#| let len = dec_count64(self)
#| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0)
#| int64_to_string_dec(buffer, self, 0, len)
#| buffer
#| }
#| 16 => {
#| let len = hex_count64(self)
#| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0)
#| int64_to_string_hex(buffer, self, 0, len)
#| buffer
#| }
#| _ => {
#| let len = radix_count64(self, radix)
#| let buffer : FixedArray[UInt16] = FixedArray::make(len, 0)
#| int64_to_string_generic(buffer, self, 0, len, radix)
#| buffer
#| }
#| }
#| unsafe_fixedarray_uint16_to_string(buffer)
#|}
#|#cfg(target="js")
#|pub fn Int64::to_string(self : Int64, radix? : Int = 10) -> String {
#| int64_to_string_js(self, radix)
#|}
#|#cfg(target="js")
#|extern "js" fn int64_to_string_js(num : Int64, radix : Int) -> String =
#| #|(num, radix) => BigInt.asIntN(64, num).toString(radix)
#|#cfg(target="js")
#|pub fn UInt64::to_string(self : UInt64, radix? : Int = 10) -> String {
#| uint64_to_string_js(self, radix)
#|}
#|#cfg(target="js")
#|extern "js" fn uint64_to_string_js(num : UInt64, radix : Int) -> String =
#| #|(num, radix) => num.toString(radix)
#|pub fn UInt16::to_string(self : UInt16, radix? : Int = 10) -> String {
#| self.to_int().to_string(radix~)
#|}
#|test "UInt::to_string" {
#| inspect(0U, content="0")
#| inspect(17U, content="17")
#| inspect(4294967295U, content="4294967295")
#|}
#|test "to_string" {
#| assert_true((0x100).to_string() == "256")
#| assert_true("\{0x100}" == "256")
#| assert_true(0x200U.to_string() == "512")
#| assert_true("\{0x200U}" == "512")
#| assert_true(0x300L.to_string() == "768")
#| assert_true("\{0x300L}" == "768")
#| assert_true(0x400UL.to_string() == "1024")
#| assert_true("\{0x400UL}" == "1024")
#|}
#|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 {
#| fn equal(Self, Self) -> Bool
#| fn not_equal(Self, Self) -> Bool = _
#|}
#|impl Eq with fn not_equal(x, y) {
#| !(x == y)
#|}
#|pub(open) trait Compare: Eq {
#| fn compare(Self, Self) -> Int
#| fn op_lt(Self, Self) -> Bool = _
#| fn op_gt(Self, Self) -> Bool = _
#| fn op_le(Self, Self) -> Bool = _
#| fn op_ge(Self, Self) -> Bool = _
#|}
#|impl Compare with fn op_lt(x, y) {
#| x.compare(y).is_neg()
#|}
#|impl Compare with fn op_gt(x, y) {
#| x.compare(y).is_pos()
#|}
#|impl Compare with fn op_le(x, y) {
#| x.compare(y).is_non_pos()
#|}
#|impl Compare with fn op_ge(x, y) {
#| x.compare(y).is_non_neg()
#|}
#|pub(open) trait Hash {
#| fn hash_combine(Self, Hasher) -> Unit
#| fn hash(Self) -> Int = _
#|}
#|impl Hash with fn hash(self) {
#| let h = Hasher()
#| h.combine(self)
#| h.finalize()
#|}
#|pub(open) trait Default {
#| fn default() -> Self
#|}
#|#must_implement_one(write_view, write_substring)
#|pub(open) trait Logger {
#| fn write_string(Self, String) -> Unit = _
#| #deprecated("use `write_view` instead", skip_current_package=true)
#| fn write_substring(Self, String, Int, Int) -> Unit = _
#| fn write_view(Self, StringView) -> Unit = _
#| fn write_char(Self, Char) -> Unit = _
#| fn write_string_interpolation(Self, &Show) -> Unit = _
#| fn write(Self, &Show) -> Unit = _
#|}
#|impl Logger with fn write_string_interpolation(self, show) {
#| show.output(self)
#|}
#|impl Logger with fn write(self, show) {
#| show.output(self)
#|}
#|impl Logger with fn write_substring(self, value, start, len) {
#| self.write_view(value[start:start + len])
#|}
#|impl Logger with fn write_string(self, value) {
#| self.write_view(value)
#|}
#|#deprecated("replace `impl write_substring` with `impl write_view`")
#|impl Logger with fn write_view(self, value) {
#| self.write_substring(value.data(), value.start_offset(), value.length())
#|}
#|impl Logger with fn write_char(self, value) {
#| self.write_string([value])
#|}
#|#must_implement_one(output, to_string)
#|pub(open) trait Show {
#| fn output(Self, &Logger) -> Unit = _
#| fn to_string(Self) -> String = _
#|}
#|impl Show with fn output(self, logger) {
#| logger.write_string(self.to_string())
#|}
#|impl Show with fn to_string(self) {
#| let logger = StringBuilder()
#| 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 if iter.next() is Some(x) {
#| self.write_object(x)
#| for x in iter {
#| self.write_string(sep)
#| self.write_object(x)
#| }
#| }
#| self.write_string(suffix)
#|}
),
"tuple_compare.mbt": (
#|pub impl[T0 : Compare, T1 : Compare] Compare for (T0, T1) with fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn hash_combine(self, hasher) {
#| let (a, b) = self
#| hasher.combine(a)
#| hasher.combine(b)
#|}
#|pub impl[A : Hash, B : Hash, C : Hash] Hash for (A, B, C) with fn hash_combine(
#| self,
#| hasher,
#|) {
#| let (a, b, c) = self
#| hasher.combine(a)
#| hasher.combine(b)
#| hasher.combine(c)
#|}
#|pub impl[A : Hash, B : Hash, C : Hash, D : Hash] Hash for (A, B, C, D) with fn hash_combine(
#| self,
#| hasher,
#|) {
#| let (a, b, c, d) = self
#| hasher.combine(a)
#| hasher.combine(b)
#| hasher.combine(c)
#| hasher.combine(d)
#|}
#|pub impl[A : Hash, B : Hash, C : Hash, D : Hash, E : Hash] Hash for (
#| A,
#| B,
#| C,
#| D,
#| E,
#|) with fn hash_combine(self, hasher) {
#| let (a, b, c, d, e) = self
#| hasher.combine(a)
#| hasher.combine(b)
#| hasher.combine(c)
#| hasher.combine(d)
#| hasher.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 fn hash_combine(self, hasher) {
#| let (a, b, c, d, e, f) = self
#| hasher.combine(a)
#| hasher.combine(b)
#| hasher.combine(c)
#| hasher.combine(d)
#| hasher.combine(e)
#| hasher.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 fn hash_combine(self, hasher) {
#| let (a, b, c, d, e, f, g) = self
#| hasher.combine(a)
#| hasher.combine(b)
#| hasher.combine(c)
#| hasher.combine(d)
#| hasher.combine(e)
#| hasher.combine(f)
#| hasher.combine(g)
#|}
),
"tuple_show.mbt": (
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show, B : Show] Show for (A, B)
#|pub impl[A : Show, B : Show] Show for (A, B) with fn output(self, logger) {
#| let (a, b) = self
#| logger.write_string("(")
#| logger.write_object(a)
#| logger.write_string(", ")
#| logger.write_object(b)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show, B : Show, C : Show] Show for (A, B, C)
#|pub impl[A : Show, B : Show, C : Show] Show for (A, B, C) with fn output(
#| self,
#| logger,
#|) {
#| let (a, b, c) = self
#| logger.write_string("(")
#| logger.write_object(a)
#| logger.write_string(", ")
#| logger.write_object(b)
#| logger.write_string(", ")
#| logger.write_object(c)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show, B : Show, C : Show, D : Show] Show for (A, B, C, D)
#|pub impl[A : Show, B : Show, C : Show, D : Show] Show for (A, B, C, D) with fn output(
#| self,
#| logger,
#|) {
#| let (a, b, c, d) = self
#| logger.write_string("(")
#| logger.write_object(a)
#| logger.write_string(", ")
#| logger.write_object(b)
#| logger.write_string(", ")
#| logger.write_object(c)
#| logger.write_string(", ")
#| logger.write_object(d)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show] Show for (
#| A,
#| B,
#| C,
#| D,
#| E,
#|)
#|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show] Show for (
#| A,
#| B,
#| C,
#| D,
#| E,
#|) with fn output(self, logger) {
#| let (a, b, c, d, e) = self
#| logger.write_string("(")
#| logger.write_object(a)
#| logger.write_string(", ")
#| logger.write_object(b)
#| logger.write_string(", ")
#| logger.write_object(c)
#| logger.write_string(", ")
#| logger.write_object(d)
#| logger.write_string(", ")
#| logger.write_object(e)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show, F : Show] Show for (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#|)
#|pub impl[A : Show, B : Show, C : Show, D : Show, E : Show, F : Show] Show for (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#|) with fn output(self, logger) {
#| let (a, b, c, d, e, f) = self
#| logger.write_string("(")
#| logger.write_object(a)
#| logger.write_string(", ")
#| logger.write_object(b)
#| logger.write_string(", ")
#| logger.write_object(c)
#| logger.write_string(", ")
#| logger.write_object(d)
#| logger.write_string(", ")
#| logger.write_object(e)
#| logger.write_string(", ")
#| logger.write_object(f)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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,
#|)
#|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 fn output(self, logger) {
#| let (a, b, c, d, e, f, g) = self
#| logger.write_string("(")
#| logger.write_object(a)
#| logger.write_string(", ")
#| logger.write_object(b)
#| logger.write_string(", ")
#| logger.write_object(c)
#| logger.write_string(", ")
#| logger.write_object(d)
#| logger.write_string(", ")
#| logger.write_object(e)
#| logger.write_string(", ")
#| logger.write_object(f)
#| logger.write_string(", ")
#| logger.write_object(g)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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 fn output(self, logger) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7) = self
#| logger.write_string("(")
#| logger.write_object(x0)
#| logger.write_string(", ")
#| logger.write_object(x1)
#| logger.write_string(", ")
#| logger.write_object(x2)
#| logger.write_string(", ")
#| logger.write_object(x3)
#| logger.write_string(", ")
#| logger.write_object(x4)
#| logger.write_string(", ")
#| logger.write_object(x5)
#| logger.write_string(", ")
#| logger.write_object(x6)
#| logger.write_string(", ")
#| logger.write_object(x7)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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 fn output(self, logger) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8) = self
#| logger.write_string("(")
#| logger.write_object(x0)
#| logger.write_string(", ")
#| logger.write_object(x1)
#| logger.write_string(", ")
#| logger.write_object(x2)
#| logger.write_string(", ")
#| logger.write_object(x3)
#| logger.write_string(", ")
#| logger.write_object(x4)
#| logger.write_string(", ")
#| logger.write_object(x5)
#| logger.write_string(", ")
#| logger.write_object(x6)
#| logger.write_string(", ")
#| logger.write_object(x7)
#| logger.write_string(", ")
#| logger.write_object(x8)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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 fn output(self, logger) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) = self
#| logger.write_string("(")
#| logger.write_object(x0)
#| logger.write_string(", ")
#| logger.write_object(x1)
#| logger.write_string(", ")
#| logger.write_object(x2)
#| logger.write_string(", ")
#| logger.write_object(x3)
#| logger.write_string(", ")
#| logger.write_object(x4)
#| logger.write_string(", ")
#| logger.write_object(x5)
#| logger.write_string(", ")
#| logger.write_object(x6)
#| logger.write_string(", ")
#| logger.write_object(x7)
#| logger.write_string(", ")
#| logger.write_object(x8)
#| logger.write_string(", ")
#| logger.write_object(x9)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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 fn output(
#| self,
#| logger,
#|) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) = self
#| logger.write_string("(")
#| logger.write_object(x0)
#| logger.write_string(", ")
#| logger.write_object(x1)
#| logger.write_string(", ")
#| logger.write_object(x2)
#| logger.write_string(", ")
#| logger.write_object(x3)
#| logger.write_string(", ")
#| logger.write_object(x4)
#| logger.write_string(", ")
#| logger.write_object(x5)
#| logger.write_string(", ")
#| logger.write_object(x6)
#| logger.write_string(", ")
#| logger.write_object(x7)
#| logger.write_string(", ")
#| logger.write_object(x8)
#| logger.write_string(", ")
#| logger.write_object(x9)
#| logger.write_string(", ")
#| logger.write_object(x10)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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 fn output(
#| self,
#| logger,
#|) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) = self
#| logger.write_string("(")
#| logger.write_object(x0)
#| logger.write_string(", ")
#| logger.write_object(x1)
#| logger.write_string(", ")
#| logger.write_object(x2)
#| logger.write_string(", ")
#| logger.write_object(x3)
#| logger.write_string(", ")
#| logger.write_object(x4)
#| logger.write_string(", ")
#| logger.write_object(x5)
#| logger.write_string(", ")
#| logger.write_object(x6)
#| logger.write_string(", ")
#| logger.write_object(x7)
#| logger.write_string(", ")
#| logger.write_object(x8)
#| logger.write_string(", ")
#| logger.write_object(x9)
#| logger.write_string(", ")
#| logger.write_object(x10)
#| logger.write_string(", ")
#| logger.write_object(x11)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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 fn output(
#| self,
#| logger,
#|) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) = self
#| logger.write_string("(")
#| logger.write_object(x0)
#| logger.write_string(", ")
#| logger.write_object(x1)
#| logger.write_string(", ")
#| logger.write_object(x2)
#| logger.write_string(", ")
#| logger.write_object(x3)
#| logger.write_string(", ")
#| logger.write_object(x4)
#| logger.write_string(", ")
#| logger.write_object(x5)
#| logger.write_string(", ")
#| logger.write_object(x6)
#| logger.write_string(", ")
#| logger.write_object(x7)
#| logger.write_string(", ")
#| logger.write_object(x8)
#| logger.write_string(", ")
#| logger.write_object(x9)
#| logger.write_string(", ")
#| logger.write_object(x10)
#| logger.write_string(", ")
#| logger.write_object(x11)
#| logger.write_string(", ")
#| logger.write_object(x12)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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 fn output(
#| self,
#| logger,
#|) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13) = self
#| logger.write_string("(")
#| logger.write_object(x0)
#| logger.write_string(", ")
#| logger.write_object(x1)
#| logger.write_string(", ")
#| logger.write_object(x2)
#| logger.write_string(", ")
#| logger.write_object(x3)
#| logger.write_string(", ")
#| logger.write_object(x4)
#| logger.write_string(", ")
#| logger.write_object(x5)
#| logger.write_string(", ")
#| logger.write_object(x6)
#| logger.write_string(", ")
#| logger.write_object(x7)
#| logger.write_string(", ")
#| logger.write_object(x8)
#| logger.write_string(", ")
#| logger.write_object(x9)
#| logger.write_string(", ")
#| logger.write_object(x10)
#| logger.write_string(", ")
#| logger.write_object(x11)
#| logger.write_string(", ")
#| logger.write_object(x12)
#| logger.write_string(", ")
#| logger.write_object(x13)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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)
#|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 fn output(
#| self,
#| logger,
#|) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14) = self
#| logger.write_string("(")
#| logger.write_object(x0)
#| logger.write_string(", ")
#| logger.write_object(x1)
#| logger.write_string(", ")
#| logger.write_object(x2)
#| logger.write_string(", ")
#| logger.write_object(x3)
#| logger.write_string(", ")
#| logger.write_object(x4)
#| logger.write_string(", ")
#| logger.write_object(x5)
#| logger.write_string(", ")
#| logger.write_object(x6)
#| logger.write_string(", ")
#| logger.write_object(x7)
#| logger.write_string(", ")
#| logger.write_object(x8)
#| logger.write_string(", ")
#| logger.write_object(x9)
#| logger.write_string(", ")
#| logger.write_object(x10)
#| logger.write_string(", ")
#| logger.write_object(x11)
#| logger.write_string(", ")
#| logger.write_object(x12)
#| logger.write_string(", ")
#| logger.write_object(x13)
#| logger.write_string(", ")
#| logger.write_object(x14)
#| logger.write_string(")")
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|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,
#|)
#|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 fn output(self, logger) {
#| let (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) = self
#| logger.write_string("(")
#| logger.write_object(x0)
#| logger.write_string(", ")
#| logger.write_object(x1)
#| logger.write_string(", ")
#| logger.write_object(x2)
#| logger.write_string(", ")
#| logger.write_object(x3)
#| logger.write_string(", ")
#| logger.write_object(x4)
#| logger.write_string(", ")
#| logger.write_object(x5)
#| logger.write_string(", ")
#| logger.write_object(x6)
#| logger.write_string(", ")
#| logger.write_object(x7)
#| logger.write_string(", ")
#| logger.write_object(x8)
#| logger.write_string(", ")
#| logger.write_object(x9)
#| logger.write_string(", ")
#| logger.write_object(x10)
#| logger.write_string(", ")
#| logger.write_object(x11)
#| logger.write_string(", ")
#| logger.write_object(x12)
#| logger.write_string(", ")
#| logger.write_object(x13)
#| logger.write_string(", ")
#| logger.write_object(x14)
#| logger.write_string(", ")
#| logger.write_object(x15)
#| logger.write_string(")")
#|}
),
"tuple_to_json.mbt": (
#|pub impl[A : ToJson, B : ToJson] ToJson for (A, B) with fn to_json(self) {
#| let (a0, a1) = self
#| [a0, a1]
#|}
#|pub impl[A : ToJson, B : ToJson, C : ToJson] ToJson for (A, B, C) with fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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]
#|}
),
"uint.mbt": (
#|pub fn UInt::UInt(self : UInt) -> UInt = "%identity"
#|pub fn UInt::min(self : UInt, other : UInt) -> UInt {
#| if self < other {
#| self
#| } else {
#| other
#| }
#|}
#|pub fn UInt::max(self : UInt, other : UInt) -> UInt {
#| if self > other {
#| self
#| } else {
#| other
#| }
#|}
#|pub fn UInt::clamp(self : UInt, min~ : UInt, max~ : UInt) -> UInt {
#| guard! min <= max
#| if self < min {
#| min
#| } else if self > max {
#| max
#| } else {
#| self
#| }
#|}
),
"uint16_char.mbt": (
#|pub fn UInt16::is_leading_surrogate(self : Self) -> Bool {
#| self >= 0xD800 && self <= 0xDBFF
#|}
#|pub fn UInt16::UInt16(self : UInt16) -> UInt16 = "%identity"
#|pub fn UInt16::is_trailing_surrogate(self : Self) -> Bool {
#| self >= 0xDC00 && self <= 0xDFFF
#|}
#|pub fn UInt16::is_surrogate(self : Self) -> Bool {
#| self >= 0xD800 && self <= 0xDFFF
#|}
#|#doc(hidden)
#|pub fn UInt16::unsafe_to_char(self : UInt16) -> Char {
#| self.to_int().unsafe_to_char()
#|}
#|pub fn UInt16::to_char(self : UInt16) -> Char? {
#| if self is (0..=0xD7FF) || self is (0xE000..<_) {
#| Some(self.unsafe_to_char())
#| } else {
#| None
#| }
#|}
#|pub impl Add for UInt16 with fn add(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() + that.to_int()).to_uint16()
#|}
#|pub impl Sub for UInt16 with fn sub(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() - that.to_int()).to_uint16()
#|}
#|pub impl Mul for UInt16 with fn mul(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() * that.to_int()).to_uint16()
#|}
#|pub impl Div for UInt16 with fn div(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() / that.to_int()).to_uint16()
#|}
#|pub impl Mod for UInt16 with fn mod(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() % that.to_int()).to_uint16()
#|}
#|pub impl Eq for UInt16 with fn equal(self, that) {
#| self.to_int() == that.to_int()
#|}
#|pub impl Eq for UInt16 with fn not_equal(self, that) {
#| self.to_int() != that.to_int()
#|}
#|pub impl Compare for UInt16 with fn compare(self, that) {
#| self.to_int().compare(that.to_int())
#|}
#|pub impl Compare for UInt16 with fn op_lt(x, y) = "%i32.lt"
#|pub impl Compare for UInt16 with fn op_le(x, y) = "%i32.le"
#|pub impl Compare for UInt16 with fn op_gt(x, y) = "%i32.gt"
#|pub impl Compare for UInt16 with fn op_ge(x, y) = "%i32.ge"
#|pub impl Hash for UInt16 with fn hash_combine(self, hasher) {
#| hasher.combine_int(self.to_int())
#|}
#|pub impl Shl for UInt16 with fn shl(self : UInt16, that : Int) -> UInt16 {
#| (self.to_int() << that).to_uint16()
#|}
#|pub impl Shr for UInt16 with fn shr(self : UInt16, that : Int) -> UInt16 {
#| (self.to_int() >> that).to_uint16()
#|}
#|pub impl BitOr for UInt16 with fn lor(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() | that.to_int()).to_uint16()
#|}
#|pub impl BitAnd for UInt16 with fn land(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() & that.to_int()).to_uint16()
#|}
#|pub impl BitXOr for UInt16 with fn lxor(self : UInt16, that : UInt16) -> UInt16 {
#| (self.to_int() ^ that.to_int()).to_uint16()
#|}
#|pub fn UInt16::lnot(self : UInt16) -> UInt16 {
#| self.to_int().lnot().to_uint16()
#|}
#|pub impl Default for UInt16 with fn default() {
#| 0
#|}
#|pub impl ToJson for UInt16 with fn 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()
#|}
),
"uint64.mbt": (
#|pub fn UInt64::UInt64(self : UInt64) -> UInt64 = "%identity"
#|pub impl Default for UInt64 with fn default() {
#| 0
#|}
#|test {
#| inspect(0x7000_0001_1F00_100FUL.popcnt(), content="14")
#|}
#|pub fn UInt64::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 UInt64::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(),
#| ]
#|}
),
"uninitialized_array.mbt": (
#|struct UninitializedArray[T](FixedArray[UnsafeMaybeUninit[T]])
#|pub fn[T] UninitializedArray::make(size : Int) -> UninitializedArray[T] = "%fixedarray.make_uninit"
#|#alias("_[_]")
#|pub fn[T] UninitializedArray::at(
#| self : UninitializedArray[T],
#| index : Int,
#|) -> T = "%fixedarray.get"
#|#internal(unsafe, "For internal use only.")
#|fn[T] UninitializedArray::unsafe_get(
#| self : UninitializedArray[T],
#| index : Int,
#|) -> T = "%fixedarray.unsafe_get"
#|#alias("_[_]=_")
#|pub fn[T] UninitializedArray::set(
#| self : UninitializedArray[T],
#| index : Int,
#| value : T,
#|) = "%fixedarray.set"
#|#internal(unsafe, "For internal use only.")
#|fn[T] UninitializedArray::unsafe_set(
#| self : UninitializedArray[T],
#| index : Int,
#| value : T,
#|) -> Unit = "%fixedarray.unsafe_set"
#|#alias(sub, deprecated="Use `exact_view` instead")
#|pub fn[T] UninitializedArray::exact_view(
#| self : UninitializedArray[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let len = self.length()
#| let end = match end {
#| Some(end) | (None with end = len) => end
#| }
#| guard start >= 0 && start <= end && end <= len else {
#| abort("View index out of bounds")
#| }
#| ArrayView::make(self, start, end - start)
#|}
#|#alias("_[_:_]")
#|pub fn[T] UninitializedArray::clamped_view(
#| self : UninitializedArray[T],
#| start? : Int = 0,
#| end? : Int,
#|) -> ArrayView[T] {
#| let len = self.length()
#| let lo = clamp_offset(start, len)
#| let hi = match end {
#| None => len
#| Some(end) => clamp_offset(end, len)
#| }
#| let count = if hi > lo { hi - lo } else { 0 }
#| ArrayView::make(self, lo, count)
#|}
#|pub fn[A] UninitializedArray::length(self : UninitializedArray[A]) -> Int {
#| self.0.length()
#|}
#|#internal(unsafe, "For internal use only.")
#|#doc(hidden)
#|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)
#|}
#|#intrinsic("%fixedarray.make_with_blit")
#|#owned(src)
#|fn[T] UninitializedArray::unsafe_make_and_blit(
#| src : UninitializedArray[T],
#| allocate_len : Int,
#| src_offset : Int,
#| dst_offset : Int,
#| blit_len : Int,
#|) -> UninitializedArray[T] {
#| let dst = UninitializedArray::make(allocate_len)
#| UninitializedArray::unsafe_blit(dst, dst_offset, src, src_offset, blit_len)
#| dst
#|}
#|#cfg(not(target="js"))
#|#intrinsic("%fixedarray.make_with_init_blit")
#|#owned(src, init)
#|fn[T] UninitializedArray::unsafe_make_and_blit_with_init(
#| src : UninitializedArray[T],
#| allocate_len : Int,
#| init : T,
#| src_offset : Int,
#| dst_offset : Int,
#| blit_len : Int,
#|) -> UninitializedArray[T] {
#| let dst = UninitializedArray::make(allocate_len)
#| dst.unchecked_fill(0, init, allocate_len)
#| UninitializedArray::unsafe_blit(dst, dst_offset, src, src_offset, blit_len)
#| dst
#|}
#|#owned(src)
#|pub fn[T] UninitializedArray::make_and_blit(
#| src : UninitializedArray[T],
#| allocate_len~ : Int,
#| len~ : Int,
#| src_offset? : Int = 0,
#| dst_offset? : Int = 0,
#|) -> UninitializedArray[T] {
#| guard allocate_len >= 0 &&
#| len >= 0 &&
#| src_offset >= 0 &&
#| dst_offset >= 0 &&
#| src_offset + len <= src.length() &&
#| dst_offset + len <= allocate_len else {
#| abort(
#| "bounds check failed: allocate_len = \{allocate_len}, src_offset = \{src_offset}, dst_offset = \{dst_offset}, len = \{len}, src.length = \{src.length()}",
#| )
#| }
#| UninitializedArray::unsafe_make_and_blit(
#| src, allocate_len, src_offset, dst_offset, len,
#| )
#|}
#|#cfg(not(target="js"))
#|#intrinsic("%fixedarray.make_with_blit")
#|#owned(src)
#|fn[T] UninitializedArray::unsafe_make_and_blit_from_fixed(
#| src : FixedArray[T],
#| allocate_len : Int,
#| src_offset : Int,
#| dst_offset : Int,
#| blit_len : Int,
#|) -> UninitializedArray[T] {
#| let dst = UninitializedArray::make(allocate_len)
#| UninitializedArray::unsafe_blit_fixed(
#| dst, dst_offset, src, src_offset, blit_len,
#| )
#| dst
#|}
#|test "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 as_view with invalid_start" {
#| let arr : UninitializedArray[Int] = UninitializedArray::make(5)
#| ignore(arr.exact_view(start=-1))
#|}
#|test "panic as_view with invalid_end" {
#| let arr : UninitializedArray[Int] = UninitializedArray::make(5)
#| ignore(arr.exact_view(start=2, end=10))
#|}
#|#coverage.skip
#|#intrinsic("%fixedarray.fill")
#|#cfg(not(target="js"))
#|#owned(value)
#|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 fn equal(_ : Unit, _ : Unit) -> Bool {
#| true
#|}
#|pub impl Compare for Unit with fn compare(_, _) {
#| 0
#|}
#|pub impl Default for Unit with fn default() -> Unit {
#| ()
#|}
#|pub impl Hash for Unit with fn hash_combine(_, hasher) -> Unit {
#| hasher.combine_unit()
#|}
),
},
)
///|
let moonbitlang_core_byte_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/byte",
deps={},
files={
"byte.mbt": (
#|pub const MAX_VALUE : Byte = b'\xFF'
#|#deprecated("Use `MAX_VALUE` instead")
#|pub let max_value : Byte = b'\xFF'
#|pub const MIN_VALUE : Byte = b'\x00'
#|#deprecated("Use `MIN_VALUE` instead")
#|pub let min_value : Byte = b'\x00'
),
},
)
///|
let moonbitlang_core_bytes_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/bytes",
deps={},
files={
"alias.mbt": (
#|#deprecated("Use `Bytes::default` instead")
#|#doc(hidden)
#|pub fn default() -> Bytes {
#| b""
#|}
#|#deprecated("Use `Bytes::from_array` instead")
#|#doc(hidden)
#|pub fn from_fixedarray(arr : FixedArray[Byte], len? : Int) -> Bytes {
#| Bytes::from_array(arr.exact_view(end=len.unwrap_or(arr.length())))
#|}
#|#deprecated("Use `Bytes::from_iter` instead")
#|#alias(from_iterator, deprecated="Use `Bytes::from_iter` instead")
#|#doc(hidden)
#|pub fn from_iter(iter : Iter[Byte]) -> Bytes {
#| Bytes::from_iter(iter)
#|}
#|#deprecated("Use `Bytes::from_array` instead")
#|#doc(hidden)
#|pub fn of(arr : ArrayView[Byte]) -> Bytes {
#| Bytes::from_array(arr)
#|}
#|#deprecated("Use `Bytes::from_array` instead")
#|#doc(hidden)
#|pub fn from_array(arr : ArrayView[Byte]) -> Bytes {
#| Bytes::from_array(arr)
#|}
#|#deprecated("@bytes.View is deprecated, use BytesView instead.")
#|pub type View = BytesView
),
},
)
///|
let moonbitlang_core_char_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/char",
deps={},
files={ "char_util.mbt": "" },
)
///|
let moonbitlang_core_cmp_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/cmp",
deps={},
files={
"cmp.mbt": (
#|pub(all) struct Reverse[T](T) derive(Eq, Hash, @debug.Debug)
#|#deprecated("Use `@debug.Debug` instead of `Show`", skip_current_package=true)
#|pub impl[T : Show] Show for Reverse[T]
#|pub impl[T : Show] Show for Reverse[T] with fn output(self, logger) {
#| logger <+
#| $|Reverse(\{self.0})|
#|}
#|pub impl[T : Compare] Compare for Reverse[T] with fn compare(a, b) {
#| -a.0.compare(b.0)
#|}
#|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
#| }
#|}
#|pub fn[T : Compare] minmax(x : T, y : T) -> (T, T) {
#| if x > y {
#| (y, x)
#| } else {
#| (x, y)
#| }
#|}
#|pub fn[T, K : Compare] minmax_by_key(x : T, y : T, f : (T) -> K) -> (T, T) {
#| if f(x) > f(y) {
#| (y, x)
#| } else {
#| (x, y)
#| }
#|}
),
"extends.mbt": (
#|pub extend Reverse with Compare::{compare}
#|pub extend Reverse with Eq::{equal}
#|pub extend Reverse with Hash::{hash}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Reverse with @debug.Debug::{to_repr}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Reverse with Compare::{op_ge, op_gt, op_le, op_lt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Reverse with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Reverse with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show`", skip_current_package=true)
#|#doc(hidden)
#|pub extend Reverse with Show::{output, to_string}
),
},
)
///|
let moonbitlang_core_debug_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/debug",
deps={},
files={
"debug.mbt": (
#|pub(open) trait Debug {
#| #as_free_fn(deprecated="Use `Repr(x)` instead")
#| fn to_repr(Self) -> Repr
#|}
#|pub impl Debug for Int with fn to_repr(self) {
#| Repr::integer(self.to_string())
#|}
#|pub impl Debug for Int16 with fn to_repr(self) {
#| Repr::integer(self.to_string())
#|}
#|pub impl Debug for Int64 with fn to_repr(self) {
#| Repr::integer(self.to_string())
#|}
#|pub impl Debug for UInt16 with fn to_repr(self) {
#| Repr::integer(self.to_string())
#|}
#|pub impl Debug for UInt with fn to_repr(self) {
#| Repr::integer(self.to_string())
#|}
#|pub impl Debug for UInt64 with fn to_repr(self) {
#| Repr::integer(self.to_string())
#|}
#|pub impl Debug for Double with fn to_repr(self) {
#| Repr::double(self)
#|}
#|pub impl Debug for Float with fn to_repr(self) {
#| Repr::float(self)
#|}
#|pub impl Debug for Bool with fn to_repr(self) {
#| Repr::bool(self)
#|}
#|pub impl Debug for Byte with fn to_repr(self) {
#| Repr::literal("0x" + self.to_hex())
#|}
#|pub impl Debug for Char with fn to_repr(self) {
#| Repr::char(self)
#|}
#|pub impl Debug for String with fn to_repr(self) {
#| Repr::string(self)
#|}
#|pub impl Debug for StringView with fn to_repr(self) {
#| Repr::opaque_("StringView", Repr::string(self.to_owned()))
#|}
#|pub impl Debug for Bytes with fn to_repr(self) {
#| Repr::opaque_("Bytes", Repr::array(self.to_array().map(x => Repr(x))))
#|}
#|pub impl Debug for BytesView with fn to_repr(self) {
#| Repr::opaque_("BytesView", Repr::array(self.to_array().map(x => Repr(x))))
#|}
#|pub impl Debug for Unit with fn to_repr(_) {
#| Repr::unit()
#|}
#|pub impl[T : Debug] Debug for Array[T] with fn to_repr(self) {
#| Repr::array(self.map(x => Repr(x)))
#|}
#|pub impl[T : Debug] Debug for ArrayView[T] with fn to_repr(self) {
#| Repr::opaque_("ArrayView", Repr::array(self.map(x => Repr(x))))
#|}
#|pub impl[T : Debug] Debug for FixedArray[T] with fn to_repr(self) {
#| let view : ArrayView[T] = self
#| Repr::opaque_("FixedArray", Repr::array(view.map(x => Repr(x))))
#|}
#|pub impl[T : Debug] Debug for ReadOnlyArray[T] with fn to_repr(self) {
#| let view : ArrayView[T] = self
#| Repr::opaque_("ReadOnlyArray", Repr::array(view.map(x => Repr(x))))
#|}
#|pub impl[T : Debug] Debug for T? with fn to_repr(self) {
#| match self {
#| None => Repr::ctor("None", [])
#| Some(x) => Repr::ctor("Some", [(None, Repr(x))])
#| }
#|}
#|pub impl[T : Debug, E : Debug] Debug for Result[T, E] with fn to_repr(self) {
#| match self {
#| Ok(x) => Repr::ctor("Ok", [(None, Repr(x))])
#| Err(e) => Repr::ctor("Err", [(None, Repr(e))])
#| }
#|}
#|pub impl[A] Debug for Iter[A] with fn to_repr(_) {
#| Repr::opaque_("Iter", Omitted)
#|}
#|pub impl[A, B] Debug for Iter2[A, B] with fn to_repr(_) {
#| Repr::opaque_("Iter2", Omitted)
#|}
#|pub impl[T : Debug] Debug for MutArrayView[T] with fn to_repr(self) {
#| Repr::opaque_("MutArrayView", Repr::array(self[:].map(x => Repr(x))))
#|}
#|pub impl Debug for StringBuilder with fn to_repr(self) {
#| Repr::string(self.to_string())
#|}
#|pub impl[K : Debug, V : Debug] Debug for Map[K, V] with fn to_repr(self) {
#| Repr::map([ for k, v in self => (Repr(k), Repr(v)) ])
#|}
#|pub impl Debug for Json with fn to_repr(self) {
#| match self {
#| Null => Repr::ctor("Null", [])
#| True => Repr::ctor("True", [])
#| False => Repr::ctor("False", [])
#| Number(number, repr~) =>
#| match repr {
#| None => Repr::ctor("Number", [(None, Repr(number))])
#| Some(_) =>
#| Repr::ctor("Number", [
#| (None, Repr(number)),
#| (Some("repr"), Repr(repr)),
#| ])
#| }
#| String(string) => Repr::ctor("String", [(None, Repr(string))])
#| Array(array) => Repr::ctor("Array", [(None, Repr(array))])
#| Object(object) => Repr::ctor("Object", [(None, Repr(object))])
#| }
#|}
#|pub impl Debug for SourceLoc with fn to_repr(self) {
#| Repr::opaque_("SourceLoc", Repr::string(self.to_string()))
#|}
#|#callsite(autofill(args_loc, loc))
#|#alias(inspect, deprecated="use `debug_inspect` without package name instead")
#|pub fn debug_inspect(
#| obj : &Debug,
#| content? : String,
#| loc~ : SourceLoc,
#| args_loc~ : ArgsLoc,
#|) -> Unit raise InspectError {
#| let loc = loc.to_json_string()
#| let args_loc = args_loc.to_json()
#| let actual = render(obj.to_repr())
#| let want = match content {
#| None => ""
#| Some(x) => x
#| }
#| if actual != want {
#| raise InspectError(
#| (
#| $|@EXPECT_FAILED {"loc": \{loc}, "args_loc": \{args_loc}, "expect": \{want.escape()}, "actual": \{actual.escape()} }
#| ),
#| )
#| }
#|}
#|#callsite(autofill(loc))
#|pub fn[T : Eq + Debug] assert_eq(
#| a : T,
#| b : T,
#| msg? : String,
#| loc~ : SourceLoc,
#|) -> Unit raise {
#| if a != b {
#| let fail_msg = match msg {
#| Some(msg) => msg
#| None => {
#| let repr_a = Repr(a)
#| let repr_b = Repr(b)
#| let diff = pretty_print_delta(diff_repr(repr_a, repr_b), use_ansi=false)
#| (
#| $|`\{render(repr_a)} != \{render(repr_b)}`
#| $|diff:
#| $|\{diff}
#| )
#| }
#| }
#| fail(fail_msg, loc~)
#| }
#|}
#|test "core builtin Debug implementations" {
#| debug_inspect((1 : Int16), content="1")
#| debug_inspect((1 : UInt16), content="1")
#| debug_inspect((1 : UInt64), content="1")
#| debug_inspect((1.0 : Float), content="1")
#| let b : Bytes = b"ab"
#| debug_inspect(b, content="")
#| let bv : BytesView = b
#| debug_inspect(bv, content="")
#| let sv : StringView = "abc"
#| debug_inspect(
#| sv,
#| content=(
#| #|
#| ),
#| )
#| let av : ArrayView[Int] = [1, 2, 3][1:3]
#| debug_inspect(av, content="")
#| let fa : FixedArray[Int] = [1, 2, 3]
#| debug_inspect(fa, content="")
#| let ro : ReadOnlyArray[Int] = [1, 2, 3]
#| debug_inspect(ro, content="")
#| let mv : MutArrayView[Int] = [1, 2, 3].mut_view(start=1, end=3)
#| debug_inspect(mv, content="")
#| debug_inspect((Ok(1) : Result[Int, String]), content="Ok(1)")
#| debug_inspect((Err("e") : Result[Int, String]), content="Err(\"e\")")
#|}
#|#callsite(autofill(loc))
#|#deprecated("This function is for debugging only and should not be used in production", skip_current_package=true)
#|pub fn[T : Debug] dump(t : T, name? : String, loc~ : SourceLoc) -> T {
#| let name = match name {
#| Some(name) => name
#| None => ""
#| }
#| println("dump(\{name}@\{loc}) = \{to_string(t)}")
#| t
#|}
#|test "dump" {
#| let x = 42
#| if false {
#| dump(()) // never reached here
#| assert_eq(dump(x) + x, 84)
#| }
#|}
#|pub impl Debug for InspectError with fn to_repr(self) {
#| match self {
#| InspectError(msg) => Repr::ctor("InspectError", [(None, Repr::string(msg))])
#| }
#|}
#|pub impl Debug for Failure with fn to_repr(self) {
#| match self {
#| Failure(msg) => Repr::ctor("Failure", [(None, Repr::string(msg))])
#| }
#|}
#|pub impl Debug for SnapshotError with fn to_repr(self) {
#| match self {
#| SnapshotError(msg) =>
#| Repr::ctor("SnapshotError", [(None, Repr::string(msg))])
#| }
#|}
#|#warnings("-deprecated")
#|pub impl Debug for BenchError with fn to_repr(self) {
#| match self {
#| BenchError(msg) => Repr::ctor("BenchError", [(None, Repr::string(msg))])
#| }
#|}
#|pub impl Debug for ArgsLoc with fn to_repr(self) {
#| let ArgsLoc(arr) = self
#| Repr::opaque_("ArgsLoc", Repr(arr))
#|}
#|pub impl Debug for Hasher with fn to_repr(_) {
#| Repr::opaque_("Hasher", Repr::omitted())
#|}
#|pub impl[T] Debug for UninitializedArray[T] with fn to_repr(_) {
#| Repr::opaque_("UninitializedArray", Repr::omitted())
#|}
#|test "Debug for builtin errors" {
#| debug_inspect(
#| InspectError::InspectError("inspect msg"),
#| content="InspectError(\"inspect msg\")",
#| )
#| debug_inspect(
#| Failure::Failure("failure msg"),
#| content="Failure(\"failure msg\")",
#| )
#| debug_inspect(
#| SnapshotError::SnapshotError("snapshot msg"),
#| content="SnapshotError(\"snapshot msg\")",
#| )
#|}
),
"delta.mbt": (
#|priv enum ReprDelta {
#| Same(Repr, Array[ReprDelta])
#| Different(Repr, Repr)
#| Extra1(Repr)
#| Extra2(Repr)
#|}
#|const DEFAULT_MAX_RELATIVE_ERROR : Double = 0.000000000001
#|fn double_abs(x : Double) -> Double {
#| if x < 0.0 {
#| -x
#| } else {
#| x
#| }
#|}
#|fn double_max(x : Double, y : Double) -> Double {
#| if x > y {
#| x
#| } else {
#| y
#| }
#|}
#|fn relative_error(x : Double, y : Double) -> Double {
#| if x == y {
#| 0.0
#| } else {
#| let denom = double_max(double_abs(x), double_abs(y))
#| if denom == 0.0 {
#| double_abs(x - y)
#| } else {
#| double_abs(x - y) / denom
#| }
#| }
#|}
#|fn info_approx_eq(max_relative_error : Double, x : Repr, y : Repr) -> Bool {
#| match (x, y) {
#| (UnitLit, UnitLit) => true
#| (Integer(x1), Integer(y1)) => x1 == y1
#| (DoubleLit(x1), DoubleLit(y1)) =>
#| relative_error(x1, y1) <= max_relative_error
#| (FloatLit(x1), FloatLit(y1)) => x1 == y1
#| (BoolLit(x1), BoolLit(y1)) => x1 == y1
#| (CharLit(x1), CharLit(y1)) => x1 == y1
#| (StringLit(x1), StringLit(y1)) => x1 == y1
#| (Tuple(_), Tuple(_)) => true
#| (Array(_), Array(_)) => true
#| (Record(_), Record(_)) => true
#| (Enum(n1, _), Enum(n2, _)) => n1 == n2
#| (Map(_), Map(_)) => true
#| (RecordField(n1, _), RecordField(n2, _)) => n1 == n2
#| (EnumLabeledArg(n1, _), EnumLabeledArg(n2, _)) => n1 == n2
#| (Opaque(n1, _), Opaque(n2, _)) => n1 == n2
#| (Literal(x1), Literal(y1)) => x1 == y1
#| (MapEntry(_, _), MapEntry(_, _)) => true
#| (Omitted, Omitted) => true
#| _ => false
#| }
#|}
#|fn info_is_unimportant(info : Repr) -> Bool {
#| info is (MapEntry(_, _) | Tuple(_) | Array(_) | Record(_))
#|}
#|fn diff_info_with(
#| left : Repr,
#| right : Repr,
#| max_relative_error~ : Double,
#|) -> ReprDelta {
#| fn go(left_node : Repr, right_node : Repr) -> ReprDelta {
#| if info_approx_eq(max_relative_error, left_node, right_node) {
#| let xs = left_node.children()
#| let ys = right_node.children()
#| let xlen = xs.length()
#| let ylen = ys.length()
#| let min_len = if xlen < ylen { xlen } else { ylen }
#| let children : Array[ReprDelta] = []
#| for i in 0.. !(d is Same(_, _))) {
#| Different(left_node, right_node)
#| } else {
#| Same(left_node.shallow(), children)
#| }
#| } else {
#| Different(left_node, right_node)
#| }
#| }
#| go(left, right)
#|}
#|fn diff_repr(
#| x : Repr,
#| y : Repr,
#| max_relative_error? : Double = DEFAULT_MAX_RELATIVE_ERROR,
#|) -> ReprDelta {
#| diff_info_with(x, y, max_relative_error~)
#|}
#|fn pretty_print_delta(
#| d : ReprDelta,
#| max_depth? : Int,
#| compact_threshold? : Int = default_threshold,
#| use_ansi? : Bool = true,
#|) -> String {
#| let max_depth : Int? = match max_depth {
#| Some(_) => max_depth
#| None => Some(default_max_depth)
#| }
#| let delta = prune_delta(max_depth, d)
#| print_content(render_delta(compact_threshold, use_ansi, delta).no_wrap())
#|}
#|fn prune_delta(max_depth : Int?, delta : ReprDelta) -> ReprDelta {
#| fn go(d : Int, node : ReprDelta) -> ReprDelta {
#| if d <= 0 {
#| match node {
#| Same(label, children) =>
#| if children.is_empty() {
#| node
#| } else if !label.info_adds_depth() {
#| Same(label, children.map(child => go(d, child)))
#| } else {
#| Same(Repr::omitted(), [])
#| }
#| Different(_, _) | Extra1(_) | Extra2(_) => Same(Repr::omitted(), [])
#| }
#| } else {
#| match node {
#| Same(label, children) => {
#| let next_depth = if label.info_adds_depth() { d - 1 } else { d }
#| Same(label, children.map(child => go(next_depth, child)))
#| }
#| Different(left, right) =>
#| Different(
#| left.prune_info(max_depth=Some(d)),
#| right.prune_info(max_depth=Some(d)),
#| )
#| Extra1(x) => Extra1(x.prune_info(max_depth=Some(d)))
#| Extra2(x) => Extra2(x.prune_info(max_depth=Some(d)))
#| }
#| }
#| }
#| match max_depth {
#| None => delta
#| Some(depth) => go(Int::max(1, depth), delta)
#| }
#|}
#|fn delta_root_size(delta : ReprDelta) -> Int {
#| match delta {
#| Same(label, _) => info_size(label)
#| _ => 0
#| }
#|}
#|const ANSI_RESET : String = "\u001b[0m"
#|const ANSI_RED : String = "\u001b[31m"
#|const ANSI_GREEN : String = "\u001b[32m"
#|fn mark_removed(use_ansi : Bool, x : ContentParens) -> ContentParens {
#| if use_ansi {
#| surround(ANSI_RED + "-", ANSI_RESET, x)
#| } else {
#| surround("-", "", x)
#| }
#|}
#|fn mark_added(use_ansi : Bool, x : ContentParens) -> ContentParens {
#| if use_ansi {
#| surround(ANSI_GREEN + "+", ANSI_RESET, x)
#| } else {
#| surround("+", "", x)
#| }
#|}
#|fn render_delta(threshold : Int, use_ansi : Bool, delta : ReprDelta) -> Content {
#| match delta {
#| Same(label, children_delta) => {
#| let children = children_delta.map(child => {
#| render_delta(threshold, use_ansi, child)
#| })
#| with_resizing(
#| delta_root_size(delta),
#| threshold,
#| label.pretty_print(children),
#| )
#| }
#| Different(left, right) => {
#| let children : Array[Content] = [
#| left.render_repr(threshold),
#| right.render_repr(threshold),
#| ]
#| with_resizing(
#| 0,
#| threshold,
#| match children {
#| [left, right] =>
#| no_parens(
#| mark_removed(use_ansi, left.no_wrap()) +
#| mark_added(use_ansi, right.no_wrap()),
#| )
#| _ => empty_content()
#| },
#| )
#| }
#| Extra1(x) => {
#| let children : Array[Content] = [x.render_repr(threshold)]
#| with_resizing(
#| 0,
#| threshold,
#| match children {
#| [x] => no_parens(mark_removed(use_ansi, x.no_wrap()))
#| _ => empty_content()
#| },
#| )
#| }
#| Extra2(x) => {
#| let children : Array[Content] = [x.render_repr(threshold)]
#| with_resizing(
#| 0,
#| threshold,
#| match children {
#| [x] => no_parens(mark_added(use_ansi, x.no_wrap()))
#| _ => empty_content()
#| },
#| )
#| }
#| }
#|}
),
"extends.mbt": (
#|pub extend Repr with Show::{to_string}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Repr with Debug::{to_repr}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Repr with Show::{output}
),
"pretty_print.mbt": (
#|let default_max_depth : Int = 16
#|let default_threshold : Int = 70
#|fn Repr::prune_info(
#| self : Repr,
#| replacement? : Repr = Repr::omitted(),
#| max_depth~ : Int?,
#|) -> Repr {
#| match max_depth {
#| None => self
#| Some(depth) => {
#| fn go(d : Int, node : Repr) -> Repr {
#| let children = node.children()
#| if d <= 0 {
#| if children.is_empty() {
#| node
#| } else if !node.info_adds_depth() {
#| node.with_children(children.map(child => go(d, child)))
#| } else {
#| replacement
#| }
#| } else if children.is_empty() {
#| node
#| } else {
#| let next_depth = if node.info_adds_depth() { d - 1 } else { d }
#| node.with_children(children.map(child => go(next_depth, child)))
#| }
#| }
#| go(Int::max(1, depth), self)
#| }
#| }
#|}
#|fn Repr::info_adds_depth(info : Repr) -> Bool {
#| !(info is (RecordField(_, _) | EnumLabeledArg(_, _) | MapEntry(_, _)))
#|}
#|fn info_size(info : Repr) -> Int {
#| match info {
#| UnitLit => 1
#| Integer(_) => 1
#| DoubleLit(_) => 1
#| FloatLit(_) => 1
#| BoolLit(_) => 1
#| CharLit(_) => 1
#| StringLit(s) => if s.length() <= 15 { 1 } else { 2 }
#| Tuple(_) => 1
#| Array(_) => 1
#| Record(_) => 2
#| RecordField(name, _) => if name.length() <= 15 { 0 } else { 1 }
#| EnumLabeledArg(name, _) => if name.length() <= 15 { 0 } else { 1 }
#| Enum(name, _) => if name.length() <= 15 { 1 } else { 2 }
#| Opaque(name, _) => if name.length() <= 15 { 1 } else { 2 }
#| Literal(s) => if s.length() <= 15 { 1 } else { 2 }
#| Map(_) => 2
#| MapEntry(_, _) => 0
#| Omitted => 0
#| }
#|}
#|fn is_unquoted_key(key : String) -> Bool {
#| match key {
#| ['a'..='z' | '_', .. rest] =>
#| rest.all(c => c is ('a'..='z' | 'A'..='Z' | '0'..='9' | '_'))
#| _ => false
#| }
#|}
#|fn pretty_print_label(name : String) -> String {
#| if is_unquoted_key(name) {
#| name
#| } else {
#| name.escape()
#| }
#|}
#|fn Repr::pretty_print(self : Repr, children : Array[Content]) -> Content {
#| match self {
#| UnitLit => comma_seq("(", ")", [])
#| Integer(s) =>
#| no_parens(content_parens(if s is ['-', ..] { 1 } else { 0 }, [s]))
#| DoubleLit(x) => {
#| let needs_parens = 1.0 / x < 0.0
#| leaf(x.to_string(), needs_parens~)
#| }
#| FloatLit(x) => {
#| let needs_parens : Bool = (1.0 : Float) / x < (0.0 : Float)
#| leaf(x.to_string(), needs_parens~)
#| }
#| BoolLit(x) => leaf(x.to_string())
#| CharLit(x) => leaf(x.escape())
#| StringLit(x) => no_parens(verbatim(x.escape()))
#| Tuple(_) => comma_seq("(", ")", children.map(x => x.no_wrap()))
#| Enum(name, _) =>
#| match children {
#| [] => no_parens(verbatim(name))
#| _ =>
#| if name == "Tuple" {
#| comma_seq("(", ")", children.map(x => x.no_wrap()))
#| } else {
#| comma_seq(name + "(", ")", children.map(x => x.no_wrap()))
#| }
#| }
#| Array(_) => comma_seq("[", "]", children.map(x => x.no_wrap()))
#| Record(_) => comma_seq("{", "}", children.map(x => x.no_wrap()))
#| Opaque(name, _) =>
#| if children.is_empty() {
#| no_parens(surround("<", ">", verbatim(name)))
#| } else {
#| let body = verbatim(name + ":") +
#| indent(
#| " ",
#| comma_seq("", "", children.map(x => x.no_wrap())).no_wrap(),
#| )
#| no_parens(surround("<", ">", body))
#| }
#| Literal(str) => no_parens(verbatim(str))
#| Map(_) => comma_seq("{", "}", children.map(x => x.no_wrap()))
#| MapEntry(_, _) =>
#| match children {
#| [key, val] => {
#| let k = key.no_wrap()
#| let v = val.no_wrap()
#| match v.lines {
#| [] => empty_content()
#| [one] =>
#| no_parens(
#| content_parens(1 + k.size + v.size, [
#| print_content(surround("", ": ", k)) + one,
#| ]),
#| )
#| [first, .. rest] => {
#| let head = print_content(surround("", ": ", k)) + first
#| no_parens(content_parens(1 + k.size + v.size, [head, ..rest]))
#| }
#| }
#| }
#| _ => empty_content()
#| }
#| EnumLabeledArg(name, _) =>
#| match children {
#| [val] =>
#| match val.lines {
#| [] => empty_content()
#| [first] =>
#| no_parens(content_parens(1 + val.size, [name + "=" + first]))
#| [first, .. rest] =>
#| no_parens(
#| content_parens(1 + val.size, [name + "=" + first, ..rest]),
#| )
#| }
#| _ => empty_content()
#| }
#| RecordField(name, _) =>
#| match children {
#| [val] => {
#| let label = pretty_print_label(name)
#| let v = val.no_wrap()
#| match v.lines {
#| [] => empty_content()
#| [one] => no_parens(content_parens(1 + v.size, [label + ": " + one]))
#| [first, .. rest] =>
#| no_parens(
#| content_parens(1 + v.size, [label + ": " + first, ..rest]),
#| )
#| }
#| }
#| _ => empty_content()
#| }
#| Omitted => parens(verbatim("..."))
#| }
#|}
#|fn Repr::render_repr(self : Repr, threshold : Int) -> Content {
#| let label = self.shallow()
#| let children = self.children().map(child => child.render_repr(threshold))
#| with_resizing(info_size(label), threshold, label.pretty_print(children))
#|}
#|pub fn render(r : Repr, max_depth? : Int) -> String {
#| let max_depth : Int? = match max_depth {
#| Some(_) => max_depth
#| None => Some(default_max_depth)
#| }
#| let threshold = default_threshold
#| let info = r.prune_info(max_depth~)
#| print_content(info.render_repr(threshold).no_wrap())
#|}
#|pub impl Show for Repr with fn output(self, logger) {
#| logger.write_string(render(self))
#|}
#|pub impl Debug for Repr with fn to_repr(self) {
#| self
#|}
#|pub fn[T : Debug] debug(x : T) -> Unit {
#| println(render(x.to_repr()))
#|}
#|#alias(repr)
#|pub fn[T : Debug] to_string(x : T) -> String {
#| render(x.to_repr())
#|}
),
"printer.mbt": (
#|priv struct Content {
#| size : Int
#| lines : Array[String]
#| needs_parens : Bool
#|}
#|priv struct ContentParens {
#| size : Int
#| lines : Array[String]
#|}
#|impl Add for ContentParens with fn add(self, other) {
#| { size: self.size + other.size, lines: self.lines + other.lines, }
#|}
#|fn empty_content() -> Content {
#| { size: 0, lines: [], needs_parens: false, }
#|}
#|fn verbatim(x : String) -> ContentParens {
#| { size: 1, lines: [x], }
#|}
#|fn content_parens(size : Int, lines : Array[String]) -> ContentParens {
#| { size, lines, }
#|}
#|fn leaf(x : String, needs_parens? : Bool = false) -> Content {
#| { size: 1, lines: [x], needs_parens, }
#|}
#|fn with_lines(
#| r : ContentParens,
#| f : (Array[String]) -> Array[String],
#|) -> ContentParens {
#| { size: r.size, lines: f(r.lines), }
#|}
#|fn Content::with_lines_content(
#| r : Content,
#| f : (Array[String]) -> Array[String],
#|) -> Content {
#| { size: r.size, lines: f(r.lines), needs_parens: r.needs_parens, }
#|}
#|fn surround_lines(
#| start : String,
#| finish : String,
#| lines : Array[String],
#|) -> Array[String] {
#| match lines {
#| [] => [start + finish]
#| [item] => [start + item + finish]
#| [first, .. middle, last] => [start + first, ..middle, last + finish]
#| }
#|}
#|fn surround(
#| start : String,
#| finish : String,
#| r : ContentParens,
#|) -> ContentParens {
#| with_lines(r, fn(lines) { surround_lines(start, finish, lines) })
#|}
#|fn Content::no_wrap(c : Content) -> ContentParens {
#| { size: c.size, lines: c.lines, }
#|}
#|fn parens(r : ContentParens) -> Content {
#| { size: r.size, lines: r.lines, needs_parens: true, }
#|}
#|fn no_parens(r : ContentParens) -> Content {
#| { size: r.size, lines: r.lines, needs_parens: false, }
#|}
#|fn compact_middle(middle : ArrayView[String]) -> StringView {
#| let parts : Array[StringView] = []
#| for m in middle {
#| let t = m.trim()
#| if t != "" {
#| parts.push(t)
#| }
#| }
#| let joined0 = parts.join(" ")
#| let joined : StringView = match joined0.strip_suffix(",") {
#| Some(sv) => sv
#| None => joined0
#| }
#| joined
#|}
#|fn compact_lines(lines : Array[String]) -> Array[String] {
#| match lines {
#| [] => []
#| [x] => [x]
#| [first, .. middle, last] =>
#| if (first == "[" && last == "]") || (first == "{" && last == "}") {
#| let joined = compact_middle(middle)
#| if first == "{" {
#| let s1 = joined.strip_prefix(" ").unwrap_or(joined)
#| let inner = s1.strip_suffix(" ").unwrap_or(s1)
#| if inner == "" {
#| ["{}"]
#| } else {
#| ["{ \{inner} }"]
#| }
#| } else {
#| ["[\{joined}]"]
#| }
#| } else if first.has_suffix("(") && last == ")" {
#| let joined = compact_middle(middle)
#| ["\{first}\{joined}\{last}"]
#| } else {
#| let parts : Array[StringView] = [first]
#| for m in middle {
#| parts.push(m.trim())
#| }
#| parts.push(last.trim())
#| [parts.join(" ")]
#| }
#| }
#|}
#|fn Content::compact(r : Content) -> Content {
#| r.with_lines_content(compact_lines)
#|}
#|fn indent(prefix : String, r : ContentParens) -> ContentParens {
#| with_lines(r, lines => lines.map(line => prefix + line))
#|}
#|fn indent_spaces(n : Int, r : ContentParens) -> ContentParens {
#| indent(" ".repeat(n), r)
#|}
#|fn bracket_seq_lines(
#| open : String,
#| close : String,
#| indent_by : Int,
#| contents : Array[Array[String]],
#|) -> Array[String] {
#| match contents {
#| [] => [open + close]
#| [item] =>
#| if item.length() > 1 {
#| let lines = indent_spaces(indent_by, { size: 0, lines: item, }).lines
#| if !lines.is_empty() {
#| let last_i = lines.length() - 1
#| lines[last_i] += ","
#| }
#| [open, ..lines, close]
#| } else {
#| let inner = compact_lines(item)
#| match inner {
#| [] => [open + close]
#| [x] =>
#| if open == "{" && close == "}" {
#| let inner = x.trim()
#| if inner == "" {
#| ["{}"]
#| } else {
#| ["{ \{inner} }"]
#| }
#| } else {
#| [open + x + close]
#| }
#| _ =>
#| [
#| open,
#| ..indent_spaces(indent_by, { size: 0, lines: item, }).lines,
#| close,
#| ]
#| }
#| }
#| _ => {
#| let out : Array[String] = [open]
#| for item in contents {
#| let item_lines = item.filter(line => line != "")
#| match item_lines {
#| [] => ()
#| [x] => out.push(" ".repeat(indent_by) + x + ",")
#| [first, .. middle, last] => {
#| out.push(" ".repeat(indent_by) + first)
#| for mid in middle {
#| out.push(" ".repeat(indent_by) + mid)
#| }
#| out.push(" ".repeat(indent_by) + last + ",")
#| }
#| }
#| }
#| out.push(close)
#| out
#| }
#| }
#|}
#|fn comma_seq_lines(
#| begin : String,
#| end : String,
#| contents : Array[Array[String]],
#|) -> Array[String] {
#| if begin == "[" && end == "]" {
#| bracket_seq_lines("[", "]", 2, contents)
#| } else if begin == "{" && end == "}" {
#| bracket_seq_lines("{", "}", 2, contents)
#| } else if begin == "" && end == "" {
#| fn spacer(begin : String) -> String {
#| " ".repeat(begin.length())
#| }
#| let lines = match contents {
#| [] => [begin + end]
#| [item] => surround_lines(begin, end, item)
#| [first, .. middle, last] => {
#| let space = spacer(begin)
#| let middle_lines = []
#| for item in middle {
#| middle_lines.append(surround_lines(space, ",", item))
#| }
#| [
#| ..surround_lines(begin, ",", first),
#| ..middle_lines,
#| ..surround_lines(space, end, last),
#| ]
#| }
#| }
#| lines.filter(line => line != "")
#| } else {
#| let indent_by = 2
#| match contents {
#| [] => [begin + end]
#| [item] => {
#| let item_lines = item.filter(line => line != "")
#| match item_lines {
#| [] => [begin + end]
#| [x] => [begin + x + end]
#| [.. pre_lines, last_line] =>
#| [
#| begin,
#| ..pre_lines.iter().map(line => " ".repeat(indent_by) + line),
#| " ".repeat(indent_by) + last_line + ",",
#| end,
#| ]
#| }
#| }
#| _ => {
#| let out : Array[String] = [begin]
#| for item in contents {
#| let item_lines = item.filter(line => line != "")
#| match item_lines {
#| [] => ()
#| [x] => out.push(" ".repeat(indent_by) + x + ",")
#| [first, .. middle, last] => {
#| out.push(" ".repeat(indent_by) + first)
#| for mid in middle {
#| out.push(" ".repeat(indent_by) + mid)
#| }
#| out.push(" ".repeat(indent_by) + last + ",")
#| }
#| }
#| }
#| out.push(end)
#| out
#| }
#| }
#| }
#|}
#|fn comma_seq(
#| begin : String,
#| end : String,
#| contents : Array[ContentParens],
#|) -> Content {
#| for c in contents; size = 0 {
#| continue size + c.size
#| } nobreak {
#| {
#| size,
#| lines: comma_seq_lines(begin, end, contents.map(c => c.lines)),
#| needs_parens: false,
#| }
#| }
#|}
#|fn print_content(r : ContentParens) -> String {
#| r.lines.join("\n")
#|}
#|fn with_resizing(
#| _root_size : Int,
#| threshold : Int,
#| rendered_children : Content,
#|) -> Content {
#| if threshold <= 0 {
#| rendered_children
#| } else {
#| let compacted = rendered_children.compact()
#| if compacted.lines.all(line => line.length() <= threshold) {
#| compacted
#| } else {
#| rendered_children
#| }
#| }
#|}
),
"repr.mbt": (
#|enum Repr {
#| UnitLit
#| Integer(String)
#| DoubleLit(Double)
#| FloatLit(Float)
#| BoolLit(Bool)
#| CharLit(Char)
#| StringLit(String)
#| Tuple(Array[Repr])
#| Array(Array[Repr])
#| Record(Array[Repr])
#| Enum(String, Array[Repr])
#| Map(Array[Repr])
#| RecordField(String, Repr)
#| EnumLabeledArg(String, Repr)
#| Opaque(String, Repr)
#| Literal(String)
#| MapEntry(Repr, Repr)
#| Omitted
#|}
#|fn Repr::children(self : Repr) -> Array[Repr] {
#| match self {
#| UnitLit
#| | Integer(_)
#| | DoubleLit(_)
#| | FloatLit(_)
#| | BoolLit(_)
#| | CharLit(_)
#| | StringLit(_)
#| | Literal(_)
#| | Omitted => []
#| Tuple(xs) | Array(xs) | Record(xs) | Enum(_, xs) | Map(xs) => xs
#| Opaque(_, value) | RecordField(_, value) | EnumLabeledArg(_, value) =>
#| [value]
#| MapEntry(key, value) => [key, value]
#| }
#|}
#|fn Repr::with_children(self : Repr, children : Array[Repr]) -> Repr {
#| match self {
#| UnitLit
#| | Integer(_)
#| | DoubleLit(_)
#| | FloatLit(_)
#| | BoolLit(_)
#| | CharLit(_)
#| | StringLit(_)
#| | Literal(_)
#| | Omitted => self
#| Tuple(_) => Tuple(children)
#| Array(_) => Array(children)
#| Record(_) => Record(children)
#| Enum(name, _) => Enum(name, children)
#| Map(_) => Map(children)
#| RecordField(name, _) =>
#| match children {
#| [value] => RecordField(name, value)
#| _ => RecordField(name, Omitted)
#| }
#| EnumLabeledArg(label, _) =>
#| match children {
#| [value] => EnumLabeledArg(label, value)
#| _ => EnumLabeledArg(label, Omitted)
#| }
#| MapEntry(_, _) =>
#| match children {
#| [key, value] => MapEntry(key, value)
#| _ => MapEntry(Omitted, Omitted)
#| }
#| Opaque(name, _) =>
#| match children {
#| [value] => Opaque(name, value)
#| _ => Opaque(name, Omitted)
#| }
#| }
#|}
#|#doc(hidden)
#|pub fn Repr::traverse(self : Repr, f : (Repr) -> Repr) -> Repr {
#| fn go(node : Repr) -> Repr {
#| let children = node.children()
#| let next_children = children.map(child => go(child))
#| f(node.with_children(next_children))
#| }
#| go(self)
#|}
#|pub fn[T : Debug] Repr::Repr(value : T) -> Repr {
#| Debug::to_repr(value)
#|}
#|#doc(hidden)
#|pub fn Repr::integer(x : String) -> Repr {
#| Integer(x)
#|}
#|#doc(hidden)
#|pub fn Repr::double(x : Double) -> Repr {
#| DoubleLit(x)
#|}
#|#doc(hidden)
#|pub fn Repr::float(x : Float) -> Repr {
#| FloatLit(x)
#|}
#|#doc(hidden)
#|pub fn Repr::bool(x : Bool) -> Repr {
#| BoolLit(x)
#|}
#|#doc(hidden)
#|pub fn Repr::char(x : Char) -> Repr {
#| CharLit(x)
#|}
#|#doc(hidden)
#|pub fn Repr::string(x : String) -> Repr {
#| StringLit(x)
#|}
#|#doc(hidden)
#|pub fn Repr::tuple(children : Array[Repr]) -> Repr {
#| Tuple(children)
#|}
#|#doc(hidden)
#|pub fn Repr::array(children : Array[Repr]) -> Repr {
#| Array(children)
#|}
#|#doc(hidden)
#|pub fn Repr::record(fields : Map[String, Repr]) -> Repr {
#| Record([ for name, value in fields => RecordField(name, value) ])
#|}
#|#doc(hidden)
#|pub fn Repr::opaque_(name : String, children : Repr) -> Repr {
#| Opaque(name, children)
#|}
#|#doc(hidden)
#|pub fn Repr::literal(value : String) -> Repr {
#| Literal(value)
#|}
#|#doc(hidden)
#|pub fn Repr::map(contents : Array[(Repr, Repr)]) -> Repr {
#| Map(
#| contents.map(pair => {
#| let (k, v) = pair
#| MapEntry(k, v)
#| }),
#| )
#|}
#|#doc(hidden)
#|pub fn Repr::omitted() -> Repr {
#| Omitted
#|}
#|#doc(hidden)
#|pub fn Repr::unit() -> Repr {
#| UnitLit
#|}
#|#doc(hidden)
#|pub fn Repr::ctor(name : String, args : Array[(String?, Repr)]) -> Repr {
#| Enum(
#| name,
#| args.map(arg => {
#| let (label, value) = arg
#| match label {
#| None => value
#| Some(label) => EnumLabeledArg(label, value)
#| }
#| }),
#| )
#|}
#|fn Repr::shallow(self : Repr) -> Repr {
#| self.with_children([])
#|}
),
"tuple_debug.mbt": (
#|pub impl[A : Debug, B : Debug] Debug for (A, B) with fn to_repr(self) {
#| let (a, b) = self
#| Repr::tuple([Repr(a), Repr(b)])
#|}
#|pub impl[A : Debug, B : Debug, C : Debug] Debug for (A, B, C) with fn to_repr(
#| self,
#|) {
#| let (a, b, c) = self
#| Repr::tuple([Repr(a), Repr(b), Repr(c)])
#|}
#|pub impl[A : Debug, B : Debug, C : Debug, D : Debug] Debug for (A, B, C, D) with fn to_repr(
#| self,
#|) {
#| let (a, b, c, d) = self
#| Repr::tuple([Repr(a), Repr(b), Repr(c), Repr(d)])
#|}
#|pub impl[A : Debug, B : Debug, C : Debug, D : Debug, E : Debug] Debug for (
#| A,
#| B,
#| C,
#| D,
#| E,
#|) with fn to_repr(self) {
#| let (a, b, c, d, e) = self
#| Repr::tuple([Repr(a), Repr(b), Repr(c), Repr(d), Repr(e)])
#|}
#|pub impl[A : Debug, B : Debug, C : Debug, D : Debug, E : Debug, F : Debug] Debug for (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#|) with fn to_repr(self) {
#| let (a, b, c, d, e, f) = self
#| Repr::tuple([Repr(a), Repr(b), Repr(c), Repr(d), Repr(e), Repr(f)])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#|] Debug for (A, B, C, D, E, F, G) with fn to_repr(self) {
#| let (a, b, c, d, e, f, g) = self
#| Repr::tuple([Repr(a), Repr(b), Repr(c), Repr(d), Repr(e), Repr(f), Repr(g)])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#|] Debug for (A, B, C, D, E, F, G, H) with fn to_repr(self) {
#| let (a, b, c, d, e, f, g, h) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I) with fn to_repr(self) {
#| let (a, b, c, d, e, f, g, h, i) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J) with fn to_repr(self) {
#| let (a, b, c, d, e, f, g, h, i, j) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#| K : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J, K) with fn to_repr(self) {
#| let (a, b, c, d, e, f, g, h, i, j, k) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| Repr(k),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#| K : Debug,
#| L : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L) with fn to_repr(self) {
#| let (a, b, c, d, e, f, g, h, i, j, k, l) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| Repr(k),
#| Repr(l),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#| K : Debug,
#| L : Debug,
#| M : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M) with fn to_repr(self) {
#| let (a, b, c, d, e, f, g, h, i, j, k, l, m) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| Repr(k),
#| Repr(l),
#| Repr(m),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#| K : Debug,
#| L : Debug,
#| M : Debug,
#| N : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N) with fn to_repr(self) {
#| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| Repr(k),
#| Repr(l),
#| Repr(m),
#| Repr(n),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#| K : Debug,
#| L : Debug,
#| M : Debug,
#| N : Debug,
#| O : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) with fn to_repr(self) {
#| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| Repr(k),
#| Repr(l),
#| Repr(m),
#| Repr(n),
#| Repr(o),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#| K : Debug,
#| L : Debug,
#| M : Debug,
#| N : Debug,
#| O : Debug,
#| P : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) with fn to_repr(
#| self,
#|) {
#| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| Repr(k),
#| Repr(l),
#| Repr(m),
#| Repr(n),
#| Repr(o),
#| Repr(p),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#| K : Debug,
#| L : Debug,
#| M : Debug,
#| N : Debug,
#| O : Debug,
#| P : Debug,
#| Q : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) with fn to_repr(
#| self,
#|) {
#| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| Repr(k),
#| Repr(l),
#| Repr(m),
#| Repr(n),
#| Repr(o),
#| Repr(p),
#| Repr(q),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#| K : Debug,
#| L : Debug,
#| M : Debug,
#| N : Debug,
#| O : Debug,
#| P : Debug,
#| Q : Debug,
#| R : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) with fn to_repr(
#| self,
#|) {
#| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| Repr(k),
#| Repr(l),
#| Repr(m),
#| Repr(n),
#| Repr(o),
#| Repr(p),
#| Repr(q),
#| Repr(r),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#| K : Debug,
#| L : Debug,
#| M : Debug,
#| N : Debug,
#| O : Debug,
#| P : Debug,
#| Q : Debug,
#| R : Debug,
#| S : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S) with fn to_repr(
#| self,
#|) {
#| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| Repr(k),
#| Repr(l),
#| Repr(m),
#| Repr(n),
#| Repr(o),
#| Repr(p),
#| Repr(q),
#| Repr(r),
#| Repr(s),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#| K : Debug,
#| L : Debug,
#| M : Debug,
#| N : Debug,
#| O : Debug,
#| P : Debug,
#| Q : Debug,
#| R : Debug,
#| S : Debug,
#| T : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T) with fn to_repr(
#| self,
#|) {
#| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| Repr(k),
#| Repr(l),
#| Repr(m),
#| Repr(n),
#| Repr(o),
#| Repr(p),
#| Repr(q),
#| Repr(r),
#| Repr(s),
#| Repr(t),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#| K : Debug,
#| L : Debug,
#| M : Debug,
#| N : Debug,
#| O : Debug,
#| P : Debug,
#| Q : Debug,
#| R : Debug,
#| S : Debug,
#| T : Debug,
#| U : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U) with fn to_repr(
#| self,
#|) {
#| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| Repr(k),
#| Repr(l),
#| Repr(m),
#| Repr(n),
#| Repr(o),
#| Repr(p),
#| Repr(q),
#| Repr(r),
#| Repr(s),
#| Repr(t),
#| Repr(u),
#| ])
#|}
#|pub impl[
#| A : Debug,
#| B : Debug,
#| C : Debug,
#| D : Debug,
#| E : Debug,
#| F : Debug,
#| G : Debug,
#| H : Debug,
#| I : Debug,
#| J : Debug,
#| K : Debug,
#| L : Debug,
#| M : Debug,
#| N : Debug,
#| O : Debug,
#| P : Debug,
#| Q : Debug,
#| R : Debug,
#| S : Debug,
#| T : Debug,
#| U : Debug,
#| V : Debug,
#|] Debug for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V) with fn to_repr(
#| self,
#|) {
#| let (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v) = self
#| Repr::tuple([
#| Repr(a),
#| Repr(b),
#| Repr(c),
#| Repr(d),
#| Repr(e),
#| Repr(f),
#| Repr(g),
#| Repr(h),
#| Repr(i),
#| Repr(j),
#| Repr(k),
#| Repr(l),
#| Repr(m),
#| Repr(n),
#| Repr(o),
#| Repr(p),
#| Repr(q),
#| Repr(r),
#| Repr(s),
#| Repr(t),
#| Repr(u),
#| Repr(v),
#| ])
#|}
),
},
)
///|
let moonbitlang_core_deque_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/deque",
deps={},
files={
"bounds.mbt": (
#|#inline(never)
#|fn[T] index_out_of_bounds(len : Int, index : Int) -> T {
#| abort(
#| "index out of bounds: the len is from 0 to \{len} but the index is \{index}",
#| )
#|}
),
"debug.mbt": (
#|pub impl[A : @debug.Debug] @debug.Debug for Deque[A] with fn to_repr(self) {
#| @debug.Repr::opaque_(
#| "Deque",
#| @debug.Repr::array(self.to_array().map(x => Repr(x))),
#| )
#|}
#|test "Debug for Deque" {
#| let dq : Deque[Int] = from_array([1, 2, 3])
#| @debug.debug_inspect(dq, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `Deque([], capacity=...)` instead")
#|#as_free_fn(deprecated="Use `Deque([], capacity=...)` instead")
#|pub fn[A] Deque::new(capacity? : Int = 0) -> Deque[A] {
#| new_deque(capacity)
#|}
),
"deque.mbt": (
#|fn[A] fill_slots(
#| buf : UninitializedArray[A],
#| start : Int,
#| end : Int,
#| value : A,
#|) -> Unit {
#| for i in start.. Deque[A] {
#| { buf: UninitializedArray::make(capacity), len: 0, head: 0, }
#|}
#|fn[A] Deque::tail_index(self : Deque[A]) -> Int {
#| (self.head + self.len - 1) % self.buf.length()
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for Deque[A]
#|pub impl[A : Show] Show for Deque[A] with fn output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@deque.from_array([", suffix="])")
#|}
#|pub impl[A : Hash] Hash for Deque[A] with fn hash_combine(self, hasher) {
#| for v in self {
#| v.hash_combine(hasher)
#| }
#|}
#|pub impl[A] Add for Deque[A] with fn add(self, other) {
#| let len = self.len + other.len
#| let buf = self.unsafe_make_and_blit_to(len, 0)
#| other.unsafe_blit_to(buf, self.len)
#| { buf, len, head: 0, }
#|}
#|test "add_empty" {
#| let empty1 : Deque[Int] = new_deque(0)
#| let empty2 : Deque[Int] = new_deque(0)
#| let result = empty1 + empty2
#| inspect(result.len, content="0")
#| inspect(result.is_empty(), content="true")
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[A] Deque::Deque(arr : ArrayView[A], capacity? : Int) -> Deque[A] {
#| let len = arr.length()
#| let capacity = match capacity {
#| Some(capacity) => capacity.max(len)
#| None => len
#| }
#| let buf = UninitializedArray::make(capacity)
#| for i, x in arr {
#| buf[i] = x
#| }
#| { buf, len, head: 0, }
#|}
#|test "from_array_empty" {
#| let dq : Deque[Int] = from_array([])
#| inspect(dq.len, content="0")
#| inspect(dq.is_empty(), content="true")
#|}
#|#alias(clone, deprecated)
#|pub fn[A] Deque::copy(self : Deque[A]) -> Deque[A] {
#| let len = self.len
#| let buf = self.unsafe_make_and_blit_to(len, 0)
#| { buf, len, head: 0, }
#|}
#|pub fn[A] Deque::blit_to(
#| self : Deque[A],
#| dst : Deque[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.buf.length() {
#| dst.reserve_capacity(dst_offset + len)
#| dst.head = 0
#| }
#| let dst_len = dst.len
#| let needs_reverse = physical_equal(self, dst) &&
#| src_offset < dst_offset &&
#| src_offset + len > dst_offset
#| if needs_reverse {
#| let new_len = if dst_offset + len > dst_len {
#| dst_offset + len
#| } else {
#| dst_len
#| }
#| if new_len > dst_len {
#| dst.len = new_len
#| }
#| for i in len>..0 {
#| let dst_idx = (dst.head + dst_offset + i) % dst.buf.length()
#| let src_idx = (self.head + src_offset + i) % self.buf.length()
#| dst.buf[dst_idx] = self.buf[src_idx]
#| }
#| } else {
#| for i in 0..= dst_len {
#| dst.len += 1
#| }
#| }
#| }
#|}
#|pub fn[A] Deque::append(self : Deque[A], other : Deque[A]) -> Unit {
#| let other_len = other.len
#| let other_head = other.head
#| let other_buf = other.buf
#| let other_buf_len = other_buf.length()
#| guard other_len != 0 else { return }
#| let space = self.buf.length() - self.len
#| 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
#| }
#| let cap = self.buf.length()
#| for i in 0.. 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.buf.length() - self.len == 0 {
#| self.realloc()
#| }
#| let cap = self.buf.length()
#| if index < self.len / 2 {
#| let new_head = (self.head - 1 + cap) % cap
#| for i in 0.. index; i = i - 1 {
#| let from = (self.head + i - 1) % cap
#| let to = (self.head + i) % cap
#| self.buf[to] = self.buf[from]
#| }
#| }
#| self.buf[(self.head + index) % cap] = value
#| self.len += 1
#|}
#|pub fn[A] Deque::remove(self : Deque[A], index : Int) -> A {
#| guard index >= 0 && index < self.length() else {
#| abort(
#| "index out of bounds: the len is \{self.length()} but the index is \{index}",
#| )
#| }
#| let res = self[index]
#| let cap = self.buf.length()
#| if index < self.len / 2 {
#| let new_head = (self.head + 1) % cap
#| for i in index>..0 {
#| let to = (self.head + i + 1) % cap
#| let from = (self.head + i) % cap
#| self.buf[to] = self.buf[from]
#| }
#| self.head = new_head
#| } else {
#| for i in (index + 1).. Int {
#| self.len
#|}
#|pub fn[A] Deque::capacity(self : Deque[A]) -> Int {
#| self.buf.length()
#|}
#|fn[A] Deque::realloc(self : Deque[A]) -> Unit {
#| let old_cap = self.buf.length()
#| let new_cap = if old_cap == 0 { 8 } else { old_cap * 2 }
#| let new_buf = self.unsafe_make_and_blit_to(new_cap, 0)
#| self.head = 0
#| self.buf = new_buf
#|}
#|pub fn[A] Deque::front(self : Deque[A]) -> A? {
#| if self.len == 0 {
#| None
#| } else {
#| Some(self.buf[self.head])
#| }
#|}
#|pub fn[A] Deque::back(self : Deque[A]) -> A? {
#| if self.len == 0 {
#| None
#| } else {
#| Some(self.buf[self.tail_index()])
#| }
#|}
#|#owned(value)
#|pub fn[A] Deque::push_front(self : Deque[A], value : A) -> Unit {
#| if self.len == self.buf.length() {
#| self.realloc()
#| }
#| let cap = self.buf.length()
#| self.head = (self.head - 1 + cap) % cap
#| self.buf[self.head] = value
#| self.len += 1
#|}
#|#owned(value)
#|pub fn[A] Deque::push_back(self : Deque[A], value : A) -> Unit {
#| if self.len == self.buf.length() {
#| self.realloc()
#| }
#| let cap = self.buf.length()
#| let write_idx = (self.head + self.len) % cap
#| self.buf[write_idx] = value
#| self.len += 1
#|}
#|#internal(unsafe, "Panic if the deque is empty.")
#|#doc(hidden)
#|#alias(pop_front_exn, deprecated)
#|pub fn[A] Deque::unsafe_pop_front(self : Deque[A]) -> Unit {
#| guard self.len > 0 else { abort("The deque is empty!") }
#| let cap = self.buf.length()
#| self.head = (self.head + 1) % cap
#| self.len -= 1
#|}
#|test "unsafe_pop_front after many push_front" {
#| let dq = new_deque(0)
#| for i in 0..<10 {
#| dq.push_front(i)
#| }
#| for _ in 0..<10 {
#| dq.unsafe_pop_front()
#| }
#| @test.assert_eq(dq.len, 0)
#|}
#|#internal(unsafe, "Panic if the deque is empty.")
#|#doc(hidden)
#|#alias(pop_back_exn, deprecated)
#|pub fn[A] Deque::unsafe_pop_back(self : Deque[A]) -> Unit {
#| guard self.len > 0 else { abort("The deque is empty!") }
#| self.len -= 1
#|}
#|pub fn[A] Deque::pop_front(self : Deque[A]) -> A? {
#| guard self.len > 0 else { return None }
#| let value = self.buf[self.head]
#| let cap = self.buf.length()
#| self.head = (self.head + 1) % cap
#| self.len -= 1
#| Some(value)
#|}
#|pub fn[A] Deque::pop_back(self : Deque[A]) -> A? {
#| guard self.len > 0 else { return None }
#| let tail_idx = self.tail_index()
#| let value = self.buf[tail_idx]
#| self.len -= 1
#| Some(value)
#|}
#|#alias("_[_]")
#|pub fn[A] Deque::at(self : Deque[A], index : Int) -> A {
#| if index < 0 || index >= self.len {
#| index_out_of_bounds(self.len, index)
#| }
#| if self.head + index < self.buf.length() {
#| self.buf[self.head + index]
#| } else {
#| self.buf[self.head + index - self.buf.length()]
#| }
#|}
#|#alias("_[_]=_")
#|#owned(value)
#|pub fn[A] Deque::set(self : Deque[A], index : Int, value : A) -> Unit {
#| if index < 0 || index >= self.len {
#| index_out_of_bounds(self.len, 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]) -> (ArrayView[A], ArrayView[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])
#| }
#|}
#|fn[A] Deque::unsafe_blit_to(
#| self : Deque[A],
#| dst : UninitializedArray[A],
#| dst_offset : Int,
#|) -> Unit {
#| guard self.len != 0 else { return }
#| let (front, back) = self.as_views()
#| dst.unsafe_blit(dst_offset, self.buf, front.start_offset(), front.length())
#| dst.unsafe_blit(
#| dst_offset + front.length(),
#| self.buf,
#| back.start_offset(),
#| back.length(),
#| )
#|}
#|fn[A] Deque::unsafe_make_and_blit_to(
#| self : Deque[A],
#| allocate_len : Int,
#| dst_offset : Int,
#|) -> UninitializedArray[A] {
#| guard self.len != 0 else { return UninitializedArray::make(allocate_len) }
#| let (front, back) = self.as_views()
#| let dst = UninitializedArray::make_and_blit(
#| self.buf,
#| allocate_len~,
#| src_offset=front.start_offset(),
#| dst_offset~,
#| len=front.length(),
#| )
#| dst.unsafe_blit(
#| dst_offset + front.length(),
#| self.buf,
#| back.start_offset(),
#| back.length(),
#| )
#| dst
#|}
#|pub impl[A : Eq] Eq for Deque[A] with fn equal(self, other) {
#| if self.len != other.len {
#| return false
#| }
#| for i in 0.. Unit raise?) -> Unit raise? {
#| for v in self {
#| f(v)
#| }
#|}
#|#locals(f)
#|pub fn[A] Deque::eachi(
#| self : Deque[A],
#| f : (Int, A) -> Unit raise?,
#|) -> Unit raise? {
#| for i, v in self {
#| f(i, v)
#| }
#|}
#|#locals(f)
#|pub fn[A] Deque::rev_each(
#| self : Deque[A],
#| f : (A) -> Unit raise?,
#|) -> Unit raise? {
#| for v in self.rev_iter() {
#| f(v)
#| }
#|}
#|#locals(f)
#|pub fn[A] Deque::rev_eachi(
#| self : Deque[A],
#| f : (Int, A) -> Unit raise?,
#|) -> Unit raise? {
#| for i, v in self.rev_iter2() {
#| f(i, v)
#| }
#|}
#|pub fn[A] Deque::clear(self : Deque[A]) -> Unit {
#| self.len = 0
#| self.head = 0
#|}
#|#locals(f)
#|pub fn[A, U] Deque::map(
#| self : Deque[A],
#| f : (A) -> U raise?,
#|) -> Deque[U] raise? {
#| let cap = self.buf.length()
#| if self.len == 0 {
#| new_deque(0)
#| } else {
#| let buf : UninitializedArray[U] = UninitializedArray::make(self.len)
#| for i in 0.. U raise?,
#|) -> Deque[U] raise? {
#| let cap = self.buf.length()
#| if self.len == 0 {
#| new_deque(0)
#| } else {
#| let buf : UninitializedArray[U] = UninitializedArray::make(self.len)
#| for i in 0.. Bool {
#| self.len == 0
#|}
#|pub fn[A : Eq] Deque::search(self : Deque[A], value : A) -> Int? {
#| let cap = self.buf.length()
#| for i in 0.. Bool {
#| self.iter().contains(value)
#|}
#|#locals(f)
#|pub fn[A] Deque::extract_if(self : Deque[A], f : (A) -> Bool) -> Deque[A] {
#| guard !self.is_empty() else { from_array([]) }
#| let removed = from_array([])
#| for read in 0.. Bool raise?,
#|) -> Deque[A] raise? {
#| let dq = from_array([])
#| for v in self {
#| if f(v) {
#| dq.push_back(v)
#| }
#| }
#| dq
#|}
#|pub fn[A] Deque::reserve_capacity(self : Deque[A], capacity : Int) -> Unit {
#| if self.capacity() >= capacity {
#| return
#| }
#| let new_buf = self.unsafe_make_and_blit_to(capacity, 0)
#| self.buf = new_buf
#| self.head = 0
#|}
#|pub fn[A] Deque::shrink_to_fit(self : Deque[A]) -> Unit {
#| if self.capacity() <= self.length() {
#| return
#| }
#| let new_buf = self.unsafe_make_and_blit_to(self.len, 0)
#| self.buf = new_buf
#| self.head = 0
#|}
#|pub fn[A] Deque::release_unused(self : Deque[A], placeholder~ : A) -> Unit {
#| let cap = self.buf.length()
#| let head_len = cap - self.head
#| if self.len <= head_len {
#| fill_slots(self.buf, 0, self.head, placeholder)
#| fill_slots(self.buf, self.head + self.len, cap, placeholder)
#| } else {
#| fill_slots(self.buf, self.len - head_len, self.head, placeholder)
#| }
#|}
#|pub fn[A] Deque::truncate(self : Deque[A], len : Int) -> Unit {
#| guard len >= 0 && len < self.len else { return }
#| self.len = len
#| if len == 0 {
#| self.head = 0
#| }
#|}
#|test "truncate zero" {
#| let dq = from_array([1, 2, 3])
#| dq.truncate(0)
#| inspect(dq.len, content="0")
#|}
#|#locals(f)
#|#alias(filter_map_inplace, deprecated)
#|pub fn[A] Deque::retain_map(self : Deque[A], f : (A) -> A?) -> Unit {
#| guard !self.is_empty() else { return }
#| let { head, buf, .. } = self
#| let cap = buf.length()
#| let (front, back) = self.as_views()
#| let (idx, kept_len) = for cur in front; idx = head, kept_len = 0 {
#| if f(cur) is Some(v) {
#| buf[idx] = v
#| continue idx + 1, kept_len + 1
#| }
#| continue idx, kept_len
#| } nobreak {
#| (idx, kept_len)
#| }
#| if back.is_empty() {
#| self.truncate(kept_len)
#| return
#| }
#| let kept_len = for cur in back; idx = idx, kept_len = kept_len {
#| let idx = if idx == cap { 0 } else { idx }
#| if f(cur) is Some(v) {
#| buf[idx] = v
#| continue idx + 1, kept_len + 1
#| }
#| continue idx, kept_len
#| } nobreak {
#| kept_len
#| }
#| self.truncate(kept_len)
#|}
#|#locals(f)
#|pub fn[A] Deque::retain(self : Deque[A], f : (A) -> Bool) -> Unit {
#| guard !self.is_empty() else { return }
#| let { head, buf, .. } = self
#| let cap = buf.length()
#| let (front, back) = self.as_views()
#| let (idx, kept_len) = for cur in front; idx = head, kept_len = 0 {
#| if f(cur) {
#| buf[idx] = cur
#| continue idx + 1, kept_len + 1
#| }
#| continue idx, kept_len
#| } nobreak {
#| (idx, kept_len)
#| }
#| if back.is_empty() {
#| self.truncate(kept_len)
#| return
#| }
#| let kept_len = for cur in back; idx = idx, kept_len = kept_len {
#| let idx = if idx == cap { 0 } else { idx }
#| if f(cur) {
#| buf[idx] = cur
#| continue idx + 1, kept_len + 1
#| }
#| continue idx, kept_len
#| } nobreak {
#| kept_len
#| }
#| self.truncate(kept_len)
#|}
#|#alias(iterator, deprecated)
#|pub fn[A] Deque::iter(self : Deque[A]) -> Iter[A] {
#| let mut index = 0
#| let len = self.len
#| Iter::new(
#| fn() {
#| guard index < len else { None }
#| let elem = self.buf[(self.head + index) % self.buf.length()]
#| index += 1
#| Some(elem)
#| },
#| size_hint=len,
#| )
#|}
#|#alias(iterator2, deprecated)
#|pub fn[A] Deque::iter2(self : Deque[A]) -> Iter2[Int, A] {
#| let mut index = 0
#| let len = self.len
#| Iter2::new(
#| fn() {
#| guard index < len else { None }
#| let result = (index, self.buf[(self.head + index) % self.buf.length()])
#| index += 1
#| Some(result)
#| },
#| size_hint=len,
#| )
#|}
#|#alias(rev_iterator, deprecated)
#|pub fn[A] Deque::rev_iter(self : Deque[A]) -> Iter[A] {
#| let len = self.len
#| let mut index = len
#| Iter::new(
#| fn() {
#| guard index > 0 else { None }
#| index -= 1
#| Some(self.buf[(self.head + index) % self.buf.length()])
#| },
#| size_hint=len,
#| )
#|}
#|#alias(rev_iterator2, deprecated)
#|pub fn[A] Deque::rev_iter2(self : Deque[A]) -> Iter2[Int, A] {
#| let len = self.len
#| let mut rev_index = len
#| Iter2::new(
#| fn() {
#| guard rev_index > 0 else { None }
#| let index = len - rev_index
#| rev_index -= 1
#| Some((index, self.buf[(self.head + rev_index) % self.buf.length()]))
#| },
#| size_hint=len,
#| )
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[A] Deque::from_iter(iter : Iter[A]) -> Deque[A] {
#| let dq = new_deque(0)
#| while iter.next() is Some(e) {
#| dq.push_back(e)
#| }
#| dq
#|}
#|pub fn[A] Deque::to_array(self : Deque[A]) -> Array[A] {
#| let len = self.length()
#| if len == 0 {
#| return []
#| }
#| let xs = Array::unsafe_make_uninit(len)
#| for i in 0.. String {
#| self.iter().join(separator)
#|}
#|pub impl[A : ToJson] ToJson for Deque[A] with fn to_json(self : Deque[A]) -> Json {
#| [
#| for x in self => x
#| ]
#|}
#|pub impl[A : @json.FromJson] @json.FromJson for Deque[A] with fn from_json(
#| json,
#| path,
#|) {
#| guard json is Array(arr) else {
#| raise JsonDecodeError((path, "Deque::from_json: expected array"))
#| }
#| let len = arr.length()
#| let buf = UninitializedArray::make(len)
#| for i, x in arr {
#| buf[i] = @json.FromJson::from_json(x, path.add_index(i))
#| }
#| { len, buf, head: 0, }
#|}
#|pub fn[A] Deque::chunks(self : Deque[A], size : Int) -> Deque[Deque[A]] {
#| guard! size > 0
#| let chunks = from_array([])
#| for i = 0; i < self.length(); {
#| let chunk = Deque([], capacity=size)
#| let i = for _ in 0..= self.length() {
#| break i
#| }
#| chunk.push_back(self[i])
#| continue i + 1
#| } nobreak {
#| i
#| }
#| chunks.push_back(chunk)
#| continue i
#| }
#| chunks
#|}
#|#locals(pred)
#|pub fn[A] Deque::chunk_by(
#| self : Deque[A],
#| pred : (A, A) -> Bool raise?,
#|) -> Deque[Deque[A]] raise? {
#| let chunks = from_array([])
#| for i = 0; i < self.length(); {
#| let chunk = from_array([])
#| chunk.push_back(self[i])
#| let i = for i = i + 1; i < self.length() && pred(self[i - 1], self[i]); {
#| chunk.push_back(self[i])
#| continue i + 1
#| } nobreak {
#| i
#| }
#| chunks.push_back(chunk)
#| continue i
#| }
#| chunks
#|}
#|pub fn[A] Deque::flatten(self : Deque[Deque[A]]) -> Deque[A] {
#| let len = for deque in self; len = 0 {
#| continue len + deque.length()
#| } nobreak {
#| len
#| }
#| let target = Deque::{ buf: UninitializedArray::make(len), len, head: 0, }
#| for deque in self; i = 0 {
#| let (front, back) = deque.as_views()
#| target.buf.unsafe_blit(i, deque.buf, front.start_offset(), front.length())
#| let i = i + front.length()
#| target.buf.unsafe_blit(i, deque.buf, back.start_offset(), back.length())
#| continue i + back.length()
#| }
#| target
#|}
#|pub fn[A] Deque::drain(self : Deque[A], start~ : Int, len? : Int) -> Deque[A] {
#| guard start >= 0 && start <= self.len else {
#| abort(
#| "Deque::drain: start index out of bounds (start=\{start}, deque.length()=\{self.len})",
#| )
#| }
#| let len = match len {
#| Some(l) => {
#| guard l >= 0 && start + l <= self.len else {
#| abort(
#| "Deque::drain: len out of bounds (start=\{start}, len=\{l}, deque.length()=\{self.len})",
#| )
#| }
#| l
#| }
#| None => self.len - start
#| }
#| if len == 0 {
#| return new_deque(0)
#| }
#| let deque = Deque::{ buf: UninitializedArray::make(len), len, head: 0, }
#| let (front, back) = self.as_views()
#| if start < front.length() {
#| let front_max_drain = front.length() - start
#| if len <= front_max_drain {
#| deque.buf.unsafe_blit(0, self.buf, front.start_offset() + start, len)
#| if start == 0 && len == front_max_drain {
#| self.head = 0
#| } else if len < front_max_drain || back.length() != 0 {
#| let new_head = front.start_offset() + len
#| self.buf.unsafe_blit(new_head, self.buf, front.start_offset(), start)
#| self.head = new_head
#| }
#| } else {
#| deque.buf.unsafe_blit(
#| 0,
#| self.buf,
#| front.start_offset() + start,
#| front_max_drain,
#| )
#| deque.buf.unsafe_blit(front_max_drain, self.buf, 0, len - front_max_drain)
#| if start > 0 {
#| let back_remaining = len - front_max_drain
#| let back_len = back.length() - back_remaining
#| if back_len != 0 {
#| let new_head = front.start_offset() + front_max_drain
#| self.buf.unsafe_blit(new_head, self.buf, front.start_offset(), start)
#| self.head = new_head
#| self.buf.unsafe_blit(0, self.buf, back_remaining, back_len)
#| }
#| } else {
#| self.head = len - front_max_drain
#| }
#| }
#| } else {
#| let back_start = start - front.length()
#| deque.buf.unsafe_blit(0, self.buf, back_start, len)
#| self.buf.unsafe_blit(
#| back_start,
#| self.buf,
#| back_start + len,
#| back.length() - back_start - len,
#| )
#| }
#| self.len -= len
#| if self.len == 0 {
#| self.head = 0
#| }
#| deque
#|}
#|test "weird behavior after drain" {
#| let deque = new_deque(16)
#| deque.push_back(1)
#| deque.push_back(2)
#| deque.push_back(3)
#| deque.push_back(4)
#| ignore(deque.pop_front())
#| ignore(deque.pop_front())
#| ignore(deque.pop_front())
#| deque.push_back(5)
#| ignore(deque.pop_front())
#| deque.push_back(6)
#| ignore(deque.pop_front())
#| deque.push_back(7)
#| ignore(deque.pop_front())
#| deque.push_back(8)
#| ignore(deque.pop_front())
#| deque.push_back(9)
#| deque.push_back(10)
#| deque.push_back(11)
#| ignore(deque.pop_front())
#| ignore(deque.pop_front())
#| deque.push_back(12)
#| deque.push_back(13)
#| ignore(deque.pop_front())
#| deque.push_back(14)
#| ignore(deque.pop_front())
#| ignore(deque.drain(start=0, len=2))
#| deque.push_back(15)
#| ignore(deque.pop_front())
#| deque.push_back(16)
#| ignore(deque.pop_front())
#| deque.push_back(17)
#| ignore(deque.pop_front())
#| deque.push_back(18)
#| ignore(deque.pop_front())
#| deque.push_back(19)
#| ignore(deque.pop_front())
#| deque.push_back(20)
#| deque.push_back(21)
#| deque.push_back(22)
#| ignore(deque.pop_front())
#| ignore(deque.pop_front())
#| ignore(deque.pop_front())
#| deque.push_back(23)
#| deque.push_back(24)
#| deque.push_back(25)
#| ignore(deque.pop_front())
#| ignore(deque.pop_front())
#| deque.push_back(26)
#| deque.push_back(27)
#| ignore(deque.pop_front())
#| ignore(deque.pop_front())
#| ignore(deque.pop_front())
#| deque.push_back(28)
#| ignore(deque.pop_front())
#| deque.push_back(29)
#| ignore(deque.pop_front())
#| deque.push_back(30)
#| @debug.debug_inspect(
#| deque.as_views(),
#| content=(
#| #|(, )
#| ),
#| )
#| ignore(deque.drain(start=0, len=2))
#| @debug.debug_inspect(
#| deque.as_views(),
#| content=(
#| #|(, )
#| ),
#| )
#| deque.push_back(31)
#| deque.push_back(32)
#| @debug.debug_inspect(
#| deque.as_views(),
#| content=(
#| #|(, )
#| ),
#| )
#| ignore(deque.pop_front())
#|}
#|#locals(cmp)
#|pub fn[A] Deque::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
#| }
#| } nobreak {
#| if i < len && cmp(self[i]) == 0 {
#| Ok(i)
#| } else {
#| Err(i)
#| }
#| }
#|}
#|pub fn[A] Deque::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] Deque::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 fn 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()
#| for _ in 0..<(self.len / 2); left = self.head, right = self.tail_index() {
#| let temp = self.buf[left]
#| self.buf[left] = self.buf[right]
#| self.buf[right] = temp
#| continue (left + 1) % cap, (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 in n>..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] Deque::shuffle(self : Deque[A], rand~ : (Int) -> Int) -> Deque[A] {
#| let new_deque = self.copy()
#| new_deque.shuffle_in_place(rand~)
#| new_deque
#|}
),
"extends.mbt": (
#|pub extend Deque with Add::{add}
#|pub extend Deque with Compare::{compare}
#|pub extend Deque with Eq::{equal}
#|pub extend Deque with Hash::{hash}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Deque with @debug.Debug::{to_repr}
#|#deprecated("Use `@json.from_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Deque with @json.FromJson::{from_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Deque with Compare::{op_ge, op_gt, op_le, op_lt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Deque with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Deque with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Deque with Show::{output, to_string}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Deque with ToJson::{to_json}
),
"types.mbt": (
#|struct Deque[A] {
#| mut buf : UninitializedArray[A]
#| mut len : Int
#| mut head : Int
#|}
),
},
)
///|
let moonbitlang_core_diff_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/diff",
deps={},
files={
"backpointer.mbt": (
#|priv struct BackPointer {
#| value : (Int, Int)
#| prev : BackPointer?
#|}
#|fn BackPointer::to_array(self : BackPointer) -> Array[(Int, Int)] {
#| let result = []
#| let mut self = self
#| while self.prev is Some(prev) {
#| result.push(self.value)
#| self = prev
#| }
#| result.push(self.value)
#| return result.rev()
#|}
),
"compact.mbt": (
#|priv struct CompactedElements[T]((ArrayView[T], FixedArray[Int]))
#|#alias("_[_]")
#|fn[T] CompactedElements::at(self : CompactedElements[T], index : Int) -> T {
#| let (source, indices) = self.0
#| source[indices[index]]
#|}
#|fn[T] CompactedElements::get_index(
#| self : CompactedElements[T],
#| index : Int,
#|) -> Int {
#| let (_, indices) = self.0
#| indices[index]
#|}
#|fn[T] CompactedElements::indices_length(self : CompactedElements[T]) -> Int {
#| self.0.1.length()
#|}
#|fn[T] CompactedElements::source_length(self : CompactedElements[T]) -> Int {
#| self.0.0.length()
#|}
),
"diff.mbt": (
#|#valtype
#|priv struct Partition {
#| lhs_midpoint : Int // position of midpoint in sequence lhs
#| rhs_midpoint : Int // position of midpoint in sequence rhs
#| lo_minimal : Bool // whether left half is optimal
#| hi_minimal : Bool // whether right half is optimal
#|}
#|fn[T : Eq] diag(
#| forward_search_diagonal~ : FixedArray[Int], // forward search diagonal array - stores farthest reachable point on each diagonal
#| backward_search_diagonal~ : FixedArray[Int], // backward search diagonal array - stores nearest reachable point on each diagonal
#| diagonal_shift~ : Int, // diagonal index shift: store diagonal k at [sh + k], including negative k and k±1/k±2 neighbors
#| lhs~ : CompactedElements[T], // compacted elements for sequence lhs
#| rhs~ : CompactedElements[T], // compacted elements for sequence rhs
#| lhs_offset~ : Int, // starting position of sequence lhs - defines left boundary of search window
#| lhs_limit~ : Int, // ending position of sequence lhs - defines right boundary of search window
#| rhs_offset~ : Int, // starting position of sequence rhs - defines upper boundary of search window
#| rhs_limit~ : Int, // ending position of sequence rhs - defines lower boundary of search window
#| too_expensive~ : Int, // computation cost threshold - use heuristic algorithm when exceeded
#| find_minimal~ : Bool, // optimality flag - whether optimal solution must be found
#|) -> Partition {
#| let dmin = lhs_offset - rhs_limit // minimum valid diagonal - corresponds to maximum insertions
#| let dmax = lhs_limit - rhs_offset // maximum valid diagonal - corresponds to maximum deletions
#| let fmid = lhs_offset - rhs_offset // center diagonal for forward search - diagonal corresponding to starting point
#| let bmid = lhs_limit - rhs_limit // center diagonal for backward search - diagonal corresponding to end point
#| let odd = ((fmid - bmid) & 1) != 0
#| forward_search_diagonal[diagonal_shift + fmid] = lhs_offset // forward search starts from (lhs_offset, rhs_offset)
#| backward_search_diagonal[diagonal_shift + bmid] = lhs_limit // backward search starts from (lhs_limit, rhs_limit)
#| for c = 1, fmin = fmid, fmax = fmid, bmin = bmid, bmax = bmid {
#| let fmin = if fmin > dmin {
#| forward_search_diagonal[diagonal_shift + fmin - 2] = -1 // mark unused diagonal
#| fmin - 1 // extend to next diagonal
#| } else {
#| fmin + 1 // boundary constraint
#| }
#| let fmax = if fmax < dmax {
#| forward_search_diagonal[diagonal_shift + fmax + 2] = -1 // mark unused diagonal
#| fmax + 1 // extend to previous diagonal
#| } else {
#| fmax - 1 // boundary constraint
#| }
#| let mut forward_result : Partition? = None
#| let mut d = fmax
#| while d >= fmin {
#| let tlo = forward_search_diagonal[diagonal_shift + d - 1]
#| let thi = forward_search_diagonal[diagonal_shift + d + 1]
#| let x = if tlo >= thi { tlo + 1 } else { thi }
#| let (x_cur, y_cur) = for x_cur = x, y_cur = x - d {
#| if x_cur < lhs_limit && y_cur < rhs_limit && lhs[x_cur] == rhs[y_cur] {
#| continue x_cur + 1, y_cur + 1
#| } else {
#| break (x_cur, y_cur)
#| }
#| }
#| forward_search_diagonal[diagonal_shift + d] = x_cur
#| if odd &&
#| bmin <= d &&
#| d <= bmax &&
#| backward_search_diagonal[diagonal_shift + d] <=
#| forward_search_diagonal[diagonal_shift + d] {
#| forward_result = Some({
#| lhs_midpoint: x_cur,
#| rhs_midpoint: y_cur,
#| lo_minimal: true, // forward path is optimal
#| hi_minimal: true, // backward path is also optimal
#| })
#| break // found meeting point, exit early
#| }
#| d -= 2 // Myers algorithm characteristic: only check diagonals with same parity
#| }
#| match forward_result {
#| Some(result) => break result
#| None => ()
#| }
#| let bmin = if bmin > dmin {
#| backward_search_diagonal[diagonal_shift + bmin - 2] = @int.MAX_VALUE // mark unused diagonal as max value
#| bmin - 1
#| } else {
#| bmin + 1
#| }
#| let bmax = if bmax < dmax {
#| backward_search_diagonal[diagonal_shift + bmax + 2] = @int.MAX_VALUE // mark unused diagonal as max value
#| bmax + 1
#| } else {
#| bmax - 1
#| }
#| let mut backward_result : Partition? = None
#| let mut d = bmax
#| while d >= bmin {
#| let tlo = backward_search_diagonal[diagonal_shift + d - 1]
#| let thi = backward_search_diagonal[diagonal_shift + d + 1]
#| let x = if tlo < thi { tlo } else { thi - 1 }
#| let (x_cur, y_cur) = for x_cur = x, y_cur = x - d {
#| if x_cur > lhs_offset &&
#| y_cur > rhs_offset &&
#| lhs[x_cur - 1] == rhs[y_cur - 1] {
#| continue x_cur - 1, y_cur - 1
#| } else {
#| break (x_cur, y_cur)
#| }
#| }
#| backward_search_diagonal[diagonal_shift + d] = x_cur
#| if !odd &&
#| fmin <= d &&
#| d <= fmax &&
#| backward_search_diagonal[diagonal_shift + d] <=
#| forward_search_diagonal[diagonal_shift + d] {
#| backward_result = Some({
#| lhs_midpoint: x_cur,
#| rhs_midpoint: y_cur,
#| lo_minimal: true,
#| hi_minimal: true,
#| })
#| break
#| }
#| d -= 2
#| }
#| match backward_result {
#| Some(result) => break result
#| None => ()
#| }
#| if !find_minimal && c >= too_expensive {
#| let mut fxybest = -1
#| let mut fxbest = fmax
#| let mut d = fmax
#| while d >= fmin {
#| let x = lhs_limit.min(forward_search_diagonal[diagonal_shift + d]) // limit to valid range
#| let y = x - d
#| let (x, y) = if rhs_limit < y {
#| (rhs_limit + d, rhs_limit)
#| } else {
#| (x, y)
#| }
#| if fxybest < x + y {
#| fxybest = x + y
#| fxbest = x
#| }
#| d -= 2
#| }
#| let mut bxybest = @int.MAX_VALUE
#| let mut bxbest = bmax
#| let mut d = bmax
#| while d >= bmin {
#| let x = lhs_offset.max(backward_search_diagonal[diagonal_shift + d]) // limit to valid range
#| let y = x - d
#| let (x, y) = if y < rhs_offset {
#| (rhs_offset + d, rhs_offset)
#| } else {
#| (x, y)
#| }
#| if x + y < bxybest {
#| bxybest = x + y
#| bxbest = x
#| }
#| d -= 2
#| }
#| if lhs_limit + rhs_limit - bxybest < fxybest - (lhs_offset + rhs_offset) {
#| break {
#| lhs_midpoint: fxbest,
#| rhs_midpoint: fxybest - fxbest,
#| lo_minimal: true,
#| hi_minimal: false, // right half is not optimal
#| }
#| } else {
#| break {
#| lhs_midpoint: bxbest,
#| rhs_midpoint: bxybest - bxbest,
#| lo_minimal: false, // left half is not optimal
#| hi_minimal: true,
#| }
#| }
#| } else {
#| continue c + 1, fmin, fmax, bmin, bmax
#| }
#| }
#|}
#|fn[T : Eq] diff_loop(
#| cutoff : Int?, // computation cost threshold
#| lhs : CompactedElements[T],
#| rhs : CompactedElements[T],
#|) -> (FixedArray[Bool], FixedArray[Bool]) {
#| let forward_search_diagonal = FixedArray::make(
#| lhs.indices_length() + rhs.indices_length() + 3,
#| 0,
#| ) // forward search array
#| let backward_search_diagonal = FixedArray::make(
#| lhs.indices_length() + rhs.indices_length() + 3,
#| 0,
#| ) // backward search array
#| let diagonal_shift = rhs.indices_length() + 1
#| let too_expensive = match cutoff {
#| Some(c) => c
#| None => {
#| let diags = lhs.indices_length() + rhs.indices_length() + 3
#| for acc = 1, diags_cur = diags {
#| if diags_cur != 0 {
#| continue acc << 1, diags_cur >> 2
#| } else {
#| break acc.max(4096) // at least 4096, ensuring reasonable performance
#| }
#| }
#| }
#| }
#| let lhs_change_markers = FixedArray::make(lhs.source_length(), true)
#| let rhs_change_markers = FixedArray::make(rhs.source_length(), true)
#| for i in 0.. Unit {
#| let (lhs_offset, rhs_offset) = for lhs_offset = lhs_offset, rhs_offset = rhs_offset {
#| if lhs_offset < lhs_limit &&
#| rhs_offset < rhs_limit &&
#| lhs[lhs_offset] == rhs[rhs_offset] {
#| continue lhs_offset + 1, rhs_offset + 1
#| } else {
#| break (lhs_offset, rhs_offset)
#| }
#| }
#| let (lhs_limit, rhs_limit) = for lhs_limit = lhs_limit, rhs_limit = rhs_limit {
#| if lhs_limit > lhs_offset &&
#| rhs_limit > rhs_offset &&
#| lhs[lhs_limit - 1] == rhs[rhs_limit - 1] {
#| continue lhs_limit - 1, rhs_limit - 1
#| } else {
#| break (lhs_limit, rhs_limit)
#| }
#| }
#| if lhs_offset == lhs_limit {
#| for y in rhs_offset.. FixedArray[Int] {
#| let n = a.length()
#| let present : Map[T, Bool] = Map([], capacity=b.length())
#| for i in 0.. (FixedArray[Bool], FixedArray[Bool]) {
#| let lhs_indices = make_indexer(lhs, rhs) // indices of lhs elements that exist in rhs
#| let rhs_indices = make_indexer(rhs, lhs) // indices of rhs elements that exist in lhs
#| let lhs = CompactedElements((lhs, lhs_indices))
#| let rhs = CompactedElements((rhs, rhs_indices))
#| diff_loop(cutoff, lhs, rhs)
#|}
#|fn[T : Eq + Hash] iter_matches(
#| cutoff~ : Int?, // optional computation cost limit
#| old~ : ArrayView[T], // original array
#| new~ : ArrayView[T], // new array
#|) -> Iter2[Int, Int] {
#| let (d1, d2) = diff_(cutoff, old, new)
#| let mut i1 = 0
#| let mut i2 = 0
#| fn go() {
#| while i1 < d1.length() && i2 < d2.length() {
#| if !d1[i1] {
#| if !d2[i2] {
#| let matching_pair = (i1, i2)
#| i1 += 1
#| i2 += 1
#| return Some(matching_pair)
#| }
#| i2 += 1
#| } else if !d2[i2] {
#| i1 += 1
#| } else {
#| i1 += 1
#| i2 += 1
#| }
#| }
#| None // reached end of arrays
#| }
#| Iter2::new(go)
#|}
#|fn[T : Eq + Hash] append_myers_matches(
#| matches : Array[(Int, Int)],
#| cutoff : Int?,
#| old : ArrayView[T],
#| new : ArrayView[T],
#| old_offset : Int,
#| new_offset : Int,
#|) -> Unit {
#| for old_idx, new_idx in iter_matches(cutoff~, old~, new~) {
#| matches.push((old_offset + old_idx, new_offset + new_idx))
#| }
#|}
#|fn[T : Eq + Hash] append_patience_matches(
#| matches : Array[(Int, Int)],
#| cutoff : Int?,
#| old : ArrayView[T],
#| new : ArrayView[T],
#| old_offset : Int,
#| new_offset : Int,
#|) -> Unit {
#| let anchors = unique_lcs(old~, new~)
#| if anchors.is_empty() {
#| append_myers_matches(matches, cutoff, old, new, old_offset, new_offset)
#| return
#| }
#| let mut prev_old_idx = 0
#| let mut prev_new_idx = 0
#| for i in 0.. Array[(Int, Int)] {
#| let matches = Array(capacity=old.length().min(new.length()))
#| match algorithm {
#| Patience => append_patience_matches(matches, cutoff, old, new, 0, 0)
#| Myers => append_myers_matches(matches, cutoff, old, new, 0, 0)
#| }
#| matches
#|}
#|struct Diff[T] {
#| old : ArrayView[T]
#| new : ArrayView[T]
#| edits : Array[Edit]
#|}
#|pub fn[T] Diff::edits(self : Diff[T]) -> ArrayView[Edit] {
#| self.edits
#|}
#|pub fn[T] Diff::old_view(self : Diff[T]) -> ArrayView[T] {
#| self.old
#|}
#|pub fn[T] Diff::new_view(self : Diff[T]) -> ArrayView[T] {
#| self.new
#|}
#|pub fn[T : Hash + Eq] Diff::Diff(
#| old~ : ArrayView[T],
#| new~ : ArrayView[T],
#| cutoff? : Int,
#| algorithm? : DiffAlgorithm = Myers,
#|) -> Diff[T] {
#| let result : Array[Edit] = Array(capacity=old.length() + new.length())
#| let matches = collect_matches(cutoff, old, new, algorithm)
#| let mut prev_old_idx = 0
#| let mut prev_new_idx = 0
#| let mut equal_old_idx = 0
#| let mut equal_new_idx = 0
#| let mut consecutive_equal_length = 0
#| for pair in matches {
#| let (old_idx, new_idx) = pair
#| if prev_old_idx != old_idx {
#| if consecutive_equal_length != 0 {
#| result.push(
#| Equal(
#| old_index=equal_old_idx,
#| new_index=equal_new_idx,
#| len=consecutive_equal_length,
#| ),
#| )
#| }
#| consecutive_equal_length = 0
#| result.push(
#| Delete(
#| old_index=prev_old_idx,
#| old_len=old_idx - prev_old_idx,
#| new_index=prev_new_idx,
#| ),
#| )
#| prev_old_idx = old_idx
#| }
#| if prev_new_idx != new_idx {
#| if consecutive_equal_length != 0 {
#| result.push(
#| Equal(
#| old_index=equal_old_idx,
#| new_index=equal_new_idx,
#| len=consecutive_equal_length,
#| ),
#| )
#| }
#| consecutive_equal_length = 0
#| result.push(
#| Insert(
#| old_index=prev_old_idx,
#| new_index=prev_new_idx,
#| new_len=new_idx - prev_new_idx,
#| ),
#| )
#| }
#| prev_old_idx = old_idx + 1
#| prev_new_idx = new_idx + 1
#| if consecutive_equal_length == 0 {
#| equal_old_idx = old_idx
#| equal_new_idx = new_idx
#| consecutive_equal_length = 1
#| } else {
#| consecutive_equal_length += 1
#| }
#| } nobreak {
#| if consecutive_equal_length != 0 {
#| result.push(
#| Equal(
#| old_index=equal_old_idx,
#| new_index=equal_new_idx,
#| len=consecutive_equal_length,
#| ),
#| )
#| }
#| if prev_old_idx != old.length() {
#| result.push(
#| Delete(
#| old_index=prev_old_idx,
#| old_len=old.length() - prev_old_idx,
#| new_index=prev_new_idx,
#| ),
#| )
#| prev_old_idx = old.length()
#| }
#| if prev_new_idx != new.length() {
#| result.push(
#| Insert(
#| old_index=prev_old_idx,
#| new_index=prev_new_idx,
#| new_len=new.length() - prev_new_idx,
#| ),
#| )
#| }
#| return { old, new, edits: result, }
#| }
#|}
#|pub fn[T] Diff::group(self : Diff[T], context? : Int = 3) -> Array[Hunk[T]] {
#| group_edits(self.edits, context~, old=self.old, new=self.new)
#|}
),
"edit.mbt": (
#|pub enum Edit {
#| Delete(old_index~ : Int, old_len~ : Int, new_index~ : Int)
#| Insert(old_index~ : Int, new_index~ : Int, new_len~ : Int)
#| Equal(old_index~ : Int, new_index~ : Int, len~ : Int)
#|} derive(Eq, @debug.Debug)
#|fn Edit::old_range(self : Edit) -> (Int, Int) {
#| match self {
#| Insert(old_index~, ..) => (old_index, old_index)
#| Delete(old_index~, old_len~, ..) => (old_index, old_index + old_len)
#| Equal(old_index~, len~, ..) => (old_index, old_index + len)
#| }
#|}
#|fn Edit::new_range(self : Edit) -> (Int, Int) {
#| match self {
#| Insert(new_index~, new_len~, ..) => (new_index, new_index + new_len)
#| Delete(new_index~, ..) => (new_index, new_index)
#| Equal(new_index~, len~, ..) => (new_index, new_index + len)
#| }
#|}
#|fn[T] Edit::view_from(
#| self : Edit,
#| old~ : ArrayView[T],
#| new~ : ArrayView[T],
#|) -> ArrayView[T] {
#| match self {
#| Insert(new_index~, new_len~, ..) =>
#| new.exact_view(start=new_index, end=new_index + new_len)
#| Delete(old_index~, old_len~, ..) =>
#| old.exact_view(start=old_index, end=old_index + old_len)
#| Equal(old_index~, len~, ..) =>
#| old.exact_view(start=old_index, end=old_index + len)
#| }
#|}
#|fn[T] group_edits(
#| edits : Array[Edit],
#| context? : Int = 3,
#| old~ : ArrayView[T],
#| new~ : ArrayView[T],
#|) -> Array[Hunk[T]] {
#| guard context >= 0 else { abort("context must be non-negative") }
#| if edits.is_empty() {
#| return []
#| }
#| let n = edits.length()
#| let mut pending : Array[Edit] = Array()
#| let result : Array[Hunk[T]] = Array()
#| for i, edit in edits {
#| match edit {
#| Equal(old_index~, new_index~, len~) => {
#| let (old_index, new_index, len) = if i == 0 {
#| let offset = len.saturating_sub(context)
#| (old_index + offset, new_index + offset, len - offset)
#| } else {
#| (old_index, new_index, len)
#| }
#| let len = if i == n - 1 {
#| len - len.saturating_sub(context)
#| } else {
#| len
#| }
#| if len > context * 2 {
#| if context > 0 {
#| pending.push(Equal(old_index~, new_index~, len=context))
#| }
#| result.push({ edits: pending, old, new, })
#| let offset = len.saturating_sub(context)
#| pending = if context > 0 {
#| [
#| Equal(
#| old_index=old_index + offset,
#| new_index=new_index + offset,
#| len=len - offset,
#| ),
#| ]
#| } else {
#| []
#| }
#| } else if len > 0 {
#| pending.push(Equal(old_index~, new_index~, len~))
#| }
#| }
#| _ => pending.push(edit)
#| }
#| }
#| if !(pending is [] || pending is [Equal(_)]) {
#| result.push({ edits: pending, old, new, })
#| }
#| result
#|}
#|fn Int::saturating_sub(self : Int, subtrahend : Int) -> Int {
#| if self < subtrahend {
#| 0
#| } else {
#| self - subtrahend
#| }
#|}
),
"extends.mbt": (
#|pub extend DiffAlgorithm with Eq::{equal}
#|pub extend Edit with Eq::{equal}
#|pub extend LevenshteinEdit with Eq::{equal}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend DiffAlgorithm with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend DiffAlgorithm with Eq::{not_equal}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Edit with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Edit with Eq::{not_equal}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend LevenshteinEdit with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend LevenshteinEdit with Eq::{not_equal}
),
"hunk.mbt": (
#|priv struct Range(Int, Int) // zero-based start and exclusive end
#|impl Show for Range with fn output(self, logger) {
#| let mut beginning = self.0 + 1 // from array index to line number
#| let len = self.1 - self.0
#| if len == 1 {
#| logger.write_object(beginning)
#| } else {
#| if len == 0 {
#| beginning -= 1
#| }
#| logger <+ "\{beginning},\{len}"
#| }
#|}
#|priv struct HunkHeader(Range, Range)
#|fn HunkHeader::new(edits : ArrayView[Edit]) -> Self {
#| let (first_old_start, first_old_end) = edits[0].old_range()
#| let (first_new_start, first_new_end) = edits[0].new_range()
#| let mut old_end = first_old_end
#| let mut new_end = first_new_end
#| let mut found_old_end = false
#| let mut found_new_end = false
#| let mut i = edits.length()
#| while i > 0 {
#| i -= 1
#| let edit = edits[i]
#| let (edit_old_start, edit_old_end) = edit.old_range()
#| let (edit_new_start, edit_new_end) = edit.new_range()
#| if !found_old_end && edit_old_start != edit_old_end {
#| old_end = edit_old_end
#| found_old_end = true
#| }
#| if !found_new_end && edit_new_start != edit_new_end {
#| new_end = edit_new_end
#| found_new_end = true
#| }
#| if found_old_end && found_new_end {
#| break
#| }
#| }
#| HunkHeader(Range(first_old_start, old_end), Range(first_new_start, new_end))
#|}
#|impl Show for HunkHeader with fn output(self, logger) {
#| logger <+ "@@ -\{self.0} +\{self.1} @@"
#|}
#|struct Hunk[T] {
#| edits : ArrayView[Edit]
#| old : ArrayView[T]
#| new : ArrayView[T]
#|}
#|pub fn[T] Hunk::header(self : Hunk[T]) -> String {
#| Show::to_string(HunkHeader::new(self.edits))
#|}
#|pub fn[T] Hunk::edits(self : Hunk[T]) -> ArrayView[Edit] {
#| self.edits
#|}
#|pub fn[T] Hunk::old_view(self : Hunk[T]) -> ArrayView[T] {
#| self.old
#|}
#|pub fn[T] Hunk::new_view(self : Hunk[T]) -> ArrayView[T] {
#| self.new
#|}
#|pub fn[T] Hunk::render(self : Hunk[T], show~ : (T) -> String) -> String {
#| let buf = StringBuilder()
#| buf <+ "\{self.header()}\n"
#| for edit in self.edits {
#| let (prefix, slice) = match edit {
#| Insert(..) => ("+", edit.view_from(old=self.old, new=self.new))
#| Delete(..) => ("-", edit.view_from(old=self.old, new=self.new))
#| Equal(..) => (" ", edit.view_from(old=self.old, new=self.new))
#| }
#| for s in slice {
#| buf <+ "\{prefix}\{show(s)}\n"
#| }
#| }
#| buf.to_string()
#|}
),
"levenshtein.mbt": (
#|pub using @edit_distance {
#| edit_distance,
#| edit_distance_within,
#| edit_distance_str,
#| edit_distance_str_within,
#|}
#|pub enum LevenshteinEdit {
#| Delete(old_index~ : Int, old_len~ : Int, new_index~ : Int)
#| Insert(old_index~ : Int, new_index~ : Int, new_len~ : Int)
#| Equal(old_index~ : Int, new_index~ : Int, len~ : Int)
#| Replace(old_index~ : Int, new_index~ : Int, len~ : Int)
#|} derive(Eq, @debug.Debug)
#|fn[T : Eq] common_prefix_len(old : ArrayView[T], new : ArrayView[T]) -> Int {
#| let max = if old.length() < new.length() {
#| old.length()
#| } else {
#| new.length()
#| }
#| let mut i = 0
#| while i < max && old[i] == new[i] {
#| i += 1
#| }
#| i
#|}
#|pub fn[T : Eq] levenshtein_edits(
#| old~ : ArrayView[T],
#| new~ : ArrayView[T],
#|) -> Array[LevenshteinEdit] {
#| let prefix = common_prefix_len(old, new)
#| let a = old.exact_view(start=prefix)
#| let b = new.exact_view(start=prefix)
#| let m = a.length()
#| let n = b.length()
#| guard (m.to_int64() + 1L) * (n.to_int64() + 1L) <= @int.MAX_VALUE.to_int64() else {
#| abort("levenshtein_edits: input too large")
#| }
#| let width = n + 1
#| let bp : FixedArray[Byte] = FixedArray::make((m + 1) * width, 0)
#| let mut next_row = FixedArray::makei(width, j => n - j)
#| for j in 0.. 0 {
#| edits.push(Equal(old_index=0, new_index=0, len=prefix))
#| }
#| let mut i = 0
#| let mut j = 0
#| while i < m || j < n {
#| match bp[i * width + j] {
#| 0 => {
#| let eq = a[i] == b[j]
#| let start_i = i
#| let start_j = j
#| let mut len = 0
#| while i < m && j < n && bp[i * width + j] == 0 && (a[i] == b[j]) == eq {
#| i += 1
#| j += 1
#| len += 1
#| }
#| if eq {
#| edits.push(
#| Equal(old_index=prefix + start_i, new_index=prefix + start_j, len~),
#| )
#| } else {
#| edits.push(
#| Replace(
#| old_index=prefix + start_i,
#| new_index=prefix + start_j,
#| len~,
#| ),
#| )
#| }
#| }
#| 1 => {
#| let start_i = i
#| let mut len = 0
#| while i < m && bp[i * width + j] == 1 {
#| i += 1
#| len += 1
#| }
#| edits.push(
#| Delete(old_index=prefix + start_i, old_len=len, new_index=prefix + j),
#| )
#| }
#| _ => {
#| let start_j = j
#| let mut len = 0
#| while j < n && bp[i * width + j] == 2 {
#| j += 1
#| len += 1
#| }
#| edits.push(
#| Insert(old_index=prefix + i, new_index=prefix + start_j, new_len=len),
#| )
#| }
#| }
#| }
#| edits
#|}
),
"pile.mbt": (
#|priv struct Pile(Array[BackPointer])
#|fn Pile::new(top : BackPointer) -> Pile {
#| Pile([top])
#|}
#|fn Pile::push(self : Pile, t : BackPointer) -> Unit {
#| self.0.push(t)
#|}
#|fn Pile::top(self : Pile) -> BackPointer {
#| self.0[self.0.length() - 1]
#|}
),
"piles.mbt": (
#|priv struct Piles(Array[Pile])
#|fn Piles::is_empty(self : Piles) -> Bool {
#| self.0.is_empty()
#|}
#|fn Piles::put_back(self : Piles, singleton : BackPointer) -> Unit {
#| self.0.push(Pile::new(singleton))
#|}
#|fn Piles::last(self : Piles) -> Pile? {
#| self.0.last()
#|}
#|#alias("_[_]")
#|fn Piles::at(self : Piles, i : Int) -> Pile {
#| self.0[i]
#|}
#|fn Piles::put_by_binary_search(
#| self : Piles,
#| new_idx~ : Int,
#| place~ : Int,
#|) -> Unit {
#| let mut lo = -1
#| let mut hi = self.0.length()
#| while lo + 1 < hi {
#| let mid = (lo + hi) / 2
#| if self[mid].top().value.0 < new_idx {
#| lo = mid
#| } else {
#| hi = mid
#| }
#| }
#| if lo >= 0 {
#| let prev = Some(self[lo].top())
#| if lo + 1 < self.0.length() {
#| self[lo + 1].push({ value: (new_idx, place), prev, })
#| } else {
#| self.put_back({ value: (new_idx, place), prev, })
#| }
#| } else {
#| self[0].push({ value: (new_idx, place), prev: None, })
#| }
#|}
),
"unique.mbt": (
#|priv struct CountRecord {
#| old_idx : Int
#| mut old_count : Int
#| mut new_idx : Int
#| mut new_count : Int
#|}
#|fn[T : Eq + Hash] find_unique(
#| old~ : ArrayView[T],
#| new~ : ArrayView[T],
#|) -> Array[(Int, Int)] {
#| let match_lines : @hashmap.HashMap[T, CountRecord] = HashMap(
#| [],
#| capacity=old.length().max(new.length()),
#| )
#| for i in 0.. p.1.new_count == 1 && p.1.old_count == 1)
#| .map(p => p.1)
#| let unique_match_lines = []
#| for record in match_lines {
#| unique_match_lines.push((record.old_idx, record.new_idx))
#| }
#| unique_match_lines.sort_by_key(pair => pair.0)
#| return unique_match_lines
#|}
),
"unique_lcs.mbt": (
#|fn[T : Eq + Hash] unique_lcs(
#| old~ : ArrayView[T],
#| new~ : ArrayView[T],
#|) -> ArrayView[(Int, Int)] {
#| let matches = find_unique(old~, new~)
#| let piles = Piles(Array(capacity=matches.length()))
#| for place in 0.. Double {
#| d.round()
#|}
#|pub fn ceil(d : Double) -> Double {
#| d.ceil()
#|}
#|pub fn floor(d : Double) -> Double {
#| d.floor()
#|}
#|pub fn trunc(d : Double) -> Double {
#| d.trunc()
#|}
),
"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
#|}
#|#deprecated("Use `@math.pow` instead")
#|#warnings("-deprecated")
#|pub fn pow(m : Double, n : Double) -> Double {
#| m.pow(n)
#|}
#|#deprecated("Use `Double::is_close` instead")
#|pub fn is_close(
#| d : Double,
#| other : Double,
#| relative_tolerance? : Double = 1.0e-09,
#| absolute_tolerance? : Double = 0.0,
#|) -> Bool {
#| d.is_close(other, relative_tolerance~, absolute_tolerance~)
#|}
#|#deprecated("Use `Double::from_int` instead")
#|pub fn from_int(i : Int) -> Double {
#| Double::from_int(i)
#|}
#|#deprecated("Use `x.abs()` instead")
#|pub fn abs(x : Double) -> Double {
#| x.abs()
#|}
),
"limits.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()
),
},
)
///|
let moonbitlang_core_encoding_ascii_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/encoding/ascii",
deps={},
files={
"decode.mbt": (
#|pub suberror Malformed {
#| Malformed(BytesView)
#|} derive(@debug.Debug)
#|fn unsafe_fixedarray_uint16_to_string(buffer : FixedArray[UInt16]) -> String = "%string.unsafe_from_uint16_fixedarray"
#|#cfg(target="js")
#|#warnings("-unused_value")
#|fn suppress_unused_v128_import_on_js() -> Unit {
#| ignore(@v128.i8x16_splat(0))
#|}
#|fn finish_string(buffer : FixedArray[UInt16], len : Int) -> String {
#| if len == buffer.length() {
#| unsafe_fixedarray_uint16_to_string(buffer)
#| } else {
#| let data = FixedArray::make(len, (Default::default() : UInt16))
#| data.unsafe_blit(0, buffer, 0, len)
#| unsafe_fixedarray_uint16_to_string(data)
#| }
#|}
#|#cfg(not(target="js"))
#|#inline
#|fn decode_scalar(bytes : BytesView) -> String raise Malformed {
#| let t : FixedArray[UInt16] = FixedArray::make(bytes.length(), 0)
#| let tlen = for tlen = 0, bs = bytes {
#| match (tlen, bs) {
#| (tlen, []) => break tlen
#| (tlen, [0..=0x7F as b, .. rest]) => {
#| t.unsafe_set(tlen, b.to_uint16())
#| continue tlen + 1, rest
#| }
#| (_, _ as bytes) => raise Malformed(bytes)
#| }
#| }
#| finish_string(t, tlen)
#|}
#|#cfg(not(target="js"))
#|fn decode_v128(bytes : BytesView) -> String raise Malformed {
#| let length = bytes.length()
#| let result = FixedArray::make(length * 2, b'\x00')
#| for rest = bytes, result_offset = 0 {
#| match rest {
#| [v128le(block), .. tail] => {
#| let non_ascii = @v128.i8x16_bitmask(block)
#| if non_ascii != 0 {
#| raise Malformed(bytes[result_offset / 2 + non_ascii.ctz():])
#| }
#| @v128.v128_store(
#| result,
#| result_offset,
#| @v128.i16x8_extend_low_i8x16_u(block),
#| )
#| @v128.v128_store(
#| result,
#| result_offset + 16,
#| @v128.i16x8_extend_high_i8x16_u(block),
#| )
#| continue tail, result_offset + 32
#| }
#| [0..=0x7F as byte, .. tail] => {
#| result.unsafe_set(result_offset, byte)
#| result.unsafe_set(result_offset + 1, b'\x00')
#| continue tail, result_offset + 2
#| }
#| [] => break
#| _ => raise Malformed(bytes[result_offset / 2:])
#| }
#| }
#| result.unsafe_reinterpret_as_bytes().to_unchecked_string()
#|}
#|#cfg(not(target="js"))
#|#inline
#|pub fn decode(bytes : BytesView) -> String raise Malformed {
#| if bytes.length() >= 64 {
#| decode_v128(bytes)
#| } else {
#| decode_scalar(bytes)
#| }
#|}
#|#cfg(target="js")
#|pub fn decode(bytes : BytesView) -> String raise Malformed {
#| let t : FixedArray[UInt16] = FixedArray::make(bytes.length(), 0)
#| let tlen = for tlen = 0, bs = bytes {
#| match (tlen, bs) {
#| (tlen, []) => break tlen
#| (tlen, [0..=0x7F as b, .. rest]) => {
#| t.unsafe_set(tlen, b.to_uint16())
#| continue tlen + 1, rest
#| }
#| (_, _ as bytes) => raise Malformed(bytes)
#| }
#| }
#| finish_string(t, tlen)
#|}
#|pub fn decode_lossy(bytes : BytesView) -> String {
#| let t : FixedArray[UInt16] = FixedArray::make(bytes.length(), 0)
#| let tlen = for tlen = 0, bs = bytes {
#| match (tlen, bs) {
#| (tlen, []) => break tlen
#| (tlen, [0..=0x7F as b, .. rest]) => {
#| t.unsafe_set(tlen, b.to_uint16())
#| continue tlen + 1, rest
#| }
#| (tlen, [_, .. rest]) => {
#| t.unsafe_set(tlen, 0xFFFD)
#| continue tlen + 1, rest
#| }
#| }
#| }
#| finish_string(t, tlen)
#|}
),
"encode.mbt": (
#|pub fn encode(str : StringView) -> Bytes {
#| let length = str.length()
#| let arr = FixedArray::make(length, b'\x00')
#| for i, code_unit in str.code_units() {
#| if code_unit > 0x7F {
#| panic()
#| }
#| arr[i] = code_unit.to_byte()
#| }
#| arr.unsafe_reinterpret_as_bytes()
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Malformed with @debug.Debug::{to_repr}
),
},
)
///|
let moonbitlang_core_encoding_base64_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/encoding/base64",
deps={},
files={
"decode.mbt": (
#|pub suberror Malformed {
#| Malformed(StringView)
#|} derive(@debug.Debug)
#|const WRITESPACE = -3
#|const PADDING = -2
#|const INVALID_CHAR = -1
#|fn base64_value(code_unit : Int) -> Int {
#| match code_unit {
#| 'A'..='Z' => code_unit - 'A'
#| 'a'..='z' => code_unit - 'a' + 26
#| '0'..='9' => code_unit - '0' + 52
#| '+' => 62
#| '/' => 63
#| ' ' | '\n' | '\r' | '\t' => WRITESPACE
#| '=' => PADDING
#| _ => INVALID_CHAR
#| }
#|}
#|#cfg(not(any(target="native", target="wasm")))
#|pub fn decode(
#| text : StringView,
#| ignore_whitespace? : Bool = false,
#|) -> Bytes raise Malformed {
#| decode_scalar(text, ignore_whitespace)
#|}
#|#cfg(any(target="native", target="wasm"))
#|pub fn decode(
#| text : StringView,
#| ignore_whitespace? : Bool = false,
#|) -> Bytes raise Malformed {
#| if !ignore_whitespace && decode_v128(text) is Some(bytes) {
#| return bytes
#| }
#| decode_scalar(text, ignore_whitespace)
#|}
#|fn decode_scalar(
#| text : StringView,
#| ignore_whitespace : Bool,
#|) -> Bytes raise Malformed {
#| let buffer = @buffer.Buffer(size_hint=text.length() / 4 * 3)
#| let quartet = FixedArray::make(4, 0)
#| let mut count = 0
#| for i, code_unit in text.code_units() {
#| match base64_value(code_unit.to_int()) {
#| WRITESPACE =>
#| if ignore_whitespace {
#| continue
#| } else {
#| raise Malformed(text)
#| }
#| PADDING =>
#| if count < 2 {
#| raise Malformed(text)
#| } else {
#| quartet[count] = PADDING
#| count += 1
#| if count == 4 {
#| count = 0
#| if quartet[2] == PADDING {
#| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte()
#| buffer.write_byte(b0)
#| guard (quartet[1] & 0x0F) == 0 else { raise Malformed(text) }
#| } else {
#| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte()
#| let b1 = (((quartet[1] & 0x0F) << 4) | (quartet[2] >> 2)).to_byte()
#| guard (quartet[2] & 0x03) == 0 else { raise Malformed(text) }
#| buffer.write_byte(b0)
#| buffer.write_byte(b1)
#| }
#| if ignore_whitespace {
#| for code_unit in text.code_units()[i + 1:] {
#| guard code_unit is (' ' | '\n' | '\r' | '\t') else {
#| raise Malformed(text)
#| }
#| }
#| } else {
#| guard i + 1 == text.length() else { raise Malformed(text) }
#| }
#| break
#| }
#| }
#| INVALID_CHAR => raise Malformed(text)
#| value => {
#| quartet[count] = value
#| count += 1
#| if count == 4 {
#| count = 0
#| guard quartet[2] != PADDING else { raise Malformed(text) }
#| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte()
#| let b1 = (((quartet[1] & 0x0F) << 4) | (quartet[2] >> 2)).to_byte()
#| let b2 = (((quartet[2] & 0x03) << 6) | quartet[3]).to_byte()
#| buffer.write_byte(b0)
#| buffer.write_byte(b1)
#| buffer.write_byte(b2)
#| }
#| }
#| }
#| }
#| match count {
#| 1 => raise Malformed(text)
#| 2 => {
#| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte()
#| guard (quartet[1] & 0x0F) == 0 else { raise Malformed(text) }
#| buffer.write_byte(b0)
#| }
#| 3 => {
#| guard quartet[2] != PADDING else { raise Malformed(text) }
#| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte()
#| let b1 = (((quartet[1] & 0x0F) << 4) | (quartet[2] >> 2)).to_byte()
#| guard (quartet[2] & 0x03) == 0 else { raise Malformed(text) }
#| buffer.write_byte(b0)
#| buffer.write_byte(b1)
#| }
#| _ => ()
#| }
#| buffer.to_bytes()
#|}
#|pub fn decode_lossy(
#| text : StringView,
#| ignore_whitespace? : Bool = false,
#|) -> Bytes {
#| let buffer = @buffer.Buffer(size_hint=text.length() / 4 * 3)
#| let quartet = FixedArray::make(4, 0)
#| let mut count = 0
#| for code_unit in text.code_units() {
#| match base64_value(code_unit.to_int()) {
#| WRITESPACE => if !ignore_whitespace { break }
#| PADDING => break
#| INVALID_CHAR => ()
#| value => {
#| quartet[count] = value
#| count += 1
#| if count == 4 {
#| count = 0
#| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte()
#| let b1 = (((quartet[1] & 0x0F) << 4) | (quartet[2] >> 2)).to_byte()
#| let b2 = (((quartet[2] & 0x03) << 6) | quartet[3]).to_byte()
#| buffer.write_byte(b0)
#| buffer.write_byte(b1)
#| buffer.write_byte(b2)
#| }
#| }
#| }
#| }
#| if count == 2 {
#| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte()
#| buffer.write_byte(b0)
#| } else if count == 3 {
#| let b0 = ((quartet[0] << 2) | (quartet[1] >> 4)).to_byte()
#| let b1 = (((quartet[1] & 0x0F) << 4) | (quartet[2] >> 2)).to_byte()
#| buffer.write_byte(b0)
#| buffer.write_byte(b1)
#| }
#| buffer.to_bytes()
#|}
),
"decode_v128.mbt": (
#|#cfg(any(target="native", target="wasm"))
#|fn decode_offsets_v128() -> V128 {
#| @v128.i8x16_const(0, 16, 19, 4, 191, 191, 185, 185, 0, 0, 0, 0, 0, 0, 0, 0)
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn decode_valid_v128(ascii : V128) -> Bool {
#| let upper = @v128.v128_and_(
#| @v128.i8x16_ge_u(ascii, @v128.i8x16_splat(b'A')),
#| @v128.i8x16_le_u(ascii, @v128.i8x16_splat(b'Z')),
#| )
#| let lower = @v128.v128_and_(
#| @v128.i8x16_ge_u(ascii, @v128.i8x16_splat(b'a')),
#| @v128.i8x16_le_u(ascii, @v128.i8x16_splat(b'z')),
#| )
#| let digit = @v128.v128_and_(
#| @v128.i8x16_ge_u(ascii, @v128.i8x16_splat(b'0')),
#| @v128.i8x16_le_u(ascii, @v128.i8x16_splat(b'9')),
#| )
#| let plus = @v128.i8x16_eq(ascii, @v128.i8x16_splat(b'+'))
#| let slash = @v128.i8x16_eq(ascii, @v128.i8x16_splat(b'/'))
#| @v128.i8x16_all_true(
#| @v128.v128_or_(
#| @v128.v128_or_(upper, lower),
#| @v128.v128_or_(digit, @v128.v128_or_(plus, slash)),
#| ),
#| )
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn decode_block_v128(ascii : V128) -> V128 {
#| let hash = @v128.i8x16_add(
#| @v128.i8x16_shr_u(ascii, 4),
#| @v128.i8x16_eq(ascii, @v128.i8x16_splat(b'/')),
#| )
#| let sextets = @v128.i8x16_add(
#| ascii,
#| @v128.i8x16_swizzle(decode_offsets_v128(), hash),
#| )
#| let groups = @v128.v128_or_(
#| @v128.v128_or_(
#| @v128.i32x4_shl(
#| @v128.v128_and_(sextets, @v128.i32x4_splat(0x0000003F)),
#| 18,
#| ),
#| @v128.i32x4_shl(
#| @v128.v128_and_(sextets, @v128.i32x4_splat(0x00003F00)),
#| 4,
#| ),
#| ),
#| @v128.v128_or_(
#| @v128.i32x4_shr_u(
#| @v128.v128_and_(sextets, @v128.i32x4_splat(0x003F0000)),
#| 10,
#| ),
#| @v128.i32x4_shr_u(
#| @v128.v128_and_(sextets, @v128.i32x4_splat(0x3F000000)),
#| 24,
#| ),
#| ),
#| )
#| @v128.i8x16_shuffle(
#| groups, groups, 2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, 0, 0, 0, 0,
#| )
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn decode_v128(text : StringView) -> Bytes? {
#| let length = text.length()
#| guard length >= 32 && length % 4 == 0 else { return None }
#| let padding = if text.unsafe_get(length - 1) != b'='.to_uint16() {
#| 0
#| } else if text.unsafe_get(length - 2) != b'='.to_uint16() {
#| 1
#| } else {
#| 2
#| }
#| let out = FixedArray::make(length / 4 * 3 - padding, b'\x00')
#| let src = text.data()
#| let body = length - 4
#| let base = text.start_offset()
#| let mut index = 0
#| let mut written = 0
#| while body - index >= 16 && out.length() - written >= 16 {
#| let offset = base + index
#| let ascii = @v128.i8x16_narrow_i16x8_u(
#| @v128.v128_load_i16x8(src, offset),
#| @v128.v128_load_i16x8(src, offset + 8),
#| )
#| guard decode_valid_v128(ascii) else { return None }
#| @v128.v128_store(out, written, decode_block_v128(ascii))
#| index += 16
#| written += 12
#| }
#| while index < body {
#| let mut group = 0
#| for lane in 0..<4 {
#| let value = base64_value(text.unsafe_get(index + lane).to_int())
#| guard value >= 0 else { return None }
#| group = (group << 6) | value
#| }
#| out[written] = (group >> 16).to_byte()
#| out[written + 1] = (group >> 8).to_byte()
#| out[written + 2] = group.to_byte()
#| index += 4
#| written += 3
#| }
#| let tail_bytes = decode_scalar(text[body:], false) catch { _ => return None }
#| guard tail_bytes.length() == out.length() - written else { return None }
#| for i, byte in tail_bytes {
#| out[written + i] = byte
#| }
#| Some(out.unsafe_reinterpret_as_bytes())
#|}
),
"encode.mbt": (
#|const BASE64_STD : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
#|#cfg(not(any(target="native", target="wasm")))
#|pub fn encode(bytes : BytesView, padding? : Bool = true) -> String {
#| encode_scalar(bytes, padding~)
#|}
#|#cfg(any(target="native", target="wasm"))
#|pub fn encode(bytes : BytesView, padding? : Bool = true) -> String {
#| encode_v128(bytes, padding)
#|}
#|fn encode_scalar(bytes : BytesView, padding? : Bool = true) -> String {
#| let full_groups = bytes.length() / 3
#| let remainder = bytes.length() % 3
#| let mut size_hint = full_groups * 4
#| if remainder != 0 {
#| size_hint += if padding is true { 4 } else { remainder + 1 }
#| }
#| let builder = StringBuilder(size_hint~)
#| for remaining = bytes {
#| match remaining {
#| [b0, b1, b2, .. rest] => {
#| let n = (b0.to_int() << 16) | (b1.to_int() << 8) | b2.to_int()
#| builder.write_char(BASE64_STD[(n >> 18) & 0x3F].to_char())
#| builder.write_char(BASE64_STD[(n >> 12) & 0x3F].to_char())
#| builder.write_char(BASE64_STD[(n >> 6) & 0x3F].to_char())
#| builder.write_char(BASE64_STD[n & 0x3F].to_char())
#| continue rest
#| }
#| [b0, b1] => {
#| let n = (b0.to_int() << 16) | (b1.to_int() << 8)
#| builder.write_char(BASE64_STD[(n >> 18) & 0x3F].to_char())
#| builder.write_char(BASE64_STD[(n >> 12) & 0x3F].to_char())
#| builder.write_char(BASE64_STD[(n >> 6) & 0x3F].to_char())
#| if padding is true {
#| builder.write_char('=')
#| }
#| break
#| }
#| [b0] => {
#| let n = b0.to_int() << 16
#| builder.write_char(BASE64_STD[(n >> 18) & 0x3F].to_char())
#| builder.write_char(BASE64_STD[(n >> 12) & 0x3F].to_char())
#| if padding is true {
#| builder.write_string("==")
#| }
#| break
#| }
#| [] => break
#| }
#| }
#| builder.to_string()
#|}
),
"encode_v128.mbt": (
#|#cfg(any(target="native", target="wasm"))
#|fn encode_offsets_v128() -> V128 {
#| @v128.i8x16_const(
#| 71, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 237, 240, 65, 0, 0,
#| )
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn encode_block_v128(data : V128) -> V128 {
#| let zero = @v128.i8x16_splat(0)
#| let groups = @v128.i8x16_shuffle(
#| data, zero, 2, 1, 0, 16, 5, 4, 3, 16, 8, 7, 6, 16, 11, 10, 9, 16,
#| )
#| let sextets = @v128.v128_or_(
#| @v128.v128_or_(
#| @v128.v128_and_(
#| @v128.i32x4_shr_u(groups, 18),
#| @v128.i32x4_splat(0x0000003F),
#| ),
#| @v128.v128_and_(
#| @v128.i32x4_shr_u(groups, 4),
#| @v128.i32x4_splat(0x00003F00),
#| ),
#| ),
#| @v128.v128_or_(
#| @v128.v128_and_(
#| @v128.i32x4_shl(groups, 10),
#| @v128.i32x4_splat(0x003F0000),
#| ),
#| @v128.v128_and_(
#| @v128.i32x4_shl(groups, 24),
#| @v128.i32x4_splat(0x3F000000),
#| ),
#| ),
#| )
#| let class = @v128.v128_or_(
#| @v128.i8x16_sub_sat_u(sextets, @v128.i8x16_splat(51)),
#| @v128.v128_and_(
#| @v128.i8x16_lt_u(sextets, @v128.i8x16_splat(26)),
#| @v128.i8x16_splat(13),
#| ),
#| )
#| @v128.i8x16_add(sextets, @v128.i8x16_swizzle(encode_offsets_v128(), class))
#|}
#|#cfg(any(target="native", target="wasm"))
#|#inline
#|fn write_code_unit(out : FixedArray[Byte], offset : Int, code : Byte) -> Unit {
#| out[offset] = code
#| out[offset + 1] = 0
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn encode_v128(bytes : BytesView, padding : Bool) -> String {
#| let length = bytes.length()
#| guard length <= 0x2000_0000 else { return encode_scalar(bytes, padding~) }
#| let full_groups = length / 3
#| let remainder = length % 3
#| let mut char_count = full_groups * 4
#| if remainder != 0 {
#| char_count += if padding { 4 } else { remainder + 1 }
#| }
#| let out = FixedArray::make(char_count * 2, b'\x00')
#| for rest = bytes, written = 0 {
#| match rest {
#| [v128le(block), ..] as current => {
#| let chars = encode_block_v128(block)
#| @v128.v128_store(out, written, @v128.i16x8_extend_low_i8x16_u(chars))
#| @v128.v128_store(
#| out,
#| written + 16,
#| @v128.i16x8_extend_high_i8x16_u(chars),
#| )
#| continue current[12:], written + 32
#| }
#| [b0, b1, b2, .. tail] => {
#| let n = (b0.to_int() << 16) | (b1.to_int() << 8) | b2.to_int()
#| write_code_unit(out, written, BASE64_STD[(n >> 18) & 0x3F])
#| write_code_unit(out, written + 2, BASE64_STD[(n >> 12) & 0x3F])
#| write_code_unit(out, written + 4, BASE64_STD[(n >> 6) & 0x3F])
#| write_code_unit(out, written + 6, BASE64_STD[n & 0x3F])
#| continue tail, written + 8
#| }
#| [b0, b1] => {
#| let n = (b0.to_int() << 16) | (b1.to_int() << 8)
#| write_code_unit(out, written, BASE64_STD[(n >> 18) & 0x3F])
#| write_code_unit(out, written + 2, BASE64_STD[(n >> 12) & 0x3F])
#| write_code_unit(out, written + 4, BASE64_STD[(n >> 6) & 0x3F])
#| if padding {
#| write_code_unit(out, written + 6, b'=')
#| }
#| break
#| }
#| [b0] => {
#| let n = b0.to_int() << 16
#| write_code_unit(out, written, BASE64_STD[(n >> 18) & 0x3F])
#| write_code_unit(out, written + 2, BASE64_STD[(n >> 12) & 0x3F])
#| if padding {
#| write_code_unit(out, written + 4, b'=')
#| write_code_unit(out, written + 6, b'=')
#| }
#| break
#| }
#| [] => break
#| }
#| }
#| out.unsafe_reinterpret_as_bytes().to_unchecked_string()
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Malformed with @debug.Debug::{to_repr}
),
},
)
///|
let moonbitlang_core_encoding_hex_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/encoding/hex",
deps={},
files={
"decode.mbt": (
#|pub suberror Malformed {
#| Malformed(StringView)
#|} derive(@debug.Debug)
#|fn hex_value(code_unit : Int) -> Int {
#| match code_unit {
#| '0'..='9' => code_unit - '0'
#| 'a'..='f' => code_unit - 'a' + 10
#| 'A'..='F' => code_unit - 'A' + 10
#| _ => -1
#| }
#|}
#|#cfg(not(any(target="native", target="wasm")))
#|pub fn decode(text : StringView) -> Bytes raise Malformed {
#| decode_scalar(text)
#|}
#|#cfg(any(target="native", target="wasm"))
#|pub fn decode(text : StringView) -> Bytes raise Malformed {
#| match decode_v128(text) {
#| Some(bytes) => bytes
#| None => decode_scalar(text)
#| }
#|}
#|fn decode_scalar(text : StringView) -> Bytes raise Malformed {
#| if text.length() % 2 != 0 {
#| raise Malformed(text)
#| }
#| let buffer = @buffer.Buffer(size_hint=text.length() / 2)
#| for i in 0..<(text.length() / 2) {
#| let hi = hex_value(text.code_unit_at(i * 2).to_int())
#| let lo = hex_value(text.code_unit_at(i * 2 + 1).to_int())
#| guard hi >= 0 && lo >= 0 else { raise Malformed(text) }
#| buffer.write_byte(((hi << 4) | lo).to_byte())
#| }
#| buffer.to_bytes()
#|}
),
"decode_v128.mbt": (
#|#cfg(any(target="native", target="wasm"))
#|fn hex_valid_v128(ascii : V128) -> Bool {
#| let digit = @v128.v128_and_(
#| @v128.i8x16_ge_u(ascii, @v128.i8x16_splat(b'0')),
#| @v128.i8x16_le_u(ascii, @v128.i8x16_splat(b'9')),
#| )
#| let lower = @v128.v128_and_(
#| @v128.i8x16_ge_u(ascii, @v128.i8x16_splat(b'a')),
#| @v128.i8x16_le_u(ascii, @v128.i8x16_splat(b'f')),
#| )
#| let upper = @v128.v128_and_(
#| @v128.i8x16_ge_u(ascii, @v128.i8x16_splat(b'A')),
#| @v128.i8x16_le_u(ascii, @v128.i8x16_splat(b'F')),
#| )
#| @v128.i8x16_all_true(@v128.v128_or_(digit, @v128.v128_or_(lower, upper)))
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn hex_nibbles_v128(ascii : V128) -> V128 {
#| let lower = @v128.v128_and_(
#| @v128.i8x16_ge_u(ascii, @v128.i8x16_splat(b'a')),
#| @v128.i8x16_splat(217), // -39 mod 256
#| )
#| let upper = @v128.v128_and_(
#| @v128.v128_and_(
#| @v128.i8x16_ge_u(ascii, @v128.i8x16_splat(b'A')),
#| @v128.i8x16_le_u(ascii, @v128.i8x16_splat(b'F')),
#| ),
#| @v128.i8x16_splat(249), // -7 mod 256
#| )
#| @v128.i8x16_add(
#| @v128.i8x16_add(ascii, @v128.i8x16_splat(208)), // -48 mod 256
#| @v128.v128_or_(lower, upper),
#| )
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn decode_v128(text : StringView) -> Bytes? {
#| let length = text.length()
#| guard length >= 32 && length % 2 == 0 else { return None }
#| let out = FixedArray::make(length / 2, b'\x00')
#| let src = text.data()
#| let base = text.start_offset()
#| let mut index = 0
#| let mut written = 0
#| while length - index >= 32 {
#| let offset = base + index
#| let ascii0 = @v128.i8x16_narrow_i16x8_u(
#| @v128.v128_load_i16x8(src, offset),
#| @v128.v128_load_i16x8(src, offset + 8),
#| )
#| let ascii1 = @v128.i8x16_narrow_i16x8_u(
#| @v128.v128_load_i16x8(src, offset + 16),
#| @v128.v128_load_i16x8(src, offset + 24),
#| )
#| guard hex_valid_v128(ascii0) && hex_valid_v128(ascii1) else { return None }
#| let n0 = hex_nibbles_v128(ascii0)
#| let n1 = hex_nibbles_v128(ascii1)
#| let hi = @v128.i8x16_shuffle(
#| n0, n1, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
#| )
#| let lo = @v128.i8x16_shuffle(
#| n0, n1, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31,
#| )
#| @v128.v128_store(out, written, @v128.v128_or_(@v128.i8x16_shl(hi, 4), lo))
#| index += 32
#| written += 16
#| }
#| while index < length {
#| let hi = hex_value(text.unsafe_get(index).to_int())
#| let lo = hex_value(text.unsafe_get(index + 1).to_int())
#| guard hi >= 0 && lo >= 0 else { return None }
#| out[written] = ((hi << 4) | lo).to_byte()
#| index += 2
#| written += 1
#| }
#| Some(out.unsafe_reinterpret_as_bytes())
#|}
),
"encode.mbt": (
#|const HEX_DIGITS : Bytes = b"0123456789abcdef"
#|#cfg(not(any(target="native", target="wasm")))
#|pub fn encode(bytes : BytesView) -> String {
#| encode_scalar(bytes)
#|}
#|#cfg(any(target="native", target="wasm"))
#|pub fn encode(bytes : BytesView) -> String {
#| encode_v128(bytes)
#|}
#|fn encode_scalar(bytes : BytesView) -> String {
#| let builder = StringBuilder(size_hint=4 * bytes.length())
#| for byte in bytes {
#| let n = byte.to_int()
#| builder.write_char(HEX_DIGITS[(n >> 4) & 0x0F].to_char())
#| builder.write_char(HEX_DIGITS[n & 0x0F].to_char())
#| }
#| builder.to_string()
#|}
),
"encode_v128.mbt": (
#|#cfg(any(target="native", target="wasm"))
#|fn hex_digits_v128() -> V128 {
#| @v128.i8x16_const(
#| 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102,
#| )
#|}
#|#cfg(any(target="native", target="wasm"))
#|#inline
#|fn write_code_unit(out : FixedArray[Byte], offset : Int, code : Byte) -> Unit {
#| out[offset] = code
#| out[offset + 1] = 0
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn encode_v128(bytes : BytesView) -> String {
#| let length = bytes.length()
#| guard length <= 0x1FFF_FFFF else { return encode_scalar(bytes) } // Int::MAX / 4
#| let out = FixedArray::make(length * 4, b'\x00')
#| let table = hex_digits_v128()
#| for rest = bytes, written = 0 {
#| match rest {
#| [v128le(data), .. tail] => {
#| let hi = @v128.i8x16_shr_u(data, 4)
#| let lo = @v128.v128_and_(data, @v128.i8x16_splat(0x0F))
#| let first = @v128.i8x16_shuffle(
#| hi, lo, 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23,
#| )
#| let second = @v128.i8x16_shuffle(
#| hi, lo, 8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31,
#| )
#| let d0 = @v128.i8x16_swizzle(table, first)
#| let d1 = @v128.i8x16_swizzle(table, second)
#| @v128.v128_store(out, written, @v128.i16x8_extend_low_i8x16_u(d0))
#| @v128.v128_store(out, written + 16, @v128.i16x8_extend_high_i8x16_u(d0))
#| @v128.v128_store(out, written + 32, @v128.i16x8_extend_low_i8x16_u(d1))
#| @v128.v128_store(out, written + 48, @v128.i16x8_extend_high_i8x16_u(d1))
#| continue tail, written + 64
#| }
#| [byte, .. tail] => {
#| let n = byte.to_int()
#| write_code_unit(out, written, HEX_DIGITS[(n >> 4) & 0x0F])
#| write_code_unit(out, written + 2, HEX_DIGITS[n & 0x0F])
#| continue tail, written + 4
#| }
#| [] => break
#| }
#| }
#| out.unsafe_reinterpret_as_bytes().to_unchecked_string()
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Malformed with @debug.Debug::{to_repr}
),
},
)
///|
let moonbitlang_core_encoding_percent_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/encoding/percent",
deps={},
files={
"decode.mbt": (
#|pub suberror Malformed {
#| Malformed(StringView)
#|} derive(@debug.Debug)
#|fn hex_value(code_unit : Int) -> Int {
#| match code_unit {
#| '0'..='9' => code_unit - '0'
#| 'a'..='f' => code_unit - 'a' + 10
#| 'A'..='F' => code_unit - 'A' + 10
#| _ => -1
#| }
#|}
#|pub fn decode(text : StringView) -> String raise Malformed {
#| match decode_impl(text, lossy=false) {
#| Some(decoded) => decoded
#| None => raise Malformed(text)
#| }
#|}
#|pub fn decode_lossy(text : StringView) -> String {
#| decode_impl(text, lossy=true).unwrap()
#|}
#|fn decode_impl(text : StringView, lossy~ : Bool) -> String? {
#| let length = text.length()
#| let builder = StringBuilder(size_hint=2 * length)
#| let bytes = @buffer.Buffer()
#| let mut i = 0
#| let mut literal_start = 0
#| while i < length {
#| if text.unsafe_get(i) != '%' {
#| i += 1
#| continue
#| }
#| builder.write_view(text.view(start_offset=literal_start, end_offset=i))
#| bytes.reset()
#| let mut resume_after_percent = false
#| while i < length && text.unsafe_get(i) == '%' {
#| if i + 2 < length {
#| let hi = hex_value(text.unsafe_get(i + 1).to_int())
#| let lo = hex_value(text.unsafe_get(i + 2).to_int())
#| if hi >= 0 && lo >= 0 {
#| bytes.write_byte(((hi << 4) | lo).to_byte())
#| i += 3
#| continue
#| }
#| }
#| guard lossy else { return None }
#| resume_after_percent = true
#| break
#| }
#| if lossy {
#| builder.write_string(@utf8.decode_lossy(bytes.contents()))
#| } else {
#| let decoded = @utf8.decode(bytes.contents()) catch { _ => return None }
#| builder.write_string(decoded)
#| }
#| if resume_after_percent {
#| builder.write_char('%')
#| i += 1
#| }
#| literal_start = i
#| }
#| builder.write_view(text.view(start_offset=literal_start, end_offset=length))
#| Some(builder.to_string())
#|}
),
"encode.mbt": (
#|const HEX_UPPER : Bytes = b"0123456789ABCDEF"
#|fn is_unreserved(code_unit : Int) -> Bool {
#| match code_unit {
#| 'A'..='Z' | 'a'..='z' | '0'..='9' | '-' | '.' | '_' | '~' => true
#| _ => false
#| }
#|}
#|fn write_escape(builder : StringBuilder, byte : Int) -> Unit {
#| builder.write_char('%')
#| builder.write_char(HEX_UPPER[(byte >> 4) & 0x0F].to_char())
#| builder.write_char(HEX_UPPER[byte & 0x0F].to_char())
#|}
#|pub fn encode(text : StringView) -> String {
#| let builder = StringBuilder(size_hint=2 * text.length())
#| let length = text.length()
#| let mut i = 0
#| let mut literal_start = 0
#| while i < length {
#| let unit = text.unsafe_get(i).to_int()
#| if unit < 0x80 {
#| if is_unreserved(unit) {
#| i += 1
#| continue
#| }
#| builder.write_view(text.view(start_offset=literal_start, end_offset=i))
#| write_escape(builder, unit)
#| i += 1
#| } else {
#| builder.write_view(text.view(start_offset=literal_start, end_offset=i))
#| if unit < 0x800 {
#| write_escape(builder, 0xC0 | (unit >> 6))
#| write_escape(builder, 0x80 | (unit & 0x3F))
#| i += 1
#| } else if unit.is_leading_surrogate() &&
#| i + 1 < length &&
#| text.unsafe_get(i + 1).is_trailing_surrogate() {
#| let low = text.unsafe_get(i + 1).to_int()
#| let code_point = 0x10000 + ((unit - 0xD800) << 10) + (low - 0xDC00)
#| write_escape(builder, 0xF0 | (code_point >> 18))
#| write_escape(builder, 0x80 | ((code_point >> 12) & 0x3F))
#| write_escape(builder, 0x80 | ((code_point >> 6) & 0x3F))
#| write_escape(builder, 0x80 | (code_point & 0x3F))
#| i += 2
#| } else {
#| let scalar = if unit.is_leading_surrogate() ||
#| unit.is_trailing_surrogate() {
#| 0xFFFD
#| } else {
#| unit
#| }
#| write_escape(builder, 0xE0 | (scalar >> 12))
#| write_escape(builder, 0x80 | ((scalar >> 6) & 0x3F))
#| write_escape(builder, 0x80 | (scalar & 0x3F))
#| i += 1
#| }
#| }
#| literal_start = i
#| }
#| builder.write_view(text.view(start_offset=literal_start, end_offset=length))
#| builder.to_string()
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Malformed with @debug.Debug::{to_repr}
),
},
)
///|
let moonbitlang_core_encoding_utf16_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/encoding/utf16",
deps={},
files={
"decode.mbt": (
#|pub suberror Malformed {
#| Malformed(BytesView)
#|} derive(@debug.Debug)
#|const U_REP = '\u{FFFD}'
#|#cfg(target="js")
#|#warnings("-unused_value")
#|fn suppress_unused_v128_import_on_js() -> Unit {
#| ignore(@v128.i8x16_splat(0))
#|}
#|#cfg(not(target="js"))
#|fn utf16_swap_u16x8(value : V128) -> V128 {
#| @v128.i8x16_shuffle(
#| value, value, 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14,
#| )
#|}
#|#cfg(not(target="js"))
#|fn utf16_v128_has_surrogate(value : V128) -> Bool {
#| let lower = @v128.i16x8_splat(0xD800)
#| let upper = @v128.i16x8_splat(0xDFFF)
#| @v128.i16x8_bitmask(
#| @v128.v128_and_(
#| @v128.i16x8_ge_u(value, lower),
#| @v128.i16x8_le_u(value, upper),
#| ),
#| ) !=
#| 0
#|}
#|#cfg(not(target="js"))
#|fn utf16_needs_scalar_le_v128(bytes : BytesView) -> Bool {
#| if bytes.length() % 2 != 0 {
#| return true
#| }
#| for rest = bytes {
#| match rest {
#| [v128le(block), .. tail] => {
#| if utf16_v128_has_surrogate(block) {
#| return true
#| }
#| continue tail
#| }
#| [u16le(0xD800..=0xDFFF), ..] => return true
#| [u16le(_), .. tail] => continue tail
#| [] => break false
#| _ => break true
#| }
#| }
#|}
#|#cfg(not(target="js"))
#|fn utf16_needs_scalar_be_v128(bytes : BytesView) -> Bool {
#| if bytes.length() % 2 != 0 {
#| return true
#| }
#| for rest = bytes {
#| match rest {
#| [v128le(block), .. tail] => {
#| if utf16_v128_has_surrogate(utf16_swap_u16x8(block)) {
#| return true
#| }
#| continue tail
#| }
#| [u16be(0xD800..=0xDFFF), ..] => return true
#| [u16be(_), .. tail] => continue tail
#| [] => break false
#| _ => break true
#| }
#| }
#|}
#|#cfg(not(target="js"))
#|fn utf16_decode_be_no_surrogate_v128(bytes : BytesView) -> String {
#| let string_bytes = FixedArray::make(bytes.length(), b'\x00')
#| for rest = bytes, written = 0 {
#| match rest {
#| [v128le(block), .. tail] => {
#| @v128.v128_store(string_bytes, written, utf16_swap_u16x8(block))
#| continue tail, written + 16
#| }
#| [u16be(code_unit), .. tail] => {
#| string_bytes.unsafe_set(written, (code_unit & 0xFF).to_byte())
#| string_bytes.unsafe_set(written + 1, (code_unit >> 8).to_byte())
#| continue tail, written + 2
#| }
#| [] => break
#| _ => break
#| }
#| }
#| string_bytes.unsafe_reinterpret_as_bytes().to_unchecked_string()
#|}
#|#inline
#|fn drop_utf16_bom(
#| bytes : BytesView,
#| ignore_bom : Bool,
#| endianness : Endian,
#|) -> BytesView {
#| if ignore_bom {
#| if endianness is Little && bytes is [.. b"\xff\xfe", .. rest] {
#| rest
#| } else if endianness is Big && bytes is [.. b"\xfe\xff", .. rest] {
#| rest
#| } else {
#| bytes
#| }
#| } else {
#| bytes
#| }
#|}
#|fn decode_scalar(
#| bytes : BytesView,
#| endianness : Endian,
#|) -> String raise Malformed {
#| if endianness is Little {
#| for x = bytes {
#| match x {
#| [] => break
#| [
#| u16le(0xD800..=0xDBFF as higher),
#| u16le(0xDC00..=0xDFFF as lower),
#| .. rest,
#| ] as bytes => {
#| if ((higher.reinterpret_as_int() - 0xD800) << 10) +
#| (lower.reinterpret_as_int() - 0xDC00) +
#| 0x10000 >
#| 0x10FFFF {
#| raise Malformed(bytes)
#| }
#| continue rest
#| }
#| [u16le(0xD800..=0xDFFF), ..] as bytes => raise Malformed(bytes)
#| [u16le(_), .. rest] => continue rest
#| _ as bytes => raise Malformed(bytes)
#| }
#| }
#| bytes
#| .data()
#| .to_unchecked_string(offset=bytes.start_offset(), length=bytes.length())
#| } else {
#| let string_bytes = FixedArray::make(bytes.length(), b'\x00')
#| let mut i = 0
#| for x = bytes {
#| match x {
#| [] => break
#| [
#| u16be(0xD800..=0xDBFF as higher),
#| u16be(0xDC00..=0xDFFF as lower),
#| .. rest,
#| ] as bytes => {
#| if ((higher.reinterpret_as_int() - 0xD800) << 10) +
#| (lower.reinterpret_as_int() - 0xDC00) +
#| 0x10000 >
#| 0x10FFFF {
#| raise Malformed(bytes)
#| }
#| string_bytes[i] = (higher & 0xFF).to_byte()
#| string_bytes[i + 1] = (higher >> 8).to_byte()
#| string_bytes[i + 2] = (lower & 0xFF).to_byte()
#| string_bytes[i + 3] = (lower >> 8).to_byte()
#| i += 4
#| continue rest
#| }
#| [u16be(0xD800..=0xDFFF), ..] as bytes => raise Malformed(bytes)
#| [u16be(code_unit), .. rest] => {
#| string_bytes[i] = (code_unit & 0xFF).to_byte()
#| string_bytes[i + 1] = (code_unit >> 8).to_byte()
#| i += 2
#| continue rest
#| }
#| _ as bytes => raise Malformed(bytes)
#| }
#| }
#| string_bytes.unsafe_reinterpret_as_bytes().to_unchecked_string()
#| }
#|}
#|#cfg(target="js")
#|pub fn decode(
#| bytes : BytesView,
#| ignore_bom? : Bool = false,
#| endianness? : Endian = Little,
#|) -> String raise Malformed {
#| decode_scalar(drop_utf16_bom(bytes, ignore_bom, endianness), endianness)
#|}
#|#cfg(not(target="js"))
#|pub fn decode(
#| bytes : BytesView,
#| ignore_bom? : Bool = false,
#| endianness? : Endian = Little,
#|) -> String raise Malformed {
#| let bytes = drop_utf16_bom(bytes, ignore_bom, endianness)
#| if endianness is Little {
#| if !utf16_needs_scalar_le_v128(bytes) {
#| return bytes
#| .data()
#| .to_unchecked_string(offset=bytes.start_offset(), length=bytes.length())
#| }
#| } else if !utf16_needs_scalar_be_v128(bytes) {
#| return utf16_decode_be_no_surrogate_v128(bytes)
#| }
#| decode_scalar(bytes, endianness)
#|}
#|pub fn decode_lossy(
#| bytes : BytesView,
#| ignore_bom? : Bool = false,
#| endianness? : Endian = Little,
#|) -> String {
#| let bytes = drop_utf16_bom(bytes, ignore_bom, endianness)
#| let builder = StringBuilder(size_hint=bytes.length())
#| if endianness is Little {
#| for x = bytes {
#| match x {
#| [] => break
#| [
#| u16le(0xD800..=0xDBFF as higher),
#| u16le(0xDC00..=0xDFFF as lower),
#| .. rest,
#| ] => {
#| let ch = ((higher.reinterpret_as_int() - 0xD800) << 10) +
#| (lower.reinterpret_as_int() - 0xDC00) +
#| 0x10000
#| if ch > 0x10FFFF {
#| builder.write_char(U_REP)
#| } else {
#| builder.write_char(ch.unsafe_to_char())
#| }
#| continue rest
#| }
#| [u16le(0xD800..=0xDFFF), .. rest] => {
#| builder.write_char(U_REP)
#| continue rest
#| }
#| [u16le(ch), .. rest] => {
#| builder.write_char(ch.reinterpret_as_int().unsafe_to_char())
#| continue rest
#| }
#| _ => {
#| builder.write_char(U_REP)
#| break
#| }
#| }
#| }
#| } else {
#| for x = bytes {
#| match x {
#| [] => break
#| [
#| u16be(0xD800..=0xDBFF as higher),
#| u16be(0xDC00..=0xDFFF as lower),
#| .. rest,
#| ] => {
#| let ch = ((higher.reinterpret_as_int() - 0xD800) << 10) +
#| (lower.reinterpret_as_int() - 0xDC00) +
#| 0x10000
#| if ch > 0x10FFFF {
#| builder.write_char(U_REP)
#| } else {
#| builder.write_char(ch.unsafe_to_char())
#| }
#| continue rest
#| }
#| [u16be(0xD800..=0xDFFF), .. rest] => {
#| builder.write_char(U_REP)
#| continue rest
#| }
#| [u16be(ch), .. rest] => {
#| builder.write_char(ch.reinterpret_as_int().unsafe_to_char())
#| continue rest
#| }
#| _ => {
#| builder.write_char(U_REP)
#| break
#| }
#| }
#| }
#| }
#| builder.to_string()
#|}
),
"encode.mbt": (
#|pub fn encode(
#| str : StringView,
#| bom? : Bool = false,
#| endianness? : Endian = Little,
#|) -> Bytes {
#| if endianness is Little {
#| if bom is true {
#| let arr = FixedArray::make(str.length() * 2 + 2, b'\x00')
#| arr[0] = 0xFF
#| arr[1] = 0xFE
#| arr.blit_from_string(2, str.data(), str.start_offset(), str.length())
#| arr.unsafe_reinterpret_as_bytes()
#| } else {
#| let arr = FixedArray::make(str.length() * 2, b'\x00')
#| arr.blit_from_string(0, str.data(), str.start_offset(), str.length())
#| arr.unsafe_reinterpret_as_bytes()
#| }
#| } else if bom is true {
#| let arr = FixedArray::make(str.length() * 2 + 2, b'\x00')
#| arr[0] = 0xFE
#| arr[1] = 0xFF
#| for code_unit in str.code_units(); i = 2 {
#| arr[i] = (code_unit >> 8).to_byte()
#| arr[i + 1] = (code_unit & 0xFF).to_byte()
#| continue i + 2
#| }
#| arr.unsafe_reinterpret_as_bytes()
#| } else {
#| let arr = FixedArray::make(str.length() * 2, b'\x00')
#| for code_unit in str.code_units(); i = 0 {
#| arr[i] = (code_unit >> 8).to_byte()
#| arr[i + 1] = (code_unit & 0xFF).to_byte()
#| continue i + 2
#| }
#| arr.unsafe_reinterpret_as_bytes()
#| }
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Endian with @debug.Debug::{to_repr}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Malformed with @debug.Debug::{to_repr}
),
"types.mbt": (
#|pub(all) enum Endian {
#| Little
#| Big
#|} derive(@debug.Debug)
),
},
)
///|
let moonbitlang_core_encoding_utf8_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/encoding/utf8",
deps={},
files={
"decode.mbt": (
#|pub suberror Malformed {
#| Malformed(BytesView)
#|} derive(@debug.Debug)
#|fn drop_utf8_bom(bytes : BytesView, ignore_bom : Bool) -> BytesView {
#| let bytes = if ignore_bom && bytes is [.. b"\xef\xbb\xbf", .. rest] {
#| rest
#| } else {
#| bytes
#| }
#| bytes
#|}
),
"decode_js.mbt": (
#|extern "js" fn decode_utf8_js(
#| bytes : Bytes,
#| start : Int,
#| len : Int,
#| preserve_bom : Bool,
#|) -> FixedArray[String] =
#| #| ((preserveBOMDecoder, dropBOMDecoder) => function(bytes, start, len, preserveBOM) {
#| #| try {
#| #| const end = start + len;
#| #| const slice = bytes.subarray(start, end);
#| #| const decoder = preserveBOM ? preserveBOMDecoder : dropBOMDecoder;
#| #| return [decoder.decode(slice)];
#| #| } catch (_) {
#| #| return [];
#| #| }
#| #| })(
#| #| new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }),
#| #| new TextDecoder("utf-8", { fatal: true, ignoreBOM: false }),
#| #| )
#|extern "js" fn decode_utf8_lossy_js(
#| bytes : Bytes,
#| start : Int,
#| len : Int,
#| preserve_bom : Bool,
#|) -> String =
#| #| ((preserveBOMDecoder, dropBOMDecoder) => function(bytes, start, len, preserveBOM) {
#| #| const end = start + len;
#| #| const slice = bytes.subarray(start, end);
#| #| const decoder = preserveBOM ? preserveBOMDecoder : dropBOMDecoder;
#| #| return decoder.decode(slice);
#| #| })(
#| #| new TextDecoder("utf-8", { ignoreBOM: true }),
#| #| new TextDecoder("utf-8", { ignoreBOM: false }),
#| #| )
#|fn utf8_find_malformed(src : Bytes, src_offset : Int, src_length : Int) -> Int {
#| let view = src[src_offset:src_offset + src_length]
#| for bytes = view {
#| match bytes {
#| [] => break -1
#| [
#| _..=0x7F,
#| _..=0x7F,
#| _..=0x7F,
#| _..=0x7F,
#| _..=0x7F,
#| _..=0x7F,
#| _..=0x7F,
#| _..=0x7F,
#| .. rest,
#| ] => continue rest
#| [0..=0x7F, .. rest] => continue rest
#| [0xC2..=0xDF, 0x80..=0xBF, .. rest] => continue rest
#| [0xE0, 0xA0..=0xBF, 0x80..=0xBF, .. rest]
#| | [0xE1..=0xEC, 0x80..=0xBF, 0x80..=0xBF, .. rest]
#| | [0xED, 0x80..=0x9F, 0x80..=0xBF, .. rest]
#| | [0xEE..=0xEF, 0x80..=0xBF, 0x80..=0xBF, .. rest] => continue rest
#| [0xF0, 0x90..=0xBF, 0x80..=0xBF, 0x80..=0xBF, .. rest]
#| | [0xF1..=0xF3, 0x80..=0xBF, 0x80..=0xBF, 0x80..=0xBF, .. rest]
#| | [0xF4, 0x80..=0x8F, 0x80..=0xBF, 0x80..=0xBF, .. rest] => continue rest
#| malformed => break malformed.start_offset() - src_offset
#| }
#| }
#|}
#|fn strict_malformed_suffix(bytes : BytesView) -> BytesView {
#| let input = bytes.data()
#| let src_offset = bytes.start_offset()
#| let src_length = bytes.length()
#| let malformed_offset = utf8_find_malformed(input, src_offset, src_length)
#| bytes[malformed_offset:]
#|}
#|pub fn decode(
#| bytes : BytesView,
#| ignore_bom? : Bool = false,
#|) -> String raise Malformed {
#| let result = decode_utf8_js(
#| bytes.data(),
#| bytes.start_offset(),
#| bytes.length(),
#| !ignore_bom,
#| )
#| if result.length() == 1 {
#| result[0]
#| } else {
#| let bytes = drop_utf8_bom(bytes, ignore_bom)
#| raise Malformed(strict_malformed_suffix(bytes))
#| }
#|}
#|pub fn decode_lossy(bytes : BytesView, ignore_bom? : Bool = false) -> String {
#| decode_utf8_lossy_js(
#| bytes.data(),
#| bytes.start_offset(),
#| bytes.length(),
#| !ignore_bom,
#| )
#|}
),
"encode_js.mbt": (
#|extern "js" fn encode_utf8_js(
#| src : String,
#| start : Int,
#| len : Int,
#| bom : Bool,
#|) -> Bytes =
#| #| (() => {
#| #| const encoder = new TextEncoder();
#| #| return function(src, start, len, bom) {
#| #| const end = start + len;
#| #| const encoded = encoder.encode(src.slice(start, end));
#| #| if (!bom) {
#| #| return encoded;
#| #| }
#| #| const result = new Uint8Array(encoded.length + 3);
#| #| result[0] = 0xEF;
#| #| result[1] = 0xBB;
#| #| result[2] = 0xBF;
#| #| result.set(encoded, 3);
#| #| return result;
#| #| };
#| #| })()
#|pub fn encode(str : StringView, bom? : Bool = false) -> Bytes {
#| encode_utf8_js(str.data(), str.start_offset(), str.length(), bom)
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Malformed with @debug.Debug::{to_repr}
),
},
)
///|
let moonbitlang_core_env_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/env",
deps={},
files={
"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()
#|}
#|pub fn get_env_var(key : String) -> String? {
#| get_env_var_internal(key)
#|}
#|pub fn get_env_vars() -> Map[String, String] {
#| get_env_vars_internal()
#|}
#|pub fn set_env_var(key : String, value : String) -> Unit {
#| set_env_var_internal(key, value)
#|}
#|pub fn unset_env_var(key : String) -> Unit {
#| unset_env_var_internal(key)
#|}
#|pub fn rand(n : Int) -> Bytes? {
#| if n <= 0 {
#| let probe : FixedArray[Byte] = FixedArray::make(1, b'\x00')
#| return if rand_internal(probe) { Some(b"") } else { None }
#| }
#| let buf : FixedArray[Byte] = FixedArray::make(n, b'\x00')
#| if rand_internal(buf) {
#| Some(Bytes::from_array(buf))
#| } else {
#| None
#| }
#|}
#|#cfg(not(target="native"))
#|#warnings("-unused_value")
#|fn unused_function() -> Unit {
#| ignore(@ref.Ref(42))
#| let _ : (@os_string.OsString) -> Unit = ignore
#|}
),
"env_js.mbt": (
#|fn get_cli_args_internal() -> Array[String] {
#| Array::from_fixed_array(get_cli_args_ffi())
#|}
#|extern "js" fn get_cli_args_ffi() -> FixedArray[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 BigInt.asUintN(64, BigInt(nowMs));
#| #| }
#|extern "js" fn current_dir_internal() -> String? =
#| #| function() {
#| #| if (typeof process !== "undefined" && typeof process.cwd === "function") {
#| #| return process.cwd();
#| #| } else {
#| #| return null;
#| #| }
#| #| }
#|fn get_env_var_internal(key : String) -> String? {
#| if is_env_var_exists_internal(key) {
#| Some(get_env_var_value_internal(key))
#| } else {
#| None
#| }
#|}
#|extern "js" fn is_env_var_exists_internal(key : String) -> Bool =
#| #| function(key) {
#| #| if (typeof process === "undefined" || typeof process.env === "undefined") {
#| #| return false;
#| #| }
#| #| return Object.prototype.hasOwnProperty.call(process.env, key);
#| #| }
#|extern "js" fn get_env_var_value_internal(key : String) -> String =
#| #| function(key) {
#| #| if (typeof process === "undefined" || typeof process.env === "undefined") {
#| #| return "";
#| #| }
#| #| const value = process.env[key];
#| #| return value === undefined ? "" : String(value);
#| #| }
#|fn get_env_vars_internal() -> Map[String, String] {
#| let tmp = get_env_vars_array_internal()
#| let res = Map([])
#| for i = 0; i < tmp.length(); i = i + 2 {
#| res[tmp[i]] = tmp[i + 1]
#| }
#| res
#|}
#|extern "js" fn get_env_vars_array_internal() -> FixedArray[String] =
#| #| function() {
#| #| if (typeof process === "undefined" || typeof process.env === "undefined") {
#| #| return [];
#| #| }
#| #| const result = [];
#| #| for (const key in process.env) {
#| #| const value = process.env[key];
#| #| if (value !== undefined) {
#| #| result.push(key);
#| #| result.push(String(value));
#| #| }
#| #| }
#| #| return result;
#| #| }
#|fn set_env_var_internal(key : String, value : String) -> Unit {
#| set_env_var_ffi(key, value)
#|}
#|extern "js" fn set_env_var_ffi(key : String, value : String) -> Unit =
#| #| function(key, value) {
#| #| if (typeof process !== "undefined" && typeof process.env !== "undefined") {
#| #| process.env[key] = value;
#| #| }
#| #| }
#|fn unset_env_var_internal(key : String) -> Unit {
#| unset_env_var_ffi(key)
#|}
#|extern "js" fn unset_env_var_ffi(key : String) -> Unit =
#| #| function(key) {
#| #| if (typeof process !== "undefined" && typeof process.env !== "undefined") {
#| #| delete process.env[key];
#| #| }
#| #| }
#|fn rand_internal(to_be_filled : FixedArray[Byte]) -> Bool {
#| if to_be_filled.length() == 0 {
#| return true
#| }
#| get_random_values_js(to_be_filled)
#|}
#|extern "js" fn get_random_values_js(to_be_filled : FixedArray[Byte]) -> Bool =
#| #| function(toBeFilled) {
#| #| const cryptoObj = globalThis.crypto;
#| #| if (cryptoObj === undefined || typeof cryptoObj.getRandomValues !== "function") {
#| #| return false;
#| #| }
#| #| try {
#| #| for (let offset = 0; offset < toBeFilled.length; offset += 65536) {
#| #| cryptoObj.getRandomValues(toBeFilled.subarray(offset, offset + 65536));
#| #| }
#| #| return true;
#| #| } catch (_) {
#| #| return false;
#| #| }
#| #| }
),
},
)
///|
let moonbitlang_core_error_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/error",
deps={},
files={
"debug.mbt": (
#|fn error_to_repr(e : Error) -> @debug.Repr = "%error.to_repr"
#|pub impl @debug.Debug for Error with fn to_repr(self) {
#| error_to_repr(self)
#|}
#|test "Debug for Error" {
#| fn fail_with_error() -> Unit raise {
#| raise InspectError::InspectError("test error")
#| }
#| try fail_with_error() catch {
#| e => @debug.debug_inspect(e, content="InspectError(\"test error\")")
#| } noraise {
#| _ => fail("expected error")
#| }
#|}
),
"error.mbt": (
#|pub fn Error::to_string(self : Error) -> String = "%error.to_string"
#|pub impl Show for Error with fn to_string(self) {
#| Error::to_string(self)
#|}
#|pub fn Error::to_json(self : Error) -> Json = "%error.to_json"
#|pub impl ToJson for Error with fn to_json(self) {
#| self.to_json()
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Error with @debug.Debug::{to_repr}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Error with Show::{output}
),
},
)
///|
let moonbitlang_core_float_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/float",
deps={},
files={
"extends.mbt": (
#|pub extend Float with Add::{add}
#|pub extend Float with Compare::{compare}
#|pub extend Float with Div::{div}
#|pub extend Float with Eq::{equal}
#|pub extend Float with Hash::{hash}
#|pub extend Float with Mod::{mod}
#|pub extend Float with Mul::{mul}
#|pub extend Float with Neg::{neg}
#|pub extend Float with Show::{to_string}
#|pub extend Float with Sub::{sub}
#|pub extend Float with ToJson::{to_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Float with Compare::{op_ge, op_gt, op_le, op_lt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Float with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Float with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Float with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Float with Show::{output}
),
"float.mbt": (
#|pub let not_a_number : Float = Float::reinterpret_from_int(0x7FC00000)
#|pub let infinity : Float = Float::reinterpret_from_int(0x7F800000)
#|pub let neg_infinity : Float = Float::reinterpret_from_int(0xFF800000)
#|pub let max_value : Float = Float::reinterpret_from_int(0x7F7FFFFF)
#|pub let min_value : Float = Float::reinterpret_from_int(0xFF7FFFFF)
#|pub let min_positive : Float = Float::reinterpret_from_int(0x00800000)
#|#as_free_fn(deprecated)
#|pub fn Float::abs(self : Float) -> Float = "%f32.abs"
#|#deprecated
#|pub fn default() -> Float {
#| 0.0
#|}
),
"methods.mbt": (
#|pub impl Show for Float with fn to_string(self) {
#| self.to_double().to_string()
#|}
#|pub impl Default for Float with fn default() {
#| 0
#|}
#|pub impl Hash for Float with fn hash_combine(self, hasher) {
#| hasher.combine_uint(if self is 0 { 0U } else { self.reinterpret_as_uint() })
#|}
#|pub fn Float::to_be_bytes(self : Float) -> Bytes {
#| let uint = self.reinterpret_as_uint()
#| [
#| (uint >> 24).to_byte(),
#| (uint >> 16).to_byte(),
#| (uint >> 8).to_byte(),
#| uint.to_byte(),
#| ]
#|}
#|pub fn Float::to_le_bytes(self : Float) -> Bytes {
#| let uint = self.reinterpret_as_uint()
#| [
#| uint.to_byte(),
#| (uint >> 8).to_byte(),
#| (uint >> 16).to_byte(),
#| (uint >> 24).to_byte(),
#| ]
#|}
#|pub fn Float::is_inf(self : Float) -> Bool {
#| self.is_pos_inf() || self.is_neg_inf()
#|}
#|pub fn Float::is_pos_inf(self : Float) -> Bool {
#| self > max_value
#|}
#|pub fn Float::is_neg_inf(self : Float) -> Bool {
#| self < min_value
#|}
#|pub fn Float::is_nan(self : Float) -> Bool {
#| self != self
#|}
#|pub fn Float::min(self : Float, other : Float) -> Float {
#| if self.is_nan() {
#| other
#| } else if other.is_nan() {
#| self
#| } else if self < other {
#| self
#| } else {
#| other
#| }
#|}
#|pub fn Float::max(self : Float, other : Float) -> Float {
#| if self.is_nan() {
#| other
#| } else if other.is_nan() {
#| self
#| } else if self > other {
#| self
#| } else {
#| other
#| }
#|}
#|pub fn Float::clamp(self : Float, min~ : Float, max~ : Float) -> Float {
#| guard! min <= max
#| if self < min {
#| min
#| } else if self > max {
#| max
#| } else {
#| self
#| }
#|}
#|pub fn Float::lerp(self : Float, target~ : Float, t~ : Float) -> Float {
#| self + (target - self) * t
#|}
#|pub fn Float::signum(self : Float) -> Float {
#| if self < 0.0 {
#| -1.0
#| } else if self > 0.0 {
#| 1.0
#| } else {
#| 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
#|}
#|pub impl Mod for Float with fn mod(self : Float, other : Float) -> Float {
#| Float::from_double(self.to_double() % other.to_double())
#|}
#|pub fn Float::until(
#| self : Float,
#| end : Float,
#| step? : Float = 1.0,
#| inclusive? : Bool = false,
#|) -> Iter[Float] {
#| if step == 0.0 {
#| return [||]
#| }
#| let mut curr_value = Some(self)
#| Iter::new(() => {
#| guard curr_value is Some(i) else { None }
#| guard (step > 0.0 && i < end) ||
#| (step < 0.0 && i > end) ||
#| (inclusive && i == end) else {
#| None
#| }
#| let next = i + step
#| if (step > 0.0 && next >= i) || (step < 0.0 && next <= i) {
#| curr_value = Some(next)
#| } else {
#| curr_value = None
#| }
#| Some(i)
#| })
#|}
#|pub fn Float::to_double(self : Float) -> Double = "%f32.to_f64"
#|pub impl ToJson for Float with fn to_json(self : Float) -> Json {
#| Json::number(self.to_double())
#|}
#|pub fn Float::sqrt(self : Float) -> Float = "%f32.sqrt"
#|pub fn Float::reinterpret_as_int(self : Float) -> Int = "%f32.to_i32_reinterpret"
#|pub impl Neg for Float with fn neg(self) = "%f32.neg"
#|pub impl Add for Float with fn add(self, other) = "%f32.add"
#|pub impl Sub for Float with fn sub(self, other) = "%f32.sub"
#|pub impl Mul for Float with fn mul(self, other) = "%f32.mul"
#|pub impl Div for Float with fn div(self, other) = "%f32.div"
#|pub impl Eq for Float with fn equal(self : Float, other : Float) -> Bool = "%f32.eq"
#|pub impl Eq for Float with fn not_equal(self : Float, other : Float) -> Bool = "%f32.ne"
#|#deprecated("Use `a != b` instead")
#|#doc(hidden)
#|pub fn Float::op_neq(self : Float, other : Float) -> Bool = "%f32.ne"
#|pub impl Compare for Float with fn compare(self, other) = "%f32.compare"
#|pub impl Compare for Float with fn op_lt(x, y) = "%f32.lt"
#|pub impl Compare for Float with fn op_le(x, y) = "%f32.le"
#|pub impl Compare for Float with fn op_gt(x, y) = "%f32.gt"
#|pub impl Compare for Float with fn op_ge(x, y) = "%f32.ge"
#|pub fn Float::reinterpret_as_uint(self : Float) -> UInt = "%f32.to_i32_reinterpret"
#|pub fn Float::reinterpret_from_int(self : Int) -> Float = "%i32.to_f32_reinterpret"
#|pub fn Float::reinterpret_from_uint(self : UInt) -> Float = "%i32.to_f32_reinterpret"
#|test "Float::reinterpret" {
#| inspect(Float::reinterpret_from_int(1065353216), content="1")
#| inspect(Float::reinterpret_from_uint(0x3F800000), content="1")
#|}
#|pub fn Float::from_int(self : Int) -> Float = "%i32.to_f32"
#|pub fn Float::from_byte(self : Byte) -> Float = "%byte.to_f32"
#|pub fn Float::from_double(self : Double) -> Float = "%f64.to_f32"
#|pub fn Float::from_uint(self : UInt) -> Float = "%u32.to_f32"
#|#cfg(not(target="js"))
#|pub fn Float::from_uint64(self : UInt64) -> Float = "%u64.to_f32"
#|#cfg(target="js")
#|pub fn Float::from_uint64(self : UInt64) -> Float {
#| Float::from_double(self.to_double())
#|}
#|test "Float::from_uint64" {
#| let n = 42UL
#| inspect(Float::from_uint64(n).to_double(), content="42")
#| let big = 18446744073709551615UL // UInt64::max_value
#| inspect(Float::from_uint64(big).to_double(), content="18446744073709552000")
#|}
#|#cfg(not(target="js"))
#|pub fn Float::from_int64(self : Int64) -> Float = "%i64.to_f32"
#|#cfg(target="js")
#|pub fn Float::from_int64(self : Int64) -> Float {
#| Float::from_double(self.to_double())
#|}
#|test "Float::from_int64" {
#| let n = 42L
#| let f = Float::from_int64(n)
#| inspect(f.to_double(), content="42")
#|}
),
"pow.mbt": (
#|#deprecated("Use `@math.powf` instead")
#|#as_free_fn(deprecated="Use `@math.powf` instead")
#|#warnings("-deprecated")
#|pub fn Float::pow(self : Float, other : Float) -> Float {
#| Float::from_double(self.to_double().pow(other.to_double()))
#|}
),
"round_js.mbt": (
#|#as_free_fn
#|pub fn Float::trunc(self : Float) -> Float = "Math" "trunc"
#|#as_free_fn
#|pub fn Float::ceil(self : Float) -> Float = "Math" "ceil"
#|#as_free_fn
#|pub fn Float::floor(self : Float) -> Float = "Math" "floor"
#|#as_free_fn
#|pub fn Float::round(self : Float) -> Float = "Math" "round"
),
"to_int.mbt": (
#|fn Float::to_unchecked_int(self : Float) -> Int = "%f32.to_i32"
#|pub fn Float::to_int(self : Float) -> Int {
#| if self != self {
#| 0
#| } else if self >= 2147483647 {
#| 2147483647
#| } else if self <= -2147483648 {
#| -2147483648
#| } else {
#| self.to_unchecked_int()
#| }
#|}
),
},
)
///|
let moonbitlang_core_hashmap_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/hashmap",
deps={},
files={
"debug.mbt": (
#|pub impl[K : @debug.Debug, V : @debug.Debug] @debug.Debug for HashMap[K, V] with fn to_repr(
#| self,
#|) {
#| @debug.Repr::opaque_(
#| "HashMap",
#| @debug.Repr::map([ for k, v in self => (Repr(k), Repr(v)) ]),
#| )
#|}
#|test "Debug for HashMap" {
#| let hm : HashMap[Int, String] = from_array([(2, "b")])
#| @debug.debug_inspect(
#| hm,
#| content=(
#| #|
#| ),
#| )
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `HashMap([], capacity=...)` instead")
#|#as_free_fn(deprecated="Use `HashMap([], capacity=...)` instead")
#|pub fn[K, V] HashMap::new(
#| capacity? : Int = default_init_capacity,
#|) -> HashMap[K, V] {
#| new_hashmap(capacity)
#|}
),
"extends.mbt": (
#|pub extend HashMap with Eq::{equal}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashMap with @debug.Debug::{to_repr}
#|#deprecated("Use `@json.from_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashMap with @json.FromJson::{from_json}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashMap with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashMap with Eq::{not_equal}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashMap with ToJson::{to_json}
),
"hashmap.mbt": (
#|let default_init_capacity = 8
#|fn[K, V] new_hashmap(capacity : Int) -> HashMap[K, V] {
#| let capacity = capacity.next_power_of_two()
#| {
#| size: 0,
#| capacity,
#| entries: FixedArray::make(capacity, None),
#| capacity_mask: capacity - 1,
#| }
#|}
#|fn capacity_for_length(length : Int) -> Int {
#| (length * 2).next_power_of_two()
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[K : Hash + Eq, V] HashMap::HashMap(
#| arr : ArrayView[(K, V)],
#| capacity? : Int,
#|) -> HashMap[K, V] {
#| let length = arr.length()
#| let capacity = match capacity {
#| Some(capacity) => capacity.max(capacity_for_length(length))
#| None =>
#| if length == 0 {
#| default_init_capacity
#| } else {
#| capacity_for_length(length)
#| }
#| }
#| let m = new_hashmap(capacity)
#| arr.each(e => m.set(e.0, e.1))
#| m
#|}
#|#alias("_[_]=_")
#|#owned(value)
#|pub fn[K : Hash + Eq, V] HashMap::set(
#| self : HashMap[K, V],
#| key : K,
#| value : V,
#|) -> Unit {
#| self.set_with_hash(key, value, Hash::hash(key))
#|}
#|#owned(value)
#|fn[K : Eq, V] HashMap::set_with_hash(
#| self : HashMap[K, V],
#| key : K,
#| value : V,
#| hash : Int,
#|) -> Unit {
#| for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries.unsafe_get(idx) {
#| None => {
#| if self.size >= self.capacity / 2 {
#| self.grow()
#| continue 0, hash & self.capacity_mask
#| }
#| let entry = { psl, key, value, hash, }
#| self.entries.unsafe_set(idx, Some(entry))
#| self.size += 1
#| return
#| }
#| Some(curr_entry) => {
#| if curr_entry.hash == hash && curr_entry.key == key {
#| curr_entry.value = value
#| return
#| }
#| if psl > curr_entry.psl {
#| if self.size >= self.capacity / 2 {
#| self.grow()
#| continue 0, hash & self.capacity_mask
#| }
#| self.push_away(idx, curr_entry)
#| let entry = { psl, key, value, hash, }
#| self.entries.unsafe_set(idx, Some(entry))
#| self.size += 1
#| return
#| }
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| }
#| }
#|}
#|#owned(entry)
#|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.unsafe_get(idx) {
#| None => {
#| entry.psl = psl
#| self.entries.unsafe_set(idx, Some(entry))
#| break
#| }
#| Some(curr_entry) =>
#| if psl > curr_entry.psl {
#| entry.psl = psl
#| self.entries.unsafe_set(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] HashMap::get(self : HashMap[K, V], key : K) -> V? {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(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[V] HashMap::get_from_bytes(
#| self : HashMap[Bytes, V],
#| key : BytesView,
#|) -> V? {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(idx) is Some(entry) else { break None }
#| if entry.hash == hash && key.equal_to_bytes(entry.key) {
#| break Some(entry.value)
#| }
#| if i > entry.psl {
#| break None
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#|}
#|pub fn[V] HashMap::get_from_string(
#| self : HashMap[String, V],
#| key : StringView,
#|) -> V? {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(idx) is Some(entry) else { break None }
#| if entry.hash == hash && key.equal_to_string(entry.key) {
#| break Some(entry.value)
#| }
#| if i > entry.psl {
#| break None
#| }
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#|}
#|#alias("_[_]")
#|pub fn[K : Hash + Eq, V] HashMap::at(self : HashMap[K, V], key : K) -> V {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard! self.entries.unsafe_get(idx) is Some(entry)
#| if entry.hash == hash && entry.key == key {
#| break entry.value
#| }
#| guard! i <= entry.psl
#| continue i + 1, (idx + 1) & self.capacity_mask
#| }
#|}
#|pub fn[K : Hash + Eq, V] HashMap::get_or_init(
#| self : HashMap[K, V],
#| key : K,
#| init : () -> V,
#|) -> V {
#| let hash = Hash::hash(key)
#| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash &
#| self.capacity_mask {
#| match self.entries.unsafe_get(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.unsafe_set(idx, Some(entry))
#| self.size += 1
#| }
#| new_value
#|}
#|pub fn[K : Hash + Eq, V] HashMap::update(
#| self : HashMap[K, V],
#| key : K,
#| f : (V?) -> V?,
#|) -> Unit {
#| let hash = Hash::hash(key)
#| let (idx, psl, new_value, push_away) = for psl = 0, idx = hash &
#| self.capacity_mask {
#| match self.entries.unsafe_get(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.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.capacity / 2 {
#| self.grow()
#| self.set_with_hash(key, new_value, hash)
#| } else {
#| if push_away is Some(entry) {
#| self.push_away(idx, entry)
#| }
#| self.entries.unsafe_set(idx, Some({ psl, hash, key, value: new_value, }))
#| self.size += 1
#| }
#|}
#|pub fn[K : Hash + Eq, V] HashMap::update_or_default(
#| self : HashMap[K, V],
#| key : K,
#| default : V,
#| f : (V) -> V,
#|) -> Unit {
#| let hash = Hash::hash(key)
#| let (idx, psl, push_away) = for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries.unsafe_get(idx) {
#| Some(entry) => {
#| if entry.hash == hash && entry.key == key {
#| entry.value = f(entry.value)
#| return
#| }
#| if psl > entry.psl {
#| break (idx, psl, Some(entry))
#| }
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| None => break (idx, psl, None)
#| }
#| }
#| if self.size >= self.capacity / 2 {
#| self.grow()
#| self.set_with_hash(key, default, hash)
#| } else {
#| if push_away is Some(entry) {
#| self.push_away(idx, entry)
#| }
#| let entry = { psl, hash, key, value: default, }
#| self.entries.unsafe_set(idx, Some(entry))
#| self.size += 1
#| }
#|}
#|pub fn[K : Hash + Eq, V] HashMap::get_or_default(
#| self : HashMap[K, V],
#| key : K,
#| default : V,
#|) -> V {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(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] HashMap::contains(
#| self : HashMap[K, V],
#| key : K,
#|) -> Bool {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(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] HashMap::contains_kv(
#| self : HashMap[K, V],
#| key : K,
#| value : V,
#|) -> Bool {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(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] HashMap::remove(self : HashMap[K, V], key : K) -> Unit {
#| self.remove_with_hash(key, Hash::hash(key))
#|}
#|fn[K : Eq, V] HashMap::remove_with_hash(
#| self : HashMap[K, V],
#| key : K,
#| hash : Int,
#|) -> Unit {
#| for i = 0, idx = hash & self.capacity_mask {
#| match self.entries.unsafe_get(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] HashMap::shift_back(self : HashMap[K, V], idx : Int) -> Unit {
#| for cur = idx {
#| let next = (cur + 1) & self.capacity_mask
#| match self.entries.unsafe_get(next) {
#| None | Some({ psl: 0, .. }) => {
#| self.entries.unsafe_set(cur, None)
#| break
#| }
#| Some(entry) => {
#| entry.psl -= 1
#| self.entries.unsafe_set(cur, Some(entry))
#| continue next
#| }
#| }
#| }
#|}
#|fn[K, V] HashMap::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
#| for entry in old_entries {
#| if entry is Some(entry) {
#| self.rehash_place_entry(entry)
#| }
#| }
#|}
#|#owned(entry)
#|fn[K, V] HashMap::rehash_place_entry(
#| self : HashMap[K, V],
#| entry : Entry[K, V],
#|) -> Unit {
#| let hash = entry.hash
#| for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries.unsafe_get(idx) {
#| None => {
#| entry.psl = psl
#| self.entries.unsafe_set(idx, Some(entry))
#| return
#| }
#| Some(curr) =>
#| if psl > curr.psl {
#| self.push_away(idx, curr)
#| entry.psl = psl
#| self.entries.unsafe_set(idx, Some(entry))
#| return
#| } else {
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| }
#| }
#|}
#|test "of" {
#| let m = from_array([(1, 2), (3, 4)])
#| @debug.debug_inspect(m.get(1), content="Some(2)")
#| @debug.debug_inspect(m.get(3), content="Some(4)")
#|}
#|pub impl[K, V] Default for HashMap[K, V] with fn default() {
#| new_hashmap(default_init_capacity)
#|}
#|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.. HashMap[K, V] {
#| let result = self.copy()
#| result.merge_in_place(other)
#| result
#|}
#|pub fn[K : Eq, V] HashMap::merge_in_place(
#| self : HashMap[K, V],
#| other : HashMap[K, V],
#|) -> Unit {
#| if physical_equal(self, other) {
#| return
#| }
#| for entry in other.entries {
#| if entry is Some({ key, value, hash, .. }) {
#| self.set_with_hash(key, value, hash)
#| }
#| }
#|}
#|priv struct MyString(String) derive(Eq, @debug.Debug)
#|#coverage.skip
#|impl Hash for MyString with fn hash(self) {
#| let MyString(self) = self
#| self.length()
#|}
#|#coverage.skip
#|impl Hash for MyString with fn hash_combine(self, hasher) {
#| hasher.combine_string(self.0)
#|}
#|test "set" {
#| let m : HashMap[MyString, Int] = new_hashmap(default_init_capacity)
#| m.set("a", 1)
#| m.set("b", 1)
#| m.set("bc", 2)
#| m.set("abc", 3)
#| m.set("cd", 2)
#| m.set("c", 1)
#| m.set("d", 1)
#| inspect(m.length(), content="7")
#|}
#|test "remove" {
#| let m : HashMap[MyString, Int] = new_hashmap(default_init_capacity)
#| m.set("a", 1)
#| m.set("ab", 2)
#| m.set("bc", 2)
#| m.set("cd", 2)
#| m.set("abc", 3)
#| m.set("abcdef", 6)
#| m.remove("ab")
#| inspect(m.length(), content="5")
#|}
#|test "remove_unexist_key" {
#| let m : HashMap[MyString, Int] = new_hashmap(default_init_capacity)
#| m.set("a", 1)
#| m.set("ab", 2)
#| m.set("abc", 3)
#| m.remove("d")
#| inspect(m.length(), content="3")
#|}
#|test "clear" {
#| let m : HashMap[MyString, Int] = from_array([("a", 1), ("b", 2), ("c", 3)])
#| m.clear()
#| inspect(m.length(), content="0")
#| inspect(m.capacity(), content="8")
#| for entry in m.entries {
#| @test.assert_same_object(entry, None)
#| }
#|}
#|test "grow" {
#| let m : HashMap[MyString, Int] = new_hashmap(default_init_capacity)
#| m.set("C", 1)
#| m.set("Go", 2)
#| m.set("C++", 3)
#| m.set("Java", 4)
#| m.set("Scala", 5)
#| m.set("Julia", 5)
#| inspect(m.length(), content="6")
#| inspect(m.capacity(), content="16")
#| m.set("Cobol", 5)
#| inspect(m.length(), content="7")
#| inspect(m.capacity(), content="16")
#| m.set("Python", 6)
#| m.set("Haskell", 7)
#| m.set("Rescript", 8)
#| inspect(m.length(), content="10")
#| inspect(m.capacity(), content="32")
#| @debug.debug_inspect(m.get("C"), content="Some(1)")
#| @debug.debug_inspect(m.get("Go"), content="Some(2)")
#| @debug.debug_inspect(m.get("C++"), content="Some(3)")
#| @debug.debug_inspect(m.get("Java"), content="Some(4)")
#| @debug.debug_inspect(m.get("Scala"), content="Some(5)")
#| @debug.debug_inspect(m.get("Julia"), content="Some(5)")
#| @debug.debug_inspect(m.get("Cobol"), content="Some(5)")
#| @debug.debug_inspect(m.get("Python"), content="Some(6)")
#| @debug.debug_inspect(m.get("Haskell"), content="Some(7)")
#| @debug.debug_inspect(m.get("Rescript"), content="Some(8)")
#|}
#|test "_[_]" {
#| let m : HashMap[MyString, Int] = new_hashmap(default_init_capacity)
#| m.set("a", 1)
#| m.set("b", 1)
#| m.set("cc", 2)
#| inspect(m["a"], content="1")
#| inspect(m["b"], content="1")
#| inspect(m["cc"], content="2")
#|}
#|test "get_or_init" {
#| let m : HashMap[MyString, Int] = new_hashmap(default_init_capacity)
#| inspect(m.get_or_init("a", () => 1), content="1")
#| @debug.debug_inspect(m.get("a"), content="Some(1)")
#| inspect(m.get_or_init("a", () => 2), content="1")
#| @debug.debug_inspect(m.get("a"), content="Some(1)")
#|}
),
"json.mbt": (
#|pub impl[K : Show, V : ToJson] ToJson for HashMap[K, V] with fn to_json(self) {
#| Json::object(
#| Map(
#| capacity=self.capacity,
#| [
#| for k, v in self => (k.to_string(), v.to_json())
#| ],
#| ),
#| )
#|}
#|pub impl[V : @json.FromJson] @json.FromJson for HashMap[String, V] with fn from_json(
#| json,
#| path,
#|) {
#| guard json is Object(obj) else {
#| raise JsonDecodeError((path, "@hashmap.from_json: expected object"))
#| }
#| let res : HashMap[String, V] = HashMap(
#| [],
#| capacity=capacity_for_length(obj.length()),
#| )
#| for k, v in obj {
#| res[k] = V::from_json(v, path.add_key(k))
#| }
#| res
#|}
),
"types.mbt": (
#|priv struct Entry[K, V] {
#| mut psl : Int
#| hash : Int
#| key : K
#| mut value : V
#|} derive(@debug.Debug)
#|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 fn 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 }
#| } nobreak {
#| true
#| }
#|}
),
"utils.mbt": (
#|fn[K : Show, V : Show] HashMap::_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
#| }
#| } nobreak {
#| s
#| }
#|}
#|pub fn[K, V] HashMap::clear(self : HashMap[K, V]) -> Unit {
#| self.entries.fill(None)
#| self.size = 0
#|}
#|#alias(iterator, deprecated)
#|pub fn[K, V] HashMap::iter(self : HashMap[K, V]) -> Iter[(K, V)] {
#| let mut i = 0
#| let len = self.entries.length()
#| Iter::new(
#| fn() {
#| while i < len {
#| let entry = self.entries.unsafe_get(i)
#| i += 1
#| if entry is Some({ key, value, .. }) {
#| return Some((key, value))
#| }
#| } nobreak {
#| None
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|#alias(iterator2, deprecated)
#|pub fn[K, V] HashMap::iter2(self : HashMap[K, V]) -> Iter2[K, V] {
#| self.iter()
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[K : Hash + Eq, V] HashMap::from_iter(
#| iter : Iter[(K, V)],
#|) -> HashMap[K, V] {
#| let m = new_hashmap(default_init_capacity)
#| while iter.next() is Some((k, v)) {
#| m[k] = v
#| }
#| m
#|}
#|pub fn[K, V] HashMap::to_array(self : HashMap[K, V]) -> Array[(K, V)] {
#| if self.size == 0 {
#| return []
#| }
#| let res = Array::unsafe_make_uninit(self.size)
#| let mut n = 0
#| for i in 0.. Int {
#| self.size
#|}
#|pub fn[K, V] HashMap::capacity(self : HashMap[K, V]) -> Int {
#| self.capacity
#|}
#|pub fn[K, V] HashMap::is_empty(self : HashMap[K, V]) -> Bool {
#| self.size == 0
#|}
#|#locals(f)
#|pub fn[K, V] HashMap::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 fn[K, V] HashMap::keys(self : HashMap[K, V]) -> Iter[K] {
#| let mut i = 0
#| Iter::new(
#| () => {
#| while i < self.entries.length() {
#| let entry = self.entries[i]
#| i += 1
#| if entry is Some({ key, .. }) {
#| break Some(key)
#| }
#| } nobreak {
#| None
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|pub fn[K, V] HashMap::values(self : HashMap[K, V]) -> Iter[V] {
#| let mut i = 0
#| Iter::new(
#| () => {
#| while i < self.entries.length() {
#| let entry = self.entries[i]
#| i += 1
#| if entry is Some({ value, .. }) {
#| break Some(value)
#| }
#| } nobreak {
#| None
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|#locals(f)
#|pub fn[K, V] HashMap::retain(self : HashMap[K, V], f : (K, V) -> Bool) -> Unit {
#| let size = self.size
#| let mut j = 0
#| for i = 0; j < size; i = i + 1 {
#| while self.entries[i] is Some(entry) {
#| j += 1
#| if f(entry.key, entry.value) {
#| break
#| } else {
#| self.shift_back(i)
#| self.size -= 1
#| }
#| }
#| }
#|}
#|test "retain" {
#| let hashmap : HashMap[String, Int] = {
#| capacity: 8,
#| capacity_mask: 7,
#| size: 4,
#| entries: [
#| Some({ psl: 2, hash: 448974246, key: "c", value: 3, }),
#| Some({ psl: 2, hash: -136509641, key: "d", value: 4, }),
#| None,
#| None,
#| None,
#| None,
#| Some({ psl: 0, hash: 1614946358, key: "a", value: 1, }),
#| Some({ psl: 1, hash: -765931946, key: "b", value: 2, }),
#| ],
#| }
#| hashmap.retain((_k, v) => v % 2 == 0)
#| @debug.debug_inspect(
#| hashmap.entries,
#| content=(
#| #|
#| ),
#| )
#|}
),
},
)
///|
let moonbitlang_core_hashset_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/hashset",
deps={},
files={
"debug.mbt": (
#|pub impl[K : @debug.Debug] @debug.Debug for HashSet[K] with fn to_repr(self) {
#| @debug.Repr::opaque_(
#| "HashSet",
#| @debug.Repr::array([ for x in self => Repr(x) ]),
#| )
#|}
#|test "Debug for HashSet" {
#| let hs : HashSet[Int] = from_array([1])
#| @debug.debug_inspect(hs, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `HashSet([], capacity=...)` instead")
#|#as_free_fn(deprecated="Use `HashSet([], capacity=...)` instead")
#|pub fn[K] HashSet::new(capacity? : Int = default_init_capacity) -> HashSet[K] {
#| new_hashset(capacity)
#|}
),
"extends.mbt": (
#|pub extend HashSet with BitAnd::{land}
#|pub extend HashSet with BitOr::{lor}
#|pub extend HashSet with BitXOr::{lxor}
#|pub extend HashSet with Sub::{sub}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashSet with @debug.Debug::{to_repr}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashSet with Default::{default}
#|#deprecated("Use `@debug.Debug` instead of `Show` for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashSet with Show::{output, to_string}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashSet with ToJson::{to_json}
),
"hashset.mbt": (
#|let default_init_capacity = 8
#|fn[K] new_hashset(capacity : Int) -> HashSet[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),
#| }
#|}
#|fn capacity_for_length(length : Int) -> Int {
#| let mut capacity = length.next_power_of_two()
#| if length > calc_grow_threshold(capacity) {
#| capacity *= 2
#| }
#| capacity
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[K : Hash + Eq] HashSet::HashSet(
#| arr : ArrayView[K],
#| capacity? : Int,
#|) -> HashSet[K] {
#| let length = arr.length()
#| let capacity = match capacity {
#| Some(capacity) | (None with capacity = default_init_capacity) =>
#| capacity.max(capacity_for_length(length))
#| }
#| let m = new_hashset(capacity)
#| arr.each(e => m.add(e))
#| m
#|}
#|#alias(insert, deprecated)
#|pub fn[K : Hash + Eq] HashSet::add(self : HashSet[K], key : K) -> Unit {
#| self.add_with_hash(key, Hash::hash(key))
#|}
#|fn[K : Eq] HashSet::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 = hash & self.capacity_mask {
#| match self.entries.unsafe_get(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
#|}
#|#owned(entry)
#|fn[K] HashSet::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.unsafe_get(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
#|#owned(entry)
#|fn[K] HashSet::set_entry(
#| self : HashSet[K],
#| entry : Entry[K],
#| new_idx : Int,
#|) -> Unit {
#| self.entries.unsafe_set(new_idx, Some(entry))
#|}
#|pub fn[K : Hash + Eq] HashSet::contains(self : HashSet[K], key : K) -> Bool {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(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] HashSet::remove(self : HashSet[K], key : K) -> Unit {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(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] HashSet::shift_back(self : HashSet[K], idx : Int) -> Unit {
#| for cur = idx {
#| let next = (cur + 1) & self.capacity_mask
#| match self.entries.unsafe_get(next) {
#| None | Some({ psl: 0, .. }) => {
#| self.entries.unsafe_set(cur, None)
#| break
#| }
#| Some(entry) => {
#| entry.psl -= 1
#| self.set_entry(entry, cur)
#| continue next
#| }
#| }
#| }
#|}
#|fn[K] HashSet::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
#| let new_capacity = self.capacity * 2
#| 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)
#| for entry in old_entries {
#| if entry is Some(entry) {
#| self.rehash_place_entry(entry)
#| }
#| }
#|}
#|#owned(entry)
#|fn[K] HashSet::rehash_place_entry(self : HashSet[K], entry : Entry[K]) -> Unit {
#| let hash = entry.hash
#| for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries.unsafe_get(idx) {
#| None => {
#| entry.psl = psl
#| self.set_entry(entry, idx)
#| return
#| }
#| Some(curr) =>
#| if psl > curr.psl {
#| self.push_away(idx, curr)
#| entry.psl = psl
#| self.set_entry(entry, idx)
#| return
#| } else {
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| }
#| }
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[K : Show] Show for HashSet[K]
#|pub impl[K : Show] Show for HashSet[K] with fn output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@hashset.from_array([", suffix="])")
#|}
#|#alias(size, deprecated)
#|pub fn[K] HashSet::length(self : HashSet[K]) -> Int {
#| self.size
#|}
#|pub fn[K] HashSet::capacity(self : HashSet[K]) -> Int {
#| self.capacity
#|}
#|pub fn[K] HashSet::is_empty(self : HashSet[K]) -> Bool {
#| self.size == 0
#|}
#|#locals(f)
#|pub fn[K] HashSet::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] HashSet::eachi(
#| self : HashSet[K],
#| f : (Int, K) -> Unit raise?,
#|) -> Unit raise? {
#| for i in 0.. Unit {
#| self.entries.fill(None)
#| self.size = 0
#|}
#|#alias(iterator, deprecated)
#|pub fn[K] HashSet::iter(self : HashSet[K]) -> Iter[K] {
#| let mut i = 0
#| let len = self.entries.length()
#| Iter::new(
#| fn() {
#| while i < len {
#| let entry = self.entries.unsafe_get(i)
#| i += 1
#| if entry is Some({ key, .. }) {
#| return Some(key)
#| }
#| } nobreak {
#| None
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|pub fn[K] HashSet::to_array(self : HashSet[K]) -> Array[K] {
#| [
#| for entry in self.entries if entry is Some({ key, .. }) => key
#| ]
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[K : Hash + Eq] HashSet::from_iter(iter : Iter[K]) -> HashSet[K] {
#| let s = new_hashset(default_init_capacity)
#| while iter.next() is Some(e) {
#| s.add(e)
#| }
#| s
#|}
#|pub fn[K : Hash + Eq] HashSet::union(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> HashSet[K] {
#| let m = new_hashset(default_init_capacity)
#| self.each(k => m.add(k))
#| other.each(k => m.add(k))
#| m
#|}
#|pub fn[K : Hash + Eq] HashSet::intersection(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> HashSet[K] {
#| let m = new_hashset(default_init_capacity)
#| self.each(k => if other.contains(k) { m.add(k) })
#| m
#|}
#|pub fn[K : Hash + Eq] HashSet::difference(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> HashSet[K] {
#| let m = new_hashset(default_init_capacity)
#| self.each(k => if !other.contains(k) { m.add(k) })
#| m
#|}
#|pub fn[K : Hash + Eq] HashSet::symmetric_difference(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> HashSet[K] {
#| let m = self.difference(other)
#| other.each(k => if !self.contains(k) { m.add(k) })
#| m
#|}
#|pub fn[K : Hash + Eq] HashSet::is_disjoint(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> Bool {
#| if self.length() <= other.length() {
#| self.iter().all(k => !other.contains(k))
#| } else {
#| other.iter().all(k => !self.contains(k))
#| }
#|}
#|pub fn[K : Hash + Eq] HashSet::is_subset(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> Bool {
#| if self.length() <= other.length() {
#| self.iter().all(k => other.contains(k))
#| } else {
#| false
#| }
#|}
#|pub fn[K : Hash + Eq] HashSet::is_superset(
#| self : HashSet[K],
#| other : HashSet[K],
#|) -> Bool {
#| other.is_subset(self)
#|}
#|pub impl[K : Hash + Eq] BitAnd for HashSet[K] with fn land(self, other) {
#| self.intersection(other)
#|}
#|pub impl[K : Hash + Eq] BitOr for HashSet[K] with fn lor(self, other) {
#| self.union(other)
#|}
#|pub impl[K : Hash + Eq] BitXOr for HashSet[K] with fn lxor(self, other) {
#| self.symmetric_difference(other)
#|}
#|pub impl[K : Hash + Eq] Sub for HashSet[K] with fn sub(self, other) {
#| self.difference(other)
#|}
#|#locals(f)
#|pub fn[K] HashSet::retain(self : HashSet[K], f : (K) -> Bool) -> Unit {
#| let size = self.size
#| let mut j = 0
#| for i = 0; j < size; i = i + 1 {
#| while self.entries[i] is Some(entry) {
#| j += 1
#| if f(entry.key) {
#| break
#| } else {
#| self.shift_back(i)
#| self.size -= 1
#| }
#| }
#| }
#|}
#|fn calc_grow_threshold(capacity : Int) -> Int {
#| capacity * 13 / 16
#|}
#|fn[K : Show] HashSet::_debug_entries(self : HashSet[K]) -> String {
#| for i in 0.. 0 { s + "," } else { s }
#| continue match self.entries[i] {
#| None => s + "_"
#| Some({ psl, key, .. }) => s + "(\{psl},\{key})"
#| }
#| } nobreak {
#| s
#| }
#|}
#|priv struct MyString(String) derive(Eq, @debug.Debug)
#|impl Hash for MyString with fn hash(self) {
#| let MyString(self) = self
#| self.length()
#|}
#|impl Hash for MyString with fn hash_combine(self, hasher) {
#| let MyString(self) = self
#| hasher.combine_string(self)
#|}
#|test "set" {
#| let m : HashSet[MyString] = new_hashset(default_init_capacity)
#| 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")
#|}
#|test "remove" {
#| let m : HashSet[MyString] = new_hashset(default_init_capacity)
#| 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.length(), content="5")
#|}
#|test "remove_unexist_key" {
#| let m : HashSet[MyString] = new_hashset(default_init_capacity)
#| fn i(s) {
#| MyString::MyString(s)
#| }
#| m.add("a" |> i)
#| m.add("ab" |> i)
#| m.add("abc" |> i)
#| m.remove("d" |> i)
#| inspect(m.length(), content="3")
#|}
#|test "grow" {
#| let m : HashSet[MyString] = new_hashset(default_init_capacity)
#| 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")
#|}
#|test "clear" {
#| let m : HashSet[MyString] = new_hashset(default_init_capacity)
#| m.clear()
#| inspect(m.length(), content="0")
#| inspect(m.capacity(), content="8")
#| for entry in m.entries {
#| @test.assert_same_object(entry, None)
#| }
#|}
#|pub fn[K : Hash + Eq] HashSet::add_and_check(
#| self : HashSet[K],
#| key : K,
#|) -> Bool {
#| let old_size = self.length()
#| self.add(key)
#| self.length() > old_size
#|}
#|pub fn[K : Hash + Eq] HashSet::remove_and_check(
#| self : HashSet[K],
#| key : K,
#|) -> Bool {
#| let old_size = self.size
#| self.remove(key)
#| self.size < old_size
#|}
#|#alias(clone, deprecated)
#|pub fn[K] HashSet::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.. key
#| ]
#|}
#|pub impl[K] Default for HashSet[K] with fn default() {
#| new_hashset(default_init_capacity)
#|}
),
"types.mbt": (
#|priv struct Entry[K] {
#| mut psl : Int
#| hash : Int
#| key : K
#|} derive(@debug.Debug)
#|struct HashSet[K] {
#| mut entries : FixedArray[Entry[K]?]
#| mut size : Int // active key 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
#|}
),
},
)
///|
let moonbitlang_core_immut_hashmap_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/hashmap",
deps={},
files={
"HAMT.mbt": (
#|priv enum CurrNode[K, V] {
#| Tree(Node[K, V])
#| Bucket(@list.List[(K, V)])
#|}
#|priv struct BuildEntry[K, V] {
#| key : K
#| value : V
#| path : @path.Path // Full path; bulk construction tracks consumed segments by depth.
#|}
#|let bulk_build_threshold = 64
#|#as_free_fn
#|pub fn[K, V] HashMap::new() -> HashMap[K, V] {
#| { data: None, }
#|}
#|#as_free_fn
#|#owned(key, value)
#|pub fn[K : Hash, V] HashMap::singleton(key : K, value : V) -> HashMap[K, V] {
#| { data: Some(Flat(key, value, @path.of(key))), }
#|}
#|pub fn[K : Eq + Hash, V] HashMap::contains(
#| self : HashMap[K, V],
#| key : K,
#|) -> Bool {
#| self.get(key) is Some(_)
#|}
#|#alias(find, deprecated)
#|pub fn[K : Eq + Hash, V] HashMap::get(self : HashMap[K, V], key : K) -> V? {
#| match self.data {
#| None => None
#| Some(node) => node.get_with_path(key, @path.of(key))
#| }
#|}
#|#alias("_[_]")
#|pub fn[K : Eq + Hash, V] HashMap::at(self : HashMap[K, V], key : K) -> V {
#| guard! self.data is Some(node)
#| node.get_with_path(key, @path.of(key)).unwrap()
#|}
#|fn[K : Eq, V] Node::get_with_path(
#| self : Node[K, V],
#| key : K,
#| path : @path.Path,
#|) -> V? {
#| for node = self, path = path {
#| match (node, path) {
#| (Leaf(key1, value1, bucket), _) =>
#| break if key == key1 { Some(value1) } else { bucket.lookup(key) }
#| (Flat(key1, value1, path1), path) =>
#| break if path == path1 && key == key1 { Some(value1) } else { None }
#| (Branch(children), path) => {
#| let idx = path.idx()
#| if children.get(idx) is Some(child) {
#| continue child, path.next()
#| }
#| break None
#| }
#| }
#| }
#|}
#|#owned(key1, value1, key2, value2)
#|fn[K, V] join_2(
#| key1 : K,
#| value1 : V,
#| path1 : @path.Path,
#| key2 : K,
#| value2 : V,
#| path2 : @path.Path,
#|) -> Node[K, V] {
#| if path1 == @path.exhausted {
#| return Leaf(key2, value2, @list.singleton((key1, value1)))
#| }
#| let idx1 = path1.idx()
#| let idx2 = path2.idx()
#| if idx1 == idx2 {
#| let node = join_2(key1, value1, path1.next(), key2, value2, path2.next())
#| Branch(@sparse_array.singleton(idx1, node))
#| } else {
#| let node1 = Flat(key1, value1, path1.next())
#| let node2 = Flat(key2, value2, path2.next())
#| Branch(@sparse_array.doubleton(idx1, node1, idx2, node2))
#| }
#|}
#|#owned(value)
#|fn[K : Eq, V] Node::add_with_path(
#| self : Node[K, V],
#| key : K,
#| value : V,
#| path : @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.get(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))
#| }
#| }
#| }
#| }
#|}
#|fn[K : Eq, V] BuildEntry::add_to_node(
#| self : BuildEntry[K, V],
#| node : Node[K, V]?,
#| depth : Int,
#|) -> Node[K, V] {
#| let path = self.path.advance(depth)
#| match node {
#| None => Flat(self.key, self.value, path)
#| Some(node) => node.add_with_path(self.key, self.value, path)
#| }
#|}
#|fn[K : Eq, V] build_hashmap_node_by_add(
#| entries : Array[BuildEntry[K, V]],
#| start : Int,
#| end : Int,
#| depth : Int,
#| reverse : Bool,
#|) -> Node[K, V] {
#| if reverse {
#| for i = end, node = (None : Node[K, V]?) {
#| if i == start {
#| break node.unwrap()
#| }
#| let node = entries[i - 1].add_to_node(node, depth)
#| continue i - 1, Some(node)
#| }
#| } else {
#| for i = start, node = (None : Node[K, V]?) {
#| if i == end {
#| break node.unwrap()
#| }
#| let node = entries[i].add_to_node(node, depth)
#| continue i + 1, Some(node)
#| }
#| }
#|}
#|fn[K : Eq, V] build_hashmap_node_range(
#| entries : Array[BuildEntry[K, V]],
#| start : Int,
#| end : Int,
#| depth : Int,
#| reverse : Bool,
#|) -> Node[K, V] {
#| if end - start == 1 {
#| let entry = entries[start]
#| return Flat(entry.key, entry.value, entry.path.advance(depth))
#| }
#| if depth == 5 {
#| return build_hashmap_node_by_add(entries, start, end, depth, reverse)
#| }
#| let starts = FixedArray::make(32, 0)
#| for i in start.. Flat(key, value, path.push(first_idx))
#| _ => Branch(@sparse_array.singleton(first_idx, first_child))
#| }
#| }
#| let indices = FixedArray::make(child_count, first_idx)
#| let children = FixedArray::make(child_count, first_child)
#| for idx = first_idx + 1, out = 1; idx < 32; {
#| if nexts[idx] == starts[idx] {
#| continue idx + 1, out
#| }
#| indices[out] = idx
#| children[out] = build_hashmap_node_range(
#| partitioned,
#| starts[idx],
#| nexts[idx],
#| depth + 1,
#| reverse,
#| )
#| continue idx + 1, out + 1
#| }
#| Branch(@sparse_array.from_sorted_fixed_array(indices, children))
#|}
#|fn[K : Eq + Hash, V] hash_map_from_iter_by_add(
#| iter : Iter[(K, V)],
#|) -> HashMap[K, V] {
#| iter.fold(init=new(), (m, e) => m.add(e.0, e.1))
#|}
#|fn[K : Eq + Hash, V] hash_map_from_array_by_add(
#| arr : ArrayView[(K, V)],
#|) -> HashMap[K, V] {
#| for n = arr.length(), map = new() {
#| match (n, map) {
#| (0, map) => break map
#| (n, map) => {
#| let (k, v) = arr[n - 1]
#| continue n - 1, map.add(k, v)
#| }
#| }
#| }
#|}
#|fn[K : Eq + Hash, V] hash_map_from_array(
#| arr : ArrayView[(K, V)],
#|) -> HashMap[K, V] {
#| if arr.length() <= bulk_build_threshold {
#| return hash_map_from_array_by_add(arr)
#| }
#| let entries = Array::makei(arr.length(), i => {
#| let kv = arr[i]
#| let (k, v) = kv
#| { key: k, value: v, path: @path.of(k), }
#| })
#| {
#| data: Some(build_hashmap_node_range(entries, 0, entries.length(), 0, true)),
#| }
#|}
#|#alias(filter_with_key, deprecated)
#|pub fn[K, V] HashMap::filter(
#| 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) {
#| match new_bucket {
#| Empty => Some(Flat(key1, value1, @path.exhausted))
#| _ => Some(Leaf(key1, value1, new_bucket))
#| }
#| } else {
#| match new_bucket {
#| Empty => None
#| More((k1, v1), tail=Empty) => Some(Flat(k1, v1, @path.exhausted))
#| 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(collapse_branch(new_children))
#| }
#| }
#| }
#| {
#| data: match self.data {
#| None => None
#| Some(node) => go(node)
#| },
#| }
#|}
#|#alias(fold_with_key, deprecated)
#|pub fn[K, V, A] HashMap::fold(
#| 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.data {
#| None => init
#| Some(node) => go(init, node)
#| }
#|}
#|#alias(map_with_key, deprecated)
#|pub fn[K, V, A] HashMap::map(
#| 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))
#| }
#| }
#| {
#| data: match self.data {
#| None => None
#| Some(node) => Some(go(node))
#| },
#| }
#|}
#|#owned(value)
#|pub fn[K : Eq + Hash, V] HashMap::add(
#| self : HashMap[K, V],
#| key : K,
#| value : V,
#|) -> HashMap[K, V] {
#| {
#| data: match self.data {
#| None => Some(Flat(key, value, @path.of(key)))
#| Some(node) => Some(node.add_with_path(key, value, @path.of(key)))
#| },
#| }
#|}
#|fn[K, V] collapse_branch(
#| children : @sparse_array.SparseArray[Node[K, V]],
#|) -> Node[K, V] {
#| match children.data {
#| [Flat(key, value, path)] =>
#| Flat(key, value, path.push(children.elem_info.first_idx()))
#| _ => Branch(children)
#| }
#|}
#|pub fn[K : Eq + Hash, V] HashMap::remove(
#| self : HashMap[K, V],
#| key : K,
#|) -> HashMap[K, V] {
#| {
#| data: match self.data {
#| None => None
#| Some(node) => node.remove_with_path(key, @path.of(key))
#| },
#| }
#|}
#|fn[K : Eq, V] Node::remove_with_path(
#| self : Node[K, V],
#| key : K,
#| path : @path.Path,
#|) -> Node[K, V]? {
#| match self {
#| Leaf(key1, value1, bucket) =>
#| if key1 == key {
#| match bucket {
#| Empty => None
#| More((key2, value2), tail=Empty) => Some(Flat(key2, value2, path))
#| More((key2, value2), tail~) => Some(Leaf(key2, value2, tail))
#| }
#| } else if bucket.find_index(kv => kv.0 == key) is Some(index) {
#| match bucket.remove_at(index) {
#| Empty => Some(Flat(key1, value1, path))
#| new_bucket => Some(Leaf(key1, value1, new_bucket))
#| }
#| } else {
#| Some(self)
#| }
#| Flat(key1, _, path1) =>
#| if path == path1 && key == key1 {
#| None
#| } else {
#| Some(self)
#| }
#| Branch(children) => {
#| let idx = path.idx()
#| match children.get(idx) {
#| None => Some(self)
#| Some(child) => {
#| let new_child = child.remove_with_path(key, path.next())
#| let new_children = match (children.length(), new_child) {
#| (1, None) => return None
#| (_, None) => children.remove(idx)
#| (_, Some(new_child)) => children.replace(idx, new_child)
#| }
#| Some(collapse_branch(new_children))
#| }
#| }
#| }
#| }
#|}
#|#alias(size, deprecated)
#|pub fn[K, V] HashMap::length(self : HashMap[K, V]) -> Int {
#| fn node_size(node) {
#| match node {
#| Leaf(_, _, bucket) => 1 + bucket.length()
#| Flat(_) => 1
#| Branch(children) =>
#| for child in children.data; total_size = 0 {
#| continue total_size + node_size(child)
#| } nobreak {
#| total_size
#| }
#| }
#| }
#| match self.data {
#| None => 0
#| Some(node) => node_size(node)
#| }
#|}
#|#alias(merge)
#|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")
#| }
#| }
#| {
#| data: match (self.data, other.data) {
#| (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")
#| }
#| }
#| {
#| data: match (self.data, other.data) {
#| (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
#| }
#| } nobreak {
#| res.push(kv2)
#| }
#| }
#| guard! @list.List(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(children) => Some(collapse_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=Empty) => Some(Flat(head.0, head.1, @path.exhausted))
#| More(head, tail~) => Some(Leaf(head.0, head.1, tail))
#| }
#| }
#| _ => abort("Unreachable")
#| }
#| }
#| {
#| data: match (self.data, other.data) {
#| (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(children) => Some(collapse_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")
#| }
#| }
#| {
#| data: match (self.data, other.data) {
#| (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.List(res) {
#| Empty => None
#| More((k, v), tail=Empty) => Some(Flat(k, v, @path.exhausted))
#| 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(children) => Some(collapse_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 => !(kvs2.lookup(kv.0) is Some(_))) {
#| Empty => None
#| More(head, tail=Empty) => Some(Flat(head.0, head.1, @path.exhausted))
#| More(head, tail~) => Some(Leaf(head.0, head.1, tail))
#| }
#| }
#| _ => abort("Unreachable")
#| }
#| }
#| match (self.data, other.data) {
#| (None, _) => { data: None, }
#| (_, None) => self
#| (Some(a), Some(b)) => { data: go(a, b), }
#| }
#|}
#|pub fn[K, V] HashMap::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)
#| }
#| }
#| if self.data is Some(node) {
#| go(node)
#| }
#|}
#|pub fn[K, V] HashMap::keys(self : HashMap[K, V]) -> Iter[K] {
#| self.iter().map(p => p.0)
#|}
#|#alias(elems, deprecated="Use `values` instead")
#|pub fn[K, V] HashMap::values(self : HashMap[K, V]) -> Iter[V] {
#| self.iter().map(p => p.1)
#|}
#|#alias(iterator, deprecated)
#|pub fn[K, V] HashMap::iter(self : HashMap[K, V]) -> Iter[(K, V)] {
#| let empty = Bucket(@list.new())
#| let mut curr_node = match self.data {
#| Some(tree) => Tree(tree)
#| None => empty
#| }
#| let mut curr_index = 0
#| let parents = []
#| Iter::new(fn() {
#| for cn = curr_node {
#| match cn {
#| Tree(Flat(k, v, _)) => {
#| curr_node = empty
#| break Some((k, v))
#| }
#| Tree(Leaf(k, v, bucket)) => {
#| curr_node = Bucket(bucket)
#| break Some((k, v))
#| }
#| Bucket(More(pair, tail~)) => {
#| curr_node = Bucket(tail)
#| break Some(pair)
#| }
#| Tree(Branch(children)) as n if curr_index < children.length() => {
#| let child = children.data[curr_index]
#| parents.push((n, curr_index + 1))
#| curr_index = 0
#| continue Tree(child)
#| }
#| Bucket(Empty) | Tree(Branch(_)) if parents.pop()
#| is Some((parent, parent_index)) => {
#| curr_node = parent
#| curr_index = parent_index
#| continue parent
#| }
#| Bucket(Empty) | Tree(Branch(_)) => break None
#| }
#| }
#| })
#|}
#|#alias(iterator2, deprecated)
#|pub fn[K, V] HashMap::iter2(self : HashMap[K, V]) -> Iter2[K, V] {
#| self.iter()
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[K : Eq + Hash, V] HashMap::from_iter(
#| iter : Iter[(K, V)],
#|) -> HashMap[K, V] {
#| if iter.size_hint() is Some(len) && len <= bulk_build_threshold {
#| return hash_map_from_iter_by_add(iter)
#| }
#| let entries = match iter.size_hint() {
#| Some(len) => Array(capacity=len)
#| None => []
#| }
#| iter.each(e => entries.push({ key: e.0, value: e.1, path: @path.of(e.0), }))
#| if entries.is_empty() {
#| new()
#| } else {
#| {
#| data: Some(
#| build_hashmap_node_range(entries, 0, entries.length(), 0, false),
#| ),
#| }
#| }
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[K : Show, V : Show] Show for HashMap[K, V]
#|#warnings("-deprecated")
#|pub impl[K : Show, V : Show] Show for HashMap[K, V] with fn output(self, logger) {
#| logger.write_iter(
#| self.iter(),
#| prefix="@immut/hashmap.from_array([",
#| suffix="])",
#| )
#|}
#|#as_free_fn(deprecated="Use @immut/hashmap.HashMap([...]) instead")
#|#alias(of, deprecated="Use @immut/hashmap.HashMap([...]) instead")
#|#as_free_fn(of, deprecated="Use @immut/hashmap.HashMap([...]) instead")
#|#deprecated("Use @immut/hashmap.HashMap([...]) instead")
#|pub fn[K : Eq + Hash, V] HashMap::from_array(
#| arr : ArrayView[(K, V)],
#|) -> HashMap[K, V] {
#| hash_map_from_array(arr)
#|}
#|pub fn[K : Eq + Hash, V] HashMap::HashMap(
#| arr : ArrayView[(K, V)],
#|) -> HashMap[K, V] {
#| hash_map_from_array(arr)
#|}
#|pub fn[K, V] HashMap::to_array(self : HashMap[K, V]) -> Array[(K, V)] {
#| [
#| for k, v in self => (k, v)
#| ]
#|}
#|impl[K : Eq, V : Eq] Eq for Node[K, V] with fn equal(self, other) {
#| if physical_equal(self, other) {
#| return true
#| }
#| 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 fn hash_combine(
#| self,
#| hasher,
#|) {
#| hasher.combine(
#| self.fold(init=0, (acc, k, v) => {
#| let h = Hasher()
#| h.combine((k, v))
#| acc ^ h.finalize()
#| }),
#| )
#|}
),
"debug.mbt": (
#|pub impl[K : @debug.Debug, V : @debug.Debug] @debug.Debug for HashMap[K, V] with fn to_repr(
#| self,
#|) {
#| @debug.Repr::opaque_(
#| "HashMap",
#| @debug.Repr::map([ for k, v in self => (Repr(k), Repr(v)) ]),
#| )
#|}
#|test "Debug for HashMap" {
#| let hm : HashMap[Int, String] = HashMap([(2, "b")])
#| @debug.debug_inspect(
#| hm,
#| content=(
#| #|
#| ),
#| )
#|}
),
"deprecated.mbt": "",
"extends.mbt": (
#|pub extend HashMap with Eq::{equal}
#|pub extend HashMap with Hash::{hash}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashMap with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashMap with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashMap with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashMap with Show::{output, to_string}
),
"types.mbt": (
#|#unsafe_cycle_free
#|priv enum Node[K, V] {
#| Flat(K, V, @path.Path)
#| Leaf(K, V, @list.List[(K, V)])
#| Branch(@sparse_array.SparseArray[Node[K, V]])
#|}
#|#valtype
#|struct HashMap[K, V] {
#| data : Node[K, V]?
#|} derive(Eq)
),
},
)
///|
let moonbitlang_core_immut_hashset_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/hashset",
deps={},
files={
"HAMT.mbt": (
#|priv struct BuildEntry[A] {
#| value : A
#| path : @path.Path // Full path; bulk construction tracks consumed segments by depth.
#|}
#|let bulk_build_threshold = 64
#|#as_free_fn
#|pub fn[A] HashSet::new() -> HashSet[A] {
#| { data: None, }
#|}
#|pub fn[A : Eq + Hash] HashSet::contains(self : HashSet[A], key : A) -> Bool {
#| self.data is Some(node) && node.contains(key, @path.of(key))
#|}
#|fn[A : Eq] Node::contains(self : Node[A], key : A, path : @path.Path) -> Bool {
#| for s = self, p = path {
#| match (s, p) {
#| (Leaf(key1, bucket), _) => break key == key1 || bucket.contains(key)
#| (Flat(key1, path1), path) => break path == path1 && key == key1
#| (Branch(children), path) => {
#| let idx = path.idx()
#| if children.get(idx) is Some(child) {
#| continue child, path.next()
#| }
#| break false
#| }
#| }
#| }
#|}
#|#owned(key1, key2)
#|fn[A] join_2(
#| key1 : A,
#| path1 : @path.Path,
#| key2 : A,
#| path2 : @path.Path,
#|) -> Node[A] {
#| if path1 == @path.exhausted {
#| return Leaf(key2, @list.singleton(key1))
#| }
#| let idx1 = path1.idx()
#| let idx2 = path2.idx()
#| if idx1 == idx2 {
#| let node = join_2(key1, path1.next(), key2, path2.next())
#| Branch(@sparse_array.singleton(idx1, node))
#| } else {
#| let node1 = Flat(key1, path1.next())
#| let node2 = Flat(key2, path2.next())
#| Branch(@sparse_array.doubleton(idx1, node1, idx2, node2))
#| }
#|}
#|fn[A : Eq] Node::add_with_path(
#| self : Node[A],
#| key : A,
#| path : @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.get(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))
#| }
#| }
#| }
#| }
#|}
#|fn[A : Eq] BuildEntry::add_to_node(
#| self : BuildEntry[A],
#| node : Node[A]?,
#| depth : Int,
#|) -> Node[A] {
#| let path = self.path.advance(depth)
#| match node {
#| None => Flat(self.value, path)
#| Some(node) => node.add_with_path(self.value, path)
#| }
#|}
#|fn[A : Eq] build_hashset_node_by_add(
#| entries : Array[BuildEntry[A]],
#| start : Int,
#| end : Int,
#| depth : Int,
#| reverse : Bool,
#|) -> Node[A] {
#| if reverse {
#| for i = end, node = (None : Node[A]?) {
#| if i == start {
#| break node.unwrap()
#| }
#| let node = entries[i - 1].add_to_node(node, depth)
#| continue i - 1, Some(node)
#| }
#| } else {
#| for i = start, node = (None : Node[A]?) {
#| if i == end {
#| break node.unwrap()
#| }
#| let node = entries[i].add_to_node(node, depth)
#| continue i + 1, Some(node)
#| }
#| }
#|}
#|fn[A : Eq] build_hashset_node_range(
#| entries : Array[BuildEntry[A]],
#| start : Int,
#| end : Int,
#| depth : Int,
#| reverse : Bool,
#|) -> Node[A] {
#| if end - start == 1 {
#| let entry = entries[start]
#| return Flat(entry.value, entry.path.advance(depth))
#| }
#| if depth == 5 {
#| return build_hashset_node_by_add(entries, start, end, depth, reverse)
#| }
#| let starts = FixedArray::make(32, 0)
#| for i in start.. Flat(value, path.push(first_idx))
#| _ => Branch(@sparse_array.singleton(first_idx, first_child))
#| }
#| }
#| let indices = FixedArray::make(child_count, first_idx)
#| let children = FixedArray::make(child_count, first_child)
#| for idx = first_idx + 1, out = 1; idx < 32; {
#| if nexts[idx] == starts[idx] {
#| continue idx + 1, out
#| }
#| indices[out] = idx
#| children[out] = build_hashset_node_range(
#| partitioned,
#| starts[idx],
#| nexts[idx],
#| depth + 1,
#| reverse,
#| )
#| continue idx + 1, out + 1
#| }
#| Branch(@sparse_array.from_sorted_fixed_array(indices, children))
#|}
#|fn[A : Eq + Hash] hash_set_from_iter_by_add(iter : Iter[A]) -> HashSet[A] {
#| iter.fold(init=new(), (s, e) => s.add(e))
#|}
#|fn[A : Eq + Hash] hash_set_from_array_by_add(arr : ArrayView[A]) -> HashSet[A] {
#| for n = arr.length(), set = new() {
#| match (n, set) {
#| (0, set) => break set
#| (n, set) => {
#| let k = arr[n - 1]
#| continue n - 1, set.add(k)
#| }
#| }
#| }
#|}
#|fn[A : Eq + Hash] hash_set_from_array(arr : ArrayView[A]) -> HashSet[A] {
#| if arr.length() <= bulk_build_threshold {
#| return hash_set_from_array_by_add(arr)
#| }
#| let entries = Array::makei(arr.length(), i => {
#| let value = arr[i]
#| { value, path: @path.of(value), }
#| })
#| {
#| data: Some(build_hashset_node_range(entries, 0, entries.length(), 0, true)),
#| }
#|}
#|pub fn[A : Eq + Hash] HashSet::add(self : HashSet[A], key : A) -> HashSet[A] {
#| {
#| data: match self.data {
#| None => Some(Flat(key, @path.of(key)))
#| Some(node) => Some(node.add_with_path(key, @path.of(key)))
#| },
#| }
#|}
#|pub fn[A : Eq + Hash] HashSet::remove(self : HashSet[A], key : A) -> HashSet[A] {
#| {
#| data: match self.data {
#| None => None
#| Some(node) => node.remove_with_path(key, @path.of(key))
#| },
#| }
#|}
#|fn[A] collapse_branch(children : @sparse_array.SparseArray[Node[A]]) -> Node[A] {
#| match children.data {
#| [Flat(key, path)] => Flat(key, path.push(children.elem_info.first_idx()))
#| _ => Branch(children)
#| }
#|}
#|fn[A : Eq] Node::remove_with_path(
#| self : Node[A],
#| key : A,
#| path : @path.Path,
#|) -> Node[A]? {
#| match self {
#| Leaf(key1, bucket) =>
#| if key1 == key {
#| match bucket {
#| Empty => None
#| More(key2, tail=Empty) => Some(Flat(key2, path))
#| More(key2, tail=xs) => Some(Leaf(key2, xs))
#| }
#| } else if bucket.find_index(x => key.equal(x)) is Some(index) {
#| match bucket.remove_at(index) {
#| Empty => Some(Flat(key1, path))
#| new_bucket => Some(Leaf(key1, new_bucket))
#| }
#| } else {
#| Some(self)
#| }
#| Flat(key1, path1) =>
#| if path == path1 && key == key1 {
#| None
#| } else {
#| Some(self)
#| }
#| Branch(children) => {
#| let idx = path.idx()
#| match children.get(idx) {
#| None => Some(self)
#| Some(child) => {
#| let new_child = child.remove_with_path(key, path.next())
#| let new_children = match (children.length(), new_child) {
#| (1, None) => return None
#| (_, None) => children.remove(idx)
#| (_, Some(new_child)) => children.replace(idx, new_child)
#| }
#| Some(collapse_branch(new_children))
#| }
#| }
#| }
#| }
#|}
#|#alias(size, deprecated)
#|pub fn[A] HashSet::length(self : HashSet[A]) -> Int {
#| fn node_size(node) {
#| match node {
#| Leaf(_, bucket) => 1 + bucket.length()
#| Flat(_) => 1
#| Branch(children) =>
#| for child in children.data; total_size = 0 {
#| continue total_size + node_size(child)
#| } nobreak {
#| total_size
#| }
#| }
#| }
#| match self.data {
#| 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")
#| }
#| }
#| {
#| data: match (self.data, other.data) {
#| (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(children) => Some(collapse_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=Empty) => Some(Flat(head, @path.exhausted))
#| More(head, tail~) => Some(Leaf(head, tail))
#| }
#| }
#| _ => abort("Unreachable")
#| }
#| }
#| {
#| data: match (self.data, other.data) {
#| (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(children) => Some(collapse_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=Empty) => Some(Flat(head, @path.exhausted))
#| More(head, tail~) => Some(Leaf(head, tail))
#| }
#| }
#| _ => abort("Unreachable")
#| }
#| }
#| match (self.data, other.data) {
#| (None, _) => { data: None, }
#| (_, None) => self
#| (Some(a), Some(b)) => { data: go(a, b), }
#| }
#|}
#|pub fn[A] HashSet::is_empty(self : HashSet[A]) -> Bool {
#| self.data is None
#|}
#|pub fn[A] HashSet::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)
#| }
#| }
#| if self.data is Some(node) {
#| go(node)
#| }
#|}
#|priv enum CurrNode[A] {
#| Tree(Node[A])
#| Bucket(@list.List[A])
#|}
#|#alias(iterator, deprecated)
#|pub fn[A] HashSet::iter(self : HashSet[A]) -> Iter[A] {
#| let empty = Bucket(@list.new())
#| let mut curr_node = match self.data {
#| Some(tree) => Tree(tree)
#| None => empty
#| }
#| let mut curr_index = 0
#| let parents = []
#| Iter::new(fn() {
#| for cn = curr_node {
#| match cn {
#| Tree(Flat(x, _)) => {
#| curr_node = empty
#| break Some(x)
#| }
#| Tree(Leaf(x, bucket)) => {
#| curr_node = Bucket(bucket)
#| break Some(x)
#| }
#| Bucket(More(x, tail~)) => {
#| curr_node = Bucket(tail)
#| break Some(x)
#| }
#| Tree(Branch(children)) as n if curr_index < children.length() => {
#| let child = children.data[curr_index]
#| parents.push((n, curr_index + 1))
#| curr_index = 0
#| continue Tree(child)
#| }
#| Bucket(Empty) | Tree(Branch(_)) if parents.pop()
#| is Some((parent, parent_index)) => {
#| curr_node = parent
#| curr_index = parent_index
#| continue parent
#| }
#| Bucket(Empty) | Tree(Branch(_)) => break None
#| }
#| }
#| })
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[A : Eq + Hash] HashSet::from_iter(iter : Iter[A]) -> HashSet[A] {
#| if iter.size_hint() is Some(len) && len <= bulk_build_threshold {
#| return hash_set_from_iter_by_add(iter)
#| }
#| let entries = match iter.size_hint() {
#| Some(len) => Array(capacity=len)
#| None => []
#| }
#| iter.each(value => entries.push({ value, path: @path.of(value), }))
#| if entries.is_empty() {
#| new()
#| } else {
#| {
#| data: Some(
#| build_hashset_node_range(entries, 0, entries.length(), 0, false),
#| ),
#| }
#| }
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for HashSet[A]
#|pub impl[A : Show] Show for HashSet[A] with fn output(self, logger) {
#| logger.write_iter(
#| self.iter(),
#| prefix="@immut/hashset.from_array([",
#| suffix="])",
#| )
#|}
#|#as_free_fn(deprecated="Use @immut/hashset.HashSet([...]) instead")
#|#alias(of, deprecated="Use @immut/hashset.HashSet([...]) instead")
#|#as_free_fn(of, deprecated="Use @immut/hashset.HashSet([...]) instead")
#|#deprecated("Use @immut/hashset.HashSet([...]) instead")
#|pub fn[A : Eq + Hash] HashSet::from_array(arr : ArrayView[A]) -> HashSet[A] {
#| hash_set_from_array(arr)
#|}
#|pub fn[A : Eq + Hash] HashSet::HashSet(arr : ArrayView[A]) -> HashSet[A] {
#| hash_set_from_array(arr)
#|}
#|pub impl[A : Hash] Hash for HashSet[A] with fn hash_combine(self, hasher) {
#| hasher.combine(self.iter().fold(init=0, (x, y) => x ^ y.hash()))
#|}
#|impl[A : Eq] Eq for Node[A] with fn equal(self, other) {
#| if physical_equal(self, other) {
#| return true
#| }
#| 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(k => keys2.contains(k))
#| })
#| (Flat(x, pathx), Flat(y, pathy)) => pathx == pathy && x == y
#| (Branch(xs), Branch(ys)) => xs == ys
#| _ => false
#| }
#|}
#|test "hash" {
#| @test.assert_eq(
#| Hash::hash(HashSet([1, 2, 3, 4])),
#| Hash::hash(HashSet([3, 2]).add(1).add(4)),
#| )
#| @test.assert_not_eq(
#| Hash::hash(HashSet([1, 2, 3])),
#| Hash::hash(HashSet([1, 2, 4])),
#| )
#|}
#|test "eq" {
#| @test.assert_eq(HashSet([1, 2, 3, 4]), HashSet([3, 2]).add(1).add(4))
#| @test.assert_not_eq(HashSet([1, 2, 3]), HashSet([1, 2, 4]))
#|}
),
"debug.mbt": (
#|pub impl[K : @debug.Debug] @debug.Debug for HashSet[K] with fn to_repr(self) {
#| @debug.Repr::opaque_(
#| "HashSet",
#| @debug.Repr::array([ for x in self => Repr(x) ]),
#| )
#|}
#|test "Debug for HashSet" {
#| let hs : HashSet[Int] = HashSet([3])
#| @debug.debug_inspect(hs, content="")
#|}
),
"deprecated.mbt": "",
"extends.mbt": (
#|pub extend HashSet with Eq::{equal}
#|pub extend HashSet with Hash::{hash}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashSet with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashSet with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashSet with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend HashSet with Show::{output, to_string}
),
"types.mbt": (
#|#unsafe_cycle_free
#|priv enum Node[A] {
#| Flat(A, @path.Path)
#| Leaf(A, @list.List[A])
#| Branch(@sparse_array.SparseArray[Node[A]])
#|}
#|#valtype
#|struct HashSet[A] {
#| data : Node[A]?
#|} derive(Eq)
),
},
)
///|
let moonbitlang_core_immut_internal_path_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/internal/path",
deps={},
files={
"extends.mbt": (
#|pub extend Path with Eq::{equal}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Path with Eq::{not_equal}
),
"path.mbt": (
#|pub 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::idx_at(self : Path, depth : Int) -> Int {
#| let Path(self) = self
#| ((self >> (SEGMENT_LENGTH * depth)) & INDEX_MASK).reinterpret_as_int()
#|}
#|pub fn Path::next(self : Path) -> Path {
#| let Path(self) = self
#| self >> SEGMENT_LENGTH
#|}
#|pub fn Path::advance(self : Path, depth : Int) -> Path {
#| let Path(self) = self
#| self >> (SEGMENT_LENGTH * depth)
#|}
#|pub let exhausted : Path = Path(HEAD_TAG >> (SEGMENT_LENGTH * SEGMENT_NUM))
),
},
)
///|
let moonbitlang_core_immut_internal_sparse_array_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/internal/sparse_array",
deps={},
files={
"bitset.mbt": (
#|pub struct Bitset(UInt) derive(Eq)
#|let empty_bitset : Bitset = Bitset(0)
#|fn Bitset::has(self : Bitset, idx : Int) -> Bool {
#| (self.0 & (1U << idx)) != 0
#|}
#|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()
#|}
#|fn Bitset::union(self : Bitset, other : Bitset) -> Bitset {
#| Bitset(self.0 | other.0)
#|}
#|fn Bitset::intersection(self : Bitset, other : Bitset) -> Bitset {
#| Bitset(self.0 & other.0)
#|}
#|fn Bitset::add(self : Bitset, idx : Int) -> Bitset {
#| Bitset(self.0 | (1U << idx))
#|}
#|fn Bitset::remove(self : Bitset, idx : Int) -> Bitset {
#| Bitset(self.0 ^ (1U << idx))
#|}
#|#alias(size, deprecated)
#|fn Bitset::length(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::size" {
#| let b = empty_bitset
#| inspect(b.length(), content="0")
#| let b = b.add(0)
#| inspect(b.length(), content="1")
#| let b = b.add(1)
#| inspect(b.length(), content="2")
#| let b = b.add(1)
#| inspect(b.length(), content="2")
#|}
#|test "Bitset::ctpop" {
#| @debug.debug_inspect(
#| ([0, 0xf0f0f0f0, 0x3c3c0ff0] : Array[_]).map(x => x.popcnt()),
#| content="[0, 16, 16]",
#| )
#|}
),
"extends.mbt": (
#|pub extend Bitset with Eq::{equal}
#|pub extend SparseArray with Eq::{equal}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Bitset with Eq::{not_equal}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SparseArray with Eq::{not_equal}
),
"sparse_array.mbt": (
#|pub struct SparseArray[X] {
#| elem_info : Bitset
#| data : FixedArray[X]
#|} derive(Eq)
#|pub fn[X] empty() -> SparseArray[X] {
#| { elem_info: empty_bitset, data: [], }
#|}
#|#owned(value)
#|pub fn[X] singleton(idx : Int, value : X) -> SparseArray[X] {
#| { elem_info: empty_bitset.add(idx), data: [value], }
#|}
#|pub fn[X] SparseArray::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] SparseArray::unsafe_get(self : SparseArray[X], idx : Int) -> X {
#| self.data[self.elem_info.index_of(idx)]
#|}
#|#owned(value1, value2)
#|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]
#| },
#| }
#|}
#|#owned(data)
#|pub fn[X] from_sorted_fixed_array(
#| indices : FixedArray[Int],
#| data : FixedArray[X],
#|) -> SparseArray[X] {
#| let mut elem_info = empty_bitset
#| for idx in indices {
#| elem_info = elem_info.add(idx)
#| }
#| { elem_info, data, }
#|}
#|#owned(value)
#|pub fn[X] SparseArray::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_and_blit(
#| old_data,
#| allocate_len=new_len,
#| init=value,
#| len=pos_of_new_item,
#| )
#| new_data[pos_of_new_item] = value
#| FixedArray::unsafe_blit(
#| new_data,
#| pos_of_new_item + 1,
#| old_data,
#| pos_of_new_item,
#| old_len - pos_of_new_item,
#| )
#| { elem_info: self.elem_info.add(idx), data: new_data, }
#|}
#|pub fn[X] SparseArray::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_and_blit(
#| old_data,
#| allocate_len=old_len - 1,
#| init=old_data.unsafe_get(0),
#| len=pos_of_removed_item,
#| )
#| FixedArray::unsafe_blit(
#| new_data,
#| pos_of_removed_item,
#| old_data,
#| pos_of_removed_item + 1,
#| old_len - pos_of_removed_item - 1,
#| )
#| { 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.length(), self.data[0])
#| for rest = union_elem_info, index = 0; rest != empty_bitset; {
#| let idx = rest.first_idx()
#| data[index] = match self.get(idx) {
#| None => other.unsafe_get(idx)
#| Some(value1) =>
#| match other.get(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] {
#| FixedArray::make_and_blit(self, allocate_len=len, init=self[0], len~)
#|}
#|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.length(), 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)
#| }
#| } nobreak {
#| 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.length(), 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.get(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
#| }
#| }
#| }
#| } nobreak {
#| 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.length(), 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
#| }
#| }
#| } nobreak {
#| 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), })
#| }
#| }
#|}
#|#owned(value)
#|pub fn[X] SparseArray::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, }
#|}
#|#alias(size, deprecated)
#|pub fn[X] SparseArray::length(self : SparseArray[X]) -> Int {
#| self.data.length()
#|}
#|pub fn[X] SparseArray::each(
#| self : SparseArray[X],
#| f : (X) -> Unit raise?,
#|) -> Unit raise? {
#| for i in 0.. Repr(x))
#| @debug.Repr::opaque_("PriorityQueue", @debug.Repr::array(xs))
#|}
#|test "Debug for PriorityQueue" {
#| let pq : PriorityQueue[Int] = from_array([3, 1, 2])
#| @debug.debug_inspect(pq, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `PriorityQueue([])` instead")
#|#as_free_fn(deprecated="Use `PriorityQueue([])` instead")
#|pub fn[A] PriorityQueue::new() -> PriorityQueue[A] {
#| { node: Empty, size: 0, }
#|}
),
"extends.mbt": (
#|pub extend PriorityQueue with Compare::{compare}
#|pub extend PriorityQueue with Eq::{equal}
#|pub extend PriorityQueue with Hash::{hash}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend PriorityQueue with @debug.Debug::{to_repr}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend PriorityQueue with Compare::{op_ge, op_gt, op_le, op_lt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend PriorityQueue with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend PriorityQueue with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend PriorityQueue with Show::{output, to_string}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend PriorityQueue with ToJson::{to_json}
),
"priority_queue.mbt": (
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[A : Compare] PriorityQueue::PriorityQueue(
#| array : ArrayView[A],
#|) -> PriorityQueue[A] {
#| from_array_in_place(array.to_owned().mut_view())
#|}
#|fn[A : Compare] from_array_in_place(heap : MutArrayView[A]) -> PriorityQueue[A] {
#| let len = heap.length()
#| guard len > 0 else { return { node: Empty, size: 0, } }
#| heapify(heap)
#| { node: priority_queue_node_from_heap(heap, 0, len), size: len, }
#|}
#|fn[A : Compare] heapify(heap : MutArrayView[A]) -> Unit {
#| let len = heap.length()
#| for i in (len / 2)>..0 {
#| sift_down(heap, i, len)
#| }
#|}
#|fn[A : Compare] sift_down(
#| heap : MutArrayView[A],
#| start : Int,
#| len : Int,
#|) -> Unit {
#| for root = start {
#| let left = root * 2 + 1
#| guard left < len else { break }
#| let right = left + 1
#| let child = if right < len && heap.unsafe_get(right) > heap.unsafe_get(left) {
#| right
#| } else {
#| left
#| }
#| guard heap.unsafe_get(root) < heap.unsafe_get(child) else { break }
#| let root_value = heap.unsafe_get(root)
#| heap.unsafe_set(root, heap.unsafe_get(child))
#| heap.unsafe_set(child, root_value)
#| continue child
#| }
#|}
#|fn[A] priority_queue_node_from_heap(
#| heap : MutArrayView[A],
#| index : Int,
#| len : Int,
#|) -> Node[A] {
#| if index >= len {
#| Empty
#| } else {
#| let value = heap.unsafe_get(index)
#| let left_index = index * 2 + 1
#| if left_index >= len {
#| Leaf(value)
#| } else {
#| Branch(
#| value,
#| left=priority_queue_node_from_heap(heap, left_index, len),
#| right=priority_queue_node_from_heap(heap, left_index + 1, len),
#| )
#| }
#| }
#|}
#|pub fn[A : Compare] PriorityQueue::to_array(
#| self : PriorityQueue[A],
#|) -> 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_in_place()
#| arr
#|}
#|#alias(iterator, deprecated)
#|pub fn[A : Compare] PriorityQueue::iter(self : PriorityQueue[A]) -> Iter[A] {
#| self.to_array().iter()
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[A : Compare] PriorityQueue::from_iter(
#| iter : Iter[A],
#|) -> PriorityQueue[A] {
#| from_array_in_place(iter.to_array().mut_view())
#|}
#|priv struct Path(Int)
#|fn path(size : Int) -> Path {
#| for x = size, y = 0 {
#| match (x, y) {
#| (1, y) => break Path(y)
#| (x, y) => continue x >> 1, (y << 1) | (x & 1)
#| }
#| }
#|}
#|fn Path::is_left(self : Path) -> Bool {
#| (self.0 & 1) == 0
#|}
#|fn Path::next(self : Path) -> Path {
#| Path(self.0 >> 1)
#|}
#|pub fn[A : Compare] PriorityQueue::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] Node::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))
#| }
#| }
#|}
#|#owned(value)
#|fn[A : Compare] Node::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.")
#|#doc(hidden)
#|#alias(pop_exn, deprecated)
#|pub fn[A : Compare] PriorityQueue::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, }
#| }
#| }
#|}
#|#owned(value)
#|pub fn[A : Compare] PriorityQueue::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, }
#| }
#| }
#|}
#|#owned(value)
#|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] PriorityQueue::peek(self : PriorityQueue[A]) -> A? {
#| match self.node {
#| Empty => None
#| Leaf(a) | Branch(a, ..) => Some(a)
#| }
#|}
#|pub fn[A] PriorityQueue::is_empty(self : PriorityQueue[A]) -> Bool {
#| self.node is Empty
#|}
#|pub fn[A] PriorityQueue::length(self : PriorityQueue[A]) -> Int {
#| self.size
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show + Compare] Show for PriorityQueue[A]
#|pub impl[A : Show + Compare] Show for PriorityQueue[A] with fn output(
#| self,
#| logger,
#|) {
#| logger.write_iter(
#| self.iter(),
#| prefix="@immut/priority_queue.from_array([",
#| suffix="])",
#| )
#|}
#|pub impl[A : Compare] Eq for PriorityQueue[A] with fn equal(self, other) {
#| physical_equal(self, other) ||
#| (self.length() == other.length() && self.to_array() == other.to_array())
#|}
#|pub impl[A : Hash + Compare] Hash for PriorityQueue[A] with fn hash_combine(
#| self,
#| hasher,
#|) {
#| for e in self {
#| hasher.combine(e)
#| }
#|}
#|pub impl[A : Compare] Compare for PriorityQueue[A] with fn 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, x in self_arr {
#| let cmp = x.compare(other_arr[i])
#| if cmp != 0 {
#| return cmp
#| }
#| } nobreak {
#| return 0
#| }
#|}
),
"types.mbt": (
#|struct PriorityQueue[A] {
#| node : Node[A]
#| size : Int
#|}
#|priv enum Node[A] {
#| Empty
#| Leaf(A)
#| Branch(A, left~ : Node[A], right~ : Node[A])
#|}
#|pub impl[A : ToJson + Compare] ToJson for PriorityQueue[A] with fn to_json(
#| self : PriorityQueue[A],
#|) {
#| [
#| for item in self => item
#| ]
#|}
),
},
)
///|
let moonbitlang_core_immut_sorted_map_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/sorted_map",
deps={},
files={
"debug.mbt": (
#|pub impl[K : @debug.Debug, V : @debug.Debug] @debug.Debug for SortedMap[K, V] with fn to_repr(
#| self,
#|) {
#| @debug.Repr::opaque_(
#| "SortedMap",
#| @debug.Repr::map(self.to_array().map(kv => (Repr(kv.0), Repr(kv.1)))),
#| )
#|}
#|test "Debug for SortedMap" {
#| let sm : SortedMap[Int, String] = SortedMap([(1, "a"), (2, "b")])
#| @debug.debug_inspect(
#| sm,
#| content=(
#| #|
#| ),
#| )
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `keys_as_iter` instead. `keys` will return `Iter[K]` instead of `Array[K]` in the future.")
#|#coverage.skip
#|pub fn[K, V] SortedMap::keys(self : SortedMap[K, V]) -> Array[K] {
#| self.keys_as_iter().collect()
#|}
#|#deprecated("Use `values` instead")
#|#coverage.skip
#|pub fn[K, V] SortedMap::elems(self : SortedMap[K, V]) -> Array[V] {
#| self.values().collect()
#|}
),
"extends.mbt": (
#|pub extend SortedMap with Compare::{compare}
#|pub extend SortedMap with Eq::{equal}
#|pub extend SortedMap with Hash::{hash}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedMap with @debug.Debug::{to_repr}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedMap with Compare::{op_ge, op_gt, op_le, op_lt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedMap with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedMap with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedMap with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedMap with Show::{output, to_string}
),
"map.mbt": (
#|#alias(insert, deprecated)
#|#owned(value)
#|pub fn[K : Compare, V] SortedMap::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, V] SortedMap::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, V] SortedMap::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, 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.length() > r.length() {
#| 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] SortedMap::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))
#| }
#| }
#| }
#|}
#|#alias(filter_with_key, deprecated)
#|pub fn[K, V] SortedMap::filter(
#| 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(pred), r.filter(pred))
#| } else {
#| glue(l.filter(pred), r.filter(pred))
#| }
#| }
#|}
#|pub fn[K, V] SortedMap::to_array(self : SortedMap[K, V]) -> Array[(K, V)] {
#| [
#| for k, v in self => (k, v)
#| ]
#|}
#|pub fn[K : Compare, V] SortedMap::merge(
#| self : SortedMap[K, V],
#| other : SortedMap[K, V],
#|) -> SortedMap[K, V] {
#| match (self, other) {
#| (Empty, _) => other
#| (_, Empty) => self
#| (_, Tree(k2, value=v2, l2, r2, ..)) => {
#| let (l1, _, r1) = self.split(k2)
#| let merged_l = l1.merge(l2)
#| let merged_r = r1.merge(r2)
#| join(merged_l, k2, v2, merged_r)
#| }
#| }
#|}
#|fn[K : Compare, V] SortedMap::split(
#| self : SortedMap[K, V],
#| key : K,
#|) -> (SortedMap[K, V], V?, SortedMap[K, V]) {
#| match self {
#| Empty => (Empty, None, Empty)
#| Tree(k, value=v, l, r, ..) => {
#| let c = key.compare(k)
#| if c == 0 {
#| (l, Some(v), r)
#| } else if c < 0 {
#| let (ll, found, lr) = l.split(key)
#| (ll, found, join(lr, k, v, r))
#| } else {
#| let (rl, found, rr) = r.split(key)
#| (join(l, k, v, rl), found, rr)
#| }
#| }
#| }
#|}
#|fn[K, V] join(
#| l : SortedMap[K, V],
#| k : K,
#| v : V,
#| r : SortedMap[K, V],
#|) -> SortedMap[K, V] {
#| match (l, r) {
#| (Empty, _) => balance(k, v, Empty, r)
#| (_, Empty) => balance(k, v, l, Empty)
#| (Tree(lk, value=lv, ll, lr, size=ls), Tree(rk, value=rv, rl, rr, size=rs)) =>
#| if ls * ratio < rs {
#| balance(rk, rv, join(l, k, v, rl), rr)
#| } else if rs * ratio < ls {
#| balance(lk, lv, ll, join(lr, k, v, r))
#| } else {
#| make_tree(k, v, l, r)
#| }
#| }
#|}
#|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.length()
#| let rn = r.length()
#| if ln + rn < 2 {
#| make_tree(key, value, l, r)
#| } else if rn > ratio * ln {
#| guard! r is Tree(_, rl, rr, ..)
#| let rln = rl.length()
#| let rrn = rr.length()
#| 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.length()
#| let lrn = lr.length()
#| 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 = SortedMap([
#| (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 = SortedMap([(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 = SortedMap([
#| (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 = SortedMap([
#| (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 = SortedMap([
#| (3, "three"),
#| (8, "eight"),
#| (1, "one"),
#| (2, "two"),
#| (0, "zero"),
#| ])
#| let n = m.map((_, v) => v + "X")
#| @test.assert_eq(
#| n.debug_tree(),
#| "(3,threeX,(1,oneX,(0,zeroX,_,_),(2,twoX,_,_)),(8,eightX,_,_))",
#| )
#|}
#|test "map_with_key" {
#| let m = SortedMap([
#| (3, "three"),
#| (8, "eight"),
#| (1, "one"),
#| (2, "two"),
#| (0, "zero"),
#| ])
#| let n = m.map((k, v) => "\{k}-\{v}")
#| @test.assert_eq(
#| n.debug_tree(),
#| "(3,3-three,(1,1-one,(0,0-zero,_,_),(2,2-two,_,_)),(8,8-eight,_,_))",
#| )
#|}
#|test "filter" {
#| let m = SortedMap([
#| (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 = SortedMap([
#| (3, "three"),
#| (8, "eight"),
#| (1, "one"),
#| (2, "two"),
#| (0, "zero"),
#| ])
#| let fm = m.filter((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 "empty" {
#| let m : SortedMap[Int, Int] = new()
#| inspect(m.debug_tree(), content="_")
#|}
#|test "split_max" {
#| let m = SortedMap([
#| (3, "three"),
#| (8, "eight"),
#| (1, "one"),
#| (2, "two"),
#| (0, "zero"),
#| ])
#| @test.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 = SortedMap([
#| (3, "three"),
#| (8, "eight"),
#| (2, "two"),
#| (1, "one"),
#| (0, "zero"),
#| ])
#| @test.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 = SortedMap([
#| (3, "three"),
#| (8, "eight"),
#| (1, "one"),
#| (2, "two"),
#| (0, "zero"),
#| ])
#| @test.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 = SortedMap([
#| (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 fn default() {
#| new()
#|}
#|pub impl[K : Eq, V : Eq] Eq for SortedMap[K, V] with fn equal(self, other) -> Bool {
#| if physical_equal(self, other) {
#| return true
#| }
#| guard self.length() == other.length() else { return false }
#| let iter = self.iter()
#| let iter1 = other.iter()
#| while iter.next() is Some(a) && iter1.next() is Some(b) {
#| guard a == b else { break false }
#| } nobreak {
#| true
#| }
#|}
#|pub impl[K : Compare, V : Compare] Compare for SortedMap[K, V] with fn compare(
#| self,
#| other,
#|) -> Int {
#| guard self.length() == other.length() else {
#| return self.length() - other.length()
#| }
#| let iter = self.iter()
#| let iter1 = other.iter()
#| while iter.next() is Some(a) && iter1.next() is Some(b) {
#| let cmp = compare(a, b)
#| guard cmp is 0 else { break cmp }
#| } nobreak {
#| 0
#| }
#|}
#|pub impl[K : Hash, V : Hash] Hash for SortedMap[K, V] with fn hash_combine(
#| self,
#| hasher,
#|) {
#| for e in self {
#| hasher.combine(e.0)
#| hasher.combine(e.1)
#| }
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[K : Show, V : Show] Show for SortedMap[K, V]
#|#warnings("-deprecated")
#|pub impl[K : Show, V : Show] Show for SortedMap[K, V] with fn output(
#| self,
#| logger,
#|) {
#| logger.write_iter(
#| self.iter(),
#| prefix="@immut/sorted_map.from_array([",
#| suffix="])",
#| )
#|}
#|pub impl[K : Show, V : ToJson] ToJson for SortedMap[K, V] with fn to_json(self) {
#| Json::object(
#| Map(
#| capacity=self.length(),
#| [
#| for k, v in self => (k.to_string(), v.to_json())
#| ],
#| ),
#| )
#|}
#|pub impl[V : @json.FromJson] @json.FromJson for SortedMap[String, V] with fn from_json(
#| json,
#| path,
#|) {
#| guard json is Object(obj) else {
#| raise JsonDecodeError(
#| (path, "@immut/sorted_map.from_json: expected object"),
#| )
#| }
#| for k, v in obj; map = (new() : SortedMap[String, V]) {
#| continue map.add(k, V::from_json(v, path.add_key(k)))
#| } nobreak {
#| map
#| }
#|}
#|#as_free_fn
#|pub fn[V : @json.FromJson] SortedMap::from_json(
#| json : Json,
#|) -> SortedMap[String, V] raise @json.JsonDecodeError {
#| @json.from_json(json)
#|}
),
"types.mbt": (
#|enum SortedMap[K, V] {
#| Empty
#| Tree(K, value~ : V, size~ : Int, SortedMap[K, V], SortedMap[K, V])
#|}
),
"utils.mbt": (
#|#as_free_fn
#|#alias(empty, deprecated)
#|pub fn[K, V] SortedMap::new() -> SortedMap[K, V] {
#| Empty
#|}
#|#as_free_fn
#|#owned(key, value)
#|pub fn[K, V] SortedMap::singleton(key : K, value : V) -> SortedMap[K, V] {
#| Tree(key, value~, size=1, Empty, Empty)
#|}
#|pub fn[K : Compare, V] SortedMap::contains(
#| self : SortedMap[K, V],
#| key : K,
#|) -> Bool {
#| for x = self {
#| match x {
#| Empty => break false
#| Tree(k, l, r, ..) => {
#| let c = key.compare(k)
#| if c == 0 {
#| break true
#| } else if c < 0 {
#| continue l
#| } else {
#| continue r
#| }
#| }
#| }
#| }
#|}
#|#alias(size, deprecated)
#|#inline
#|pub fn[K, V] SortedMap::length(self : SortedMap[K, V]) -> Int {
#| match self {
#| Empty => 0
#| Tree(_) as t => t.size
#| }
#|}
#|pub fn[K, V] SortedMap::is_empty(self : SortedMap[K, V]) -> Bool {
#| self.length() == 0
#|}
#|#inline
#|#owned(key, value, l, r)
#|fn[K, V] make_tree(
#| key : K,
#| value : V,
#| l : SortedMap[K, V],
#| r : SortedMap[K, V],
#|) -> SortedMap[K, V] {
#| let size = l.length() + r.length() + 1
#| Tree(key, value~, size~, l, r)
#|}
#|#alias(lookup, deprecated)
#|pub fn[K : Compare, V] SortedMap::get(self : SortedMap[K, V], key : K) -> V? {
#| for x = self {
#| match x {
#| Empty => break None
#| Tree(k, value~, l, r, ..) => {
#| let c = key.compare(k)
#| if c == 0 {
#| break Some(value)
#| } else if c < 0 {
#| continue l
#| } else {
#| continue r
#| }
#| }
#| }
#| }
#|}
#|#alias("_[_]")
#|pub fn[K : Compare, V] SortedMap::at(self : SortedMap[K, V], key : K) -> V {
#| for x = self {
#| match x {
#| Empty => break panic()
#| Tree(k, value~, l, r, ..) => {
#| let c = key.compare(k)
#| if c == 0 {
#| break value
#| } else if c < 0 {
#| continue l
#| } else {
#| continue r
#| }
#| }
#| }
#| }
#|}
#|pub fn[K, V] SortedMap::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] SortedMap::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.length() + i, k, value)
#| do_eachi(r, f, l.length() + i + 1)
#| }
#| }
#| }
#| do_eachi(self, f, 0)
#|}
#|#alias(map_with_key, deprecated)
#|pub fn[K, X, Y] SortedMap::map(
#| 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(f), r.map(f))
#| }
#|}
#|#alias(foldr_with_key)
#|pub fn[K, V, A] SortedMap::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)
#|}
#|#alias(foldl_with_key, deprecated)
#|pub fn[K, V, A] SortedMap::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(r, f(go(l, acc), k, value))
#| }
#| }
#| go(self, init)
#|}
#|fn[K : Show, V : Show] SortedMap::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})"
#| }
#| }
#|}
#|#as_free_fn(deprecated="Use @immut/sorted_map.SortedMap([...]) instead")
#|#alias(of, deprecated="Use @immut/sorted_map.SortedMap([...]) instead")
#|#as_free_fn(of, deprecated="Use @immut/sorted_map.SortedMap([...]) instead")
#|#deprecated("Use @immut/sorted_map.SortedMap([...]) instead")
#|pub fn[K : Compare, V] SortedMap::from_array(
#| array : ArrayView[(K, V)],
#|) -> SortedMap[K, V] {
#| sorted_map_from_array(array)
#|}
#|fn[K : Compare, V] sorted_map_from_array(
#| array : ArrayView[(K, V)],
#|) -> SortedMap[K, V] {
#| let (order, has_duplicates) = sorted_map_array_order(array)
#| if order == 1 {
#| if has_duplicates {
#| let compacted = sorted_map_compact_ordered_array(array, true)
#| return sorted_map_from_ascending_array(compacted, 0, compacted.length())
#| }
#| return sorted_map_from_ascending_array(array, 0, array.length())
#| } else if order == -1 {
#| if has_duplicates {
#| let compacted = sorted_map_compact_ordered_array(array, false)
#| return sorted_map_from_ascending_array(compacted, 0, compacted.length())
#| }
#| return sorted_map_from_descending_array(array, 0, array.length())
#| }
#| if array.length() >= sorted_map_sort_build_threshold {
#| sorted_map_from_unsorted_array(array)
#| } else {
#| sorted_map_from_array_by_add(array)
#| }
#|}
#|let sorted_map_sort_build_threshold = 64
#|priv struct SortEntry[K, V] {
#| key : K
#| value : V
#| index : Int
#|}
#|impl[K : Compare, V] Eq for SortEntry[K, V] with fn equal(self, other) {
#| self.key == other.key && self.index == other.index
#|}
#|impl[K : Compare, V] Compare for SortEntry[K, V] with fn compare(self, other) {
#| let c = self.key.compare(other.key)
#| if c == 0 {
#| self.index.compare(other.index)
#| } else {
#| c
#| }
#|}
#|fn[K : Compare, V] sorted_map_from_unsorted_array(
#| array : ArrayView[(K, V)],
#|) -> SortedMap[K, V] {
#| let entries : FixedArray[SortEntry[K, V]] = FixedArray::makei(
#| array.length(),
#| i => { key: array[i].0, value: array[i].1, index: i, },
#| )
#| sorted_map_from_unsorted_entries(entries.mut_view())
#|}
#|fn[K : Compare, V] sorted_map_from_unsorted_entries(
#| entries : MutArrayView[SortEntry[K, V]],
#|) -> SortedMap[K, V] {
#| entries.sort()
#| let len = sorted_map_compact_entries_in_place(entries)
#| sorted_map_from_sorted_entries(entries.exact_view(), 0, len)
#|}
#|fn[K : Compare, V] sorted_map_from_array_by_add(
#| array : ArrayView[(K, V)],
#|) -> SortedMap[K, V] {
#| for item in array; mp = Empty {
#| let (k, v) = item
#| continue mp.add(k, v)
#| } nobreak {
#| mp
#| }
#|}
#|pub fn[K : Compare, V] SortedMap::SortedMap(
#| array : ArrayView[(K, V)],
#|) -> SortedMap[K, V] {
#| sorted_map_from_array(array)
#|}
#|fn[K : Compare, V] sorted_map_compact_entries_in_place(
#| entries : MutArrayView[SortEntry[K, V]],
#|) -> Int {
#| let len = entries.length()
#| let mut write = 0
#| for start = 0; start < len; {
#| let end = for end = start; end + 1 < len &&
#| entries.unsafe_get(end).key.compare(
#| entries.unsafe_get(end + 1).key,
#| ) ==
#| 0; {
#| continue end + 1
#| } nobreak {
#| end
#| }
#| entries.unsafe_set(write, {
#| key: entries.unsafe_get(start).key,
#| value: entries.unsafe_get(end).value,
#| index: entries.unsafe_get(start).index,
#| })
#| write += 1
#| continue end + 1
#| }
#| write
#|}
#|fn[K : Compare, V] sorted_map_array_order(
#| array : ArrayView[(K, V)],
#|) -> (Int, Bool) {
#| let len = array.length()
#| guard len > 1 else { return (1, false) }
#| let mut order = 0
#| let mut has_duplicates = false
#| for i in 1.. Array[(K, V)] {
#| let result = []
#| let len = array.length()
#| if ascending {
#| for start = 0; start < len; {
#| let end = for end = start; end + 1 < len &&
#| array[end].0.compare(array[end + 1].0) == 0; {
#| continue end + 1
#| } nobreak {
#| end
#| }
#| result.push((array[start].0, array[end].1))
#| continue end + 1
#| }
#| } else {
#| for end = len - 1; end >= 0; {
#| let start = for start = end; start > 0 &&
#| array[start - 1].0.compare(array[start].0) == 0; {
#| continue start - 1
#| } nobreak {
#| start
#| }
#| result.push((array[start].0, array[end].1))
#| continue start - 1
#| }
#| }
#| result
#|}
#|fn[K, V] sorted_map_from_ascending_array(
#| array : ArrayView[(K, V)],
#| start : Int,
#| end : Int,
#|) -> SortedMap[K, V] {
#| if start >= end {
#| Empty
#| } else {
#| let mid = (start + end) / 2
#| let (key, value) = array[mid]
#| let left = sorted_map_from_ascending_array(array, start, mid)
#| let right = sorted_map_from_ascending_array(array, mid + 1, end)
#| make_tree(key, value, left, right)
#| }
#|}
#|fn[K, V] sorted_map_from_descending_array(
#| array : ArrayView[(K, V)],
#| start : Int,
#| end : Int,
#|) -> SortedMap[K, V] {
#| if start >= end {
#| Empty
#| } else {
#| let mid = (start + end) / 2
#| let (key, value) = array[mid]
#| let left = sorted_map_from_descending_array(array, mid + 1, end)
#| let right = sorted_map_from_descending_array(array, start, mid)
#| make_tree(key, value, left, right)
#| }
#|}
#|fn[K, V] sorted_map_from_sorted_entries(
#| entries : ArrayView[SortEntry[K, V]],
#| start : Int,
#| end : Int,
#|) -> SortedMap[K, V] {
#| if start >= end {
#| Empty
#| } else {
#| let mid = (start + end) / 2
#| let entry = entries[mid]
#| let left = sorted_map_from_sorted_entries(entries, start, mid)
#| let right = sorted_map_from_sorted_entries(entries, mid + 1, end)
#| make_tree(entry.key, entry.value, left, right)
#| }
#|}
#|#alias(iterator, deprecated)
#|pub fn[K, V] SortedMap::iter(self : SortedMap[K, V]) -> Iter[(K, V)] {
#| let mut curr_node = self
#| let parents = []
#| Iter::new(
#| fn() {
#| for x = curr_node {
#| match x {
#| Tree(k, value~, Empty, r, ..) => {
#| curr_node = r
#| break Some((k, value))
#| }
#| Tree(k, value~, l, r, ..) => {
#| parents.push((k, value, r))
#| continue l
#| }
#| Empty if parents.pop() is Some((k, v, r)) => {
#| curr_node = r
#| break Some((k, v))
#| }
#| Empty => break None
#| }
#| }
#| },
#| size_hint=self.length(),
#| )
#|}
#|#alias(iterator2, deprecated)
#|pub fn[K, V] SortedMap::iter2(self : SortedMap[K, V]) -> Iter2[K, V] {
#| self.iter()
#|}
#|pub fn[K : Compare, V] SortedMap::range(
#| self : SortedMap[K, V],
#| low~ : K,
#| high~ : K,
#|) -> Iter2[K, V] {
#| let todo_list = []
#| let mut next_node = self
#| Iter2::new(fn() {
#| for x = next_node {
#| match x {
#| Tree(k, value~, l, r, ..) => {
#| let cmp_key_low = k.compare(low)
#| let cmp_key_high = k.compare(high)
#| if cmp_key_low < 0 {
#| continue r
#| } else if cmp_key_high > 0 {
#| continue l
#| } else if l is Empty {
#| next_node = r
#| break Some((k, value))
#| } else {
#| todo_list.push((k, value, r))
#| continue l
#| }
#| }
#| Empty if todo_list.pop() is Some((k, value, r)) => {
#| next_node = r
#| break Some((k, value))
#| }
#| Empty => break None
#| }
#| }
#| })
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[K : Compare, V] SortedMap::from_iter(
#| iter : Iter[(K, V)],
#|) -> SortedMap[K, V] {
#| iter.fold(init=new(), (m, e) => m.add(e.0, e.1))
#|}
#|pub fn[K, V] SortedMap::keys_as_iter(self : SortedMap[K, V]) -> Iter[K] {
#| self.iter().map(p => p.0)
#|}
#|pub fn[K, V] SortedMap::values(self : SortedMap[K, V]) -> Iter[V] {
#| self.iter().map(p => p.1)
#|}
#|pub fn[K, V] SortedMap::rev_keys(self : SortedMap[K, V]) -> Iter[K] {
#| let mut curr_node = self
#| let parents = []
#| Iter::new(
#| fn() {
#| for x = curr_node {
#| match x {
#| Tree(k, l, Empty, ..) => {
#| curr_node = l
#| break Some(k)
#| }
#| Tree(k, l, r, ..) => {
#| parents.push((k, l))
#| continue r
#| }
#| Empty if parents.pop() is Some((k, l)) => {
#| curr_node = l
#| break Some(k)
#| }
#| Empty => break None
#| }
#| }
#| },
#| size_hint=self.length(),
#| )
#|}
#|pub fn[K, V] SortedMap::rev_values(self : SortedMap[K, V]) -> Iter[V] {
#| let mut curr_node = self
#| let parents = []
#| Iter::new(
#| fn() {
#| for x = curr_node {
#| match x {
#| Tree(_k, value~, l, Empty, ..) => {
#| curr_node = l
#| break Some(value)
#| }
#| Tree(_k, value~, l, r, ..) => {
#| parents.push((value, l))
#| continue r
#| }
#| Empty if parents.pop() is Some((v, l)) => {
#| curr_node = l
#| break Some(v)
#| }
#| Empty => break None
#| }
#| }
#| },
#| size_hint=self.length(),
#| )
#|}
#|pub fn[K : Show, V : ToJson] SortedMap::to_json(self : SortedMap[K, V]) -> Json {
#| ToJson::to_json(self)
#|}
),
},
)
///|
let moonbitlang_core_immut_sorted_set_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/sorted_set",
deps={},
files={
"debug.mbt": (
#|pub impl[K : @debug.Debug] @debug.Debug for SortedSet[K] with fn to_repr(self) {
#| @debug.Repr::opaque_(
#| "SortedSet",
#| @debug.Repr::array([ for x in self => Repr(x) ]),
#| )
#|}
#|test "Debug for SortedSet" {
#| let ss : SortedSet[Int] = SortedSet([3, 1, 2])
#| @debug.debug_inspect(ss, content="")
#|}
),
"deprecated.mbt": "",
"extends.mbt": (
#|pub extend SortedSet with Compare::{compare}
#|pub extend SortedSet with Eq::{equal}
#|pub extend SortedSet with Hash::{hash}
#|pub extend SortedSet with Sub::{sub}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedSet with @debug.Debug::{to_repr}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedSet with Compare::{op_ge, op_gt, op_le, op_lt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedSet with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedSet with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedSet with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedSet with Show::{output, to_string}
),
"generic.mbt": (
#|#alias(rev_iterator, deprecated)
#|pub fn[A] SortedSet::rev_iter(self : SortedSet[A]) -> Iter[A] {
#| let mut curr_node = self
#| let parents = []
#| Iter::new(
#| fn() {
#| for x = curr_node {
#| match x {
#| Node(left~, right=Empty, value~, ..) => {
#| curr_node = left
#| break Some(value)
#| }
#| Node(left~, right~, value~, ..) => {
#| parents.push((value, left))
#| continue right
#| }
#| Empty if parents.pop() is Some((value, left)) => {
#| curr_node = left
#| break Some(value)
#| }
#| Empty => break None
#| }
#| }
#| },
#| size_hint=self.length(),
#| )
#|}
#|#alias(iterator, deprecated)
#|pub fn[A] SortedSet::iter(self : SortedSet[A]) -> Iter[A] {
#| let mut curr_node = self
#| let parents = []
#| Iter::new(
#| fn() {
#| for x = curr_node {
#| match x {
#| Node(left=Empty, right~, value~, size=_) => {
#| curr_node = right
#| break Some(value)
#| }
#| Node(left~, right~, value~, size=_) => {
#| parents.push((value, right))
#| continue left
#| }
#| Empty if parents.pop() is Some((value, right)) => {
#| curr_node = right
#| break Some(value)
#| }
#| Empty => break None
#| }
#| }
#| },
#| size_hint=self.length(),
#| )
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[A : Compare] SortedSet::from_iter(iter : Iter[A]) -> SortedSet[A] {
#| iter.fold(init=new(), (s, e) => s.add(e))
#|}
#|test {
#| @json.json_inspect(SortedSet([2, 7, 1, 2, 3, 4, 5]), content=[
#| 1, 2, 3, 4, 5, 7,
#| ])
#|}
#|pub impl[A : Eq] Eq for SortedSet[A] with fn equal(self, other) -> Bool {
#| if physical_equal(self, other) {
#| return true
#| }
#| guard self.length() == other.length() else { return false }
#| let iter = self.iter()
#| let iter1 = other.iter()
#| while iter.next() is Some(a) && iter1.next() is Some(b) {
#| guard a == b else { break false }
#| } nobreak {
#| true
#| }
#|}
#|pub impl[A : Compare] Compare for SortedSet[A] with fn compare(self, other) -> Int {
#| let my_size = self.length()
#| let other_size = other.length()
#| guard my_size == other_size else { return my_size - other_size }
#| let iter = self.iter()
#| let iter1 = other.iter()
#| while iter.next() is Some(a) && iter1.next() is Some(b) {
#| let cmp = a.compare(b)
#| guard cmp is 0 else { break cmp }
#| } nobreak {
#| 0
#| }
#|}
#|test "Eq - equal sets" {
#| let s1 = SortedSet([1, 2, 3, 4, 5])
#| let s2 = SortedSet([5, 4, 3, 2, 1])
#| inspect(s1 == s2, content="true")
#|}
#|test "Eq - different elements same size" {
#| let s1 = SortedSet([1, 2, 3, 4, 5])
#| let s2 = SortedSet([1, 2, 3, 4, 6])
#| inspect(s1 == s2, content="false")
#|}
#|test "Eq - different sizes" {
#| let s1 = SortedSet([1, 2, 3])
#| let s2 = SortedSet([1, 2, 3, 4, 5])
#| inspect(s1 == s2, content="false")
#|}
#|test "Eq - empty sets" {
#| let s1 : SortedSet[Int] = new()
#| let s2 : SortedSet[Int] = new()
#| inspect(s1 == s2, content="true")
#|}
#|test "Eq - one empty one not" {
#| let s1 : SortedSet[Int] = new()
#| let s2 = SortedSet([1])
#| inspect(s1 == s2, content="false")
#|}
#|test "Compare - equal sets" {
#| let s1 = SortedSet([1, 2, 3])
#| let s2 = SortedSet([3, 2, 1])
#| inspect(s1.compare(s2), content="0")
#|}
#|test "Compare - first smaller by size" {
#| let s1 = SortedSet([1, 2])
#| let s2 = SortedSet([1, 2, 3])
#| inspect(s1.compare(s2) < 0, content="true")
#|}
#|test "Compare - first larger by size" {
#| let s1 = SortedSet([1, 2, 3, 4])
#| let s2 = SortedSet([1, 2])
#| inspect(s1.compare(s2) > 0, content="true")
#|}
#|test "Compare - same size first smaller by elements" {
#| let s1 = SortedSet([1, 2, 3])
#| let s2 = SortedSet([1, 2, 4])
#| inspect(s1.compare(s2) < 0, content="true")
#|}
#|test "Compare - same size first larger by elements" {
#| let s1 = SortedSet([1, 2, 5])
#| let s2 = SortedSet([1, 2, 4])
#| inspect(s1.compare(s2) > 0, content="true")
#|}
#|test "Compare - empty sets" {
#| let s1 : SortedSet[Int] = new()
#| let s2 : SortedSet[Int] = new()
#| inspect(s1.compare(s2), content="0")
#|}
),
"immutable_set.mbt": (
#|#as_free_fn
#|pub fn[A] SortedSet::new() -> SortedSet[A] {
#| Empty
#|}
#|pub impl[A] Default for SortedSet[A] with fn default() {
#| Empty
#|}
#|#as_free_fn
#|#owned(value)
#|pub fn[A] SortedSet::singleton(value : A) -> SortedSet[A] {
#| Node(left=Empty, value~, right=Empty, size=1)
#|}
#|#as_free_fn(deprecated="Use @immut/sorted_set.SortedSet([...]) instead")
#|#alias(of, deprecated="Use @immut/sorted_set.SortedSet([...]) instead")
#|#as_free_fn(of, deprecated="Use @immut/sorted_set.SortedSet([...]) instead")
#|#deprecated("Use @immut/sorted_set.SortedSet([...]) instead")
#|pub fn[A : Compare] SortedSet::from_array(array : ArrayView[A]) -> SortedSet[A] {
#| sorted_set_from_array(array)
#|}
#|fn[A : Compare] sorted_set_from_array(array : ArrayView[A]) -> SortedSet[A] {
#| let (order, has_duplicates) = sorted_set_array_order(array)
#| if order == 1 {
#| if has_duplicates {
#| let compacted = sorted_set_compact_ordered_array(array, true)
#| return sorted_set_from_ascending_array(compacted, 0, compacted.length())
#| }
#| return sorted_set_from_ascending_array(array, 0, array.length())
#| } else if order == -1 {
#| if has_duplicates {
#| let compacted = sorted_set_compact_ordered_array(array, false)
#| return sorted_set_from_ascending_array(compacted, 0, compacted.length())
#| }
#| return sorted_set_from_descending_array(array, 0, array.length())
#| }
#| if array.length() >= sorted_set_sort_build_threshold {
#| sorted_set_from_unsorted_buffer(array.to_owned().mut_view())
#| } else {
#| sorted_set_from_array_by_add(array)
#| }
#|}
#|let sorted_set_sort_build_threshold = 64
#|fn[A : Compare] sorted_set_from_unsorted_buffer(
#| buf : MutArrayView[A],
#|) -> SortedSet[A] {
#| buf.stable_sort()
#| let len = sorted_set_dedupe_in_place(buf)
#| sorted_set_from_ascending_array(buf.exact_view(start=0, end=len), 0, len)
#|}
#|fn[A : Compare] sorted_set_dedupe_in_place(buf : MutArrayView[A]) -> Int {
#| let len = buf.length()
#| let mut write = 0
#| for start = 0; start < len; {
#| let end = for end = start; end + 1 < len &&
#| buf.unsafe_get(end).compare(buf.unsafe_get(end + 1)) == 0; {
#| continue end + 1
#| } nobreak {
#| end
#| }
#| buf.unsafe_set(write, buf.unsafe_get(end))
#| write += 1
#| continue end + 1
#| }
#| write
#|}
#|fn[A : Compare] sorted_set_from_array_by_add(
#| array : ArrayView[A],
#|) -> SortedSet[A] {
#| for i = array.length() - 1, set = Empty; i >= 0; {
#| continue i - 1, set.add(array[i])
#| } nobreak {
#| set
#| }
#|}
#|pub fn[A : Compare] SortedSet::SortedSet(array : ArrayView[A]) -> SortedSet[A] {
#| sorted_set_from_array(array)
#|}
#|fn[A : Compare] sorted_set_array_order(array : ArrayView[A]) -> (Int, Bool) {
#| let len = array.length()
#| guard len > 1 else { return (1, false) }
#| let mut order = 0
#| let mut has_duplicates = false
#| for i in 1.. Array[A] {
#| let result = []
#| let len = array.length()
#| if ascending {
#| for start = 0; start < len; {
#| let end = for end = start; end + 1 < len &&
#| array[end].compare(array[end + 1]) == 0; {
#| continue end + 1
#| } nobreak {
#| end
#| }
#| result.push(array[end])
#| continue end + 1
#| }
#| } else {
#| for end = len - 1; end >= 0; {
#| let start = for start = end; start > 0 &&
#| array[start - 1].compare(array[start]) == 0; {
#| continue start - 1
#| } nobreak {
#| start
#| }
#| result.push(array[end])
#| continue start - 1
#| }
#| }
#| result
#|}
#|fn[A] sorted_set_from_ascending_array(
#| array : ArrayView[A],
#| start : Int,
#| end : Int,
#|) -> SortedSet[A] {
#| if start >= end {
#| Empty
#| } else {
#| let mid = (start + end) / 2
#| let value = array[mid]
#| let left = sorted_set_from_ascending_array(array, start, mid)
#| let right = sorted_set_from_ascending_array(array, mid + 1, end)
#| create(left, value, right)
#| }
#|}
#|fn[A] sorted_set_from_descending_array(
#| array : ArrayView[A],
#| start : Int,
#| end : Int,
#|) -> SortedSet[A] {
#| if start >= end {
#| Empty
#| } else {
#| let mid = (start + end) / 2
#| let value = array[mid]
#| let left = sorted_set_from_descending_array(array, mid + 1, end)
#| let right = sorted_set_from_descending_array(array, start, mid)
#| create(left, value, right)
#| }
#|}
#|pub fn[A] SortedSet::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] SortedSet::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] SortedSet::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] SortedSet::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] SortedSet::min(self : SortedSet[A]) -> A {
#| for cur = self {
#| match cur {
#| Empty => abort("min: there are no values in sorted_set.")
#| Node(left~, value~, ..) =>
#| if left is Empty {
#| break value
#| } else {
#| continue left
#| }
#| }
#| }
#|}
#|pub fn[A] SortedSet::min_option(self : SortedSet[A]) -> A? {
#| for cur = self {
#| match cur {
#| Empty => break None
#| Node(left~, value~, ..) =>
#| if left is Empty {
#| break Some(value)
#| } else {
#| continue left
#| }
#| }
#| }
#|}
#|pub fn[A] SortedSet::max(self : SortedSet[A]) -> A {
#| for cur = self {
#| match cur {
#| Empty => abort("max: there are no values in ImmutableSet.")
#| Node(right~, value~, ..) =>
#| if right is Empty {
#| break value
#| } else {
#| continue right
#| }
#| }
#| }
#|}
#|pub fn[A] SortedSet::max_option(self : SortedSet[A]) -> A? {
#| for cur = self {
#| match cur {
#| Empty => break None
#| Node(right~, value~, ..) =>
#| if right is Empty {
#| break Some(value)
#| } else {
#| continue right
#| }
#| }
#| }
#|}
#|pub fn[A : Compare] SortedSet::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] SortedSet::is_empty(self : SortedSet[A]) -> Bool {
#| self is Empty
#|}
#|pub fn[A : Compare] SortedSet::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] SortedSet::range(
#| self : SortedSet[A],
#| low~ : A,
#| high~ : A,
#|) -> Iter[A] {
#| let todo_list = []
#| let mut next_node = self
#| Iter::new(fn() {
#| for x = next_node {
#| match x {
#| Node(left~, right~, value~, ..) => {
#| let cmp_value_low = value.compare(low)
#| let cmp_value_high = value.compare(high)
#| if cmp_value_low < 0 {
#| continue right
#| } else if cmp_value_high > 0 {
#| continue left
#| } else if left is Empty {
#| next_node = right
#| break Some(value)
#| } else {
#| todo_list.push((value, right))
#| continue left
#| }
#| }
#| Empty if todo_list.pop() is Some((value, right)) => {
#| next_node = right
#| break Some(value)
#| }
#| Empty => break None
#| }
#| }
#| })
#|}
#|pub fn[A : Compare] SortedSet::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 fn add(self, other) {
#| return self.union(other)
#|}
#|#alias(inter, deprecated)
#|pub fn[A : Compare] SortedSet::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))
#| }
#| }
#|}
#|#alias(diff, deprecated)
#|pub fn[A : Compare] SortedSet::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 impl[A : Compare] Sub for SortedSet[A] with fn sub(self, other) {
#| self.difference(other)
#|}
#|pub fn[A : Compare] SortedSet::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] SortedSet::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(other)
#| } else {
#| Node(left=Empty, value=v1, right=r1, size=1).subset(r2) &&
#| l1.subset(other)
#| }
#| }
#| }
#|}
#|pub fn[A : Compare] SortedSet::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] SortedSet::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, B] SortedSet::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, B : Compare] SortedSet::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] SortedSet::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] SortedSet::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] SortedSet::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)
#| }
#| }
#| }
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for SortedSet[A]
#|pub impl[A : Show] Show for SortedSet[A] with fn output(self, logger) {
#| logger.write_iter(
#| self.iter(),
#| prefix="@immut/sorted_set.from_array([",
#| suffix="])",
#| )
#|}
#|pub impl[A : ToJson] ToJson for SortedSet[A] with fn to_json(self) {
#| [
#| for a in self => a
#| ]
#|}
#|pub fn[A : ToJson] SortedSet::to_json(self : SortedSet[A]) -> Json {
#| ToJson::to_json(self)
#|}
#|pub impl[A : @json.FromJson + Compare] @json.FromJson for SortedSet[A] with fn from_json(
#| json,
#| path,
#|) {
#| guard json is Array(arr) else {
#| raise JsonDecodeError((path, "@immut/sorted_set.from_json: expected array"))
#| }
#| for i, x in arr; set = (new() : SortedSet[A]) {
#| continue set.add(@json.FromJson::from_json(x, path.add_index(i)))
#| } nobreak {
#| set
#| }
#|}
#|#as_free_fn
#|pub fn[A : @json.FromJson + Compare] SortedSet::from_json(
#| json : Json,
#|) -> SortedSet[A] raise @json.JsonDecodeError {
#| @json.from_json(json)
#|}
#|const BALANCE_RATIO = 5
#|priv enum SplitBis[A] {
#| Found
#| NotFound(SortedSet[A], () -> SortedSet[A])
#|}
#|impl[T] Show for SplitBis[T] with fn output(self, logger) {
#| match self {
#| Found => logger.write_string("Found")
#| NotFound(_) => logger.write_string("NotFound")
#| }
#|}
#|fn[A : Compare] SortedSet::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)
#| }
#| }
#| }
#| }
#|}
#|#alias(size, deprecated)
#|#inline
#|pub fn[A] SortedSet::length(self : SortedSet[A]) -> Int {
#| match self {
#| Node(size~, ..) | (Empty with size = 0) => size
#| }
#|}
#|#inline
#|#owned(left, value, right)
#|fn[A] create(
#| left : SortedSet[A],
#| value : A,
#| right : SortedSet[A],
#|) -> SortedSet[A] {
#| Node(left~, right~, value~, size=left.length() + right.length() + 1)
#|}
#|fn[A] balance(
#| left : SortedSet[A],
#| value : A,
#| right : SortedSet[A],
#|) -> SortedSet[A] {
#| let left_size = left.length()
#| let right_size = right.length()
#| 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.length() >= lr.length() {
#| 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.length() >= rl.length() {
#| 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)
#| }
#|}
#|#owned(value)
#|fn[A] SortedSet::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)
#| }
#|}
#|#owned(value)
#|fn[A] SortedSet::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] 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] SortedSet::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] SortedSet::concat(
#| self : SortedSet[A],
#| other : SortedSet[A],
#|) -> SortedSet[A] {
#| match (self, other) {
#| (Empty, _) => other
#| (_, Empty) => self
#| _ => join(self, other.min(), other.remove_min())
#| }
#|}
#|pub impl[A : Hash] Hash for SortedSet[A] with fn hash_combine(self, hasher) {
#| for t in self {
#| t.hash_combine(hasher)
#| }
#|}
#|test "split_bis" {
#| inspect(SortedSet([1, 2, 3]).split_bis(1), content="Found")
#| inspect(SortedSet([1, 2, 3]).split_bis(3), content="Found")
#| inspect(SortedSet([1, 2, 3]).split_bis(0), content="NotFound")
#| inspect(SortedSet([1, 2, 3]).split_bis(4), content="NotFound")
#|}
#|test "balance with left height greater" {
#| let left = SortedSet([1, 2, 3])
#| let value = 4
#| let right = SortedSet([5])
#| let balanced_set = balance(left, value, right)
#| @debug.debug_inspect(
#| balanced_set,
#| content=(
#| #|
#| ),
#| )
#|}
#|test "balance with right height greater" {
#| let left = SortedSet([1])
#| let value = 2
#| let right = SortedSet([3, 4, 5])
#| let balanced_set = balance(left, value, right)
#| @debug.debug_inspect(
#| balanced_set,
#| content=(
#| #|
#| ),
#| )
#|}
#|test "join with different heights" {
#| let left = SortedSet([1, 2, 3])
#| let value = 4
#| let right = SortedSet([5, 6, 7])
#| let joined_set = join(left, value, right)
#| @debug.debug_inspect(
#| joined_set,
#| content=(
#| #|
#| ),
#| )
#|}
#|test "hash" {
#| @test.assert_eq(
#| Hash::hash(SortedSet([1, 2, 3, 4])),
#| Hash::hash(SortedSet([3, 2]).add(1).add(4)),
#| )
#| @test.assert_not_eq(
#| Hash::hash(SortedSet([1, 2, 3])),
#| Hash::hash(SortedSet([1, 2, 4])),
#| )
#|}
),
"types.mbt": (
#|enum SortedSet[A] {
#| Empty
#| Node(left~ : SortedSet[A], right~ : SortedSet[A], size~ : Int, value~ : A)
#|}
),
},
)
///|
let moonbitlang_core_immut_vector_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/vector",
deps={},
files={
"debug.mbt": (
#|pub impl[A : @debug.Debug] @debug.Debug for Vector[A] with fn to_repr(self) {
#| @debug.Repr::opaque_(
#| "Vector",
#| @debug.Repr::array(self.to_array().map(x => Repr(x))),
#| )
#|}
#|test "Debug for Vector" {
#| let xs : Vector[Int] = from_array([1, 2, 3])
#| @debug.debug_inspect(xs, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("We don't copy immutable vector")
#|#coverage.skip
#|#alias(clone, deprecated)
#|pub fn[A] Vector::copy(self : Vector[A]) -> Vector[A] {
#| self
#|}
),
"extends.mbt": (
#|pub extend Vector with Add::{add}
#|pub extend Vector with Compare::{compare}
#|pub extend Vector with Eq::{equal}
#|pub extend Vector with Hash::{hash}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Vector with @debug.Debug::{to_repr}
#|#deprecated("Use `@json.from_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Vector with @json.FromJson::{from_json}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Vector with Compare::{op_ge, op_gt, op_le, op_lt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Vector with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Vector with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Vector with Show::{output, to_string}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Vector with ToJson::{to_json}
),
"tree.mbt": (
#|const NUM_BITS = 5
#|const BRANCHING_FACTOR : Int = 1 << NUM_BITS
#|const 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] {
#| Empty
#|}
#|#owned(leaf)
#|fn[T] new_branch_left(leaf : FixedArray[T], shift : Int) -> Tree[T] {
#| let sizes : FixedArray[Int]? = if leaf.length() == BRANCHING_FACTOR {
#| None
#| } else {
#| Some([leaf.length()])
#| }
#| match shift {
#| 0 => Leaf(leaf)
#| s => Node([new_branch_left(leaf, s - NUM_BITS)], sizes)
#| }
#|}
#|fn[T] Tree::get(self : Tree[T], index : Int, shift : Int) -> T {
#| fn get_radix(node : Tree[T], shift : Int) -> T {
#| for cur = node, s = shift {
#| match cur {
#| Leaf(leaf) => break leaf[index & BITMASK]
#| Node(node, None) =>
#| continue node[radix_indexing(index, s)], s - 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")
#| }
#|}
#|#owned(value)
#|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")
#| }
#|}
#|#owned(value)
#|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 new_sizes = match sizes {
#| Some(_) => update_sizes_last(sizes)
#| None => compute_sizes(new_nodes, shift - NUM_BITS)
#| }
#| Some(Node(new_nodes, new_sizes))
#| }
#| None =>
#| if len < BRANCHING_FACTOR {
#| let new_nodes = immutable_push(
#| nodes,
#| new_branch_left([value], shift - NUM_BITS),
#| )
#| let new_sizes = match sizes {
#| Some(_) => push_sizes_last(sizes)
#| None => compute_sizes(new_nodes, shift - NUM_BITS)
#| }
#| Some(Node(new_nodes, new_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)
#| let len = self.size(shift)
#| (
#| Node([self, new_branch], Some(FixedArray::from_array([len, 1 + len]))),
#| 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 : Eq] Tree::contains(self : Tree[A], value : A) -> Bool {
#| match self {
#| Empty => false
#| Leaf(elems) =>
#| for elem in elems {
#| guard elem != value else { break true }
#| } nobreak {
#| false
#| }
#| Node(children, _) =>
#| for child in children {
#| guard !child.contains(value) else { break true }
#| } nobreak {
#| false
#| }
#| }
#|}
#|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, x in l {
#| f(start + i, x)
#| }
#| Node(ns, None) => {
#| let child_shift = shift - NUM_BITS
#| for child in ns; start = start {
#| child.eachi(f, child_shift, start)
#| continue start + (1 << shift)
#| }
#| }
#| Node(ns, Some(sizes)) => {
#| let child_shift = shift - NUM_BITS
#| for i, child in ns; offset = 0 {
#| child.eachi(f, child_shift, start + offset)
#| continue sizes[i]
#| }
#| }
#| }
#|}
#|fn[A, B] Tree::fold(
#| self : Tree[A],
#| acc : B,
#| f : (B, A) -> 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 count = (new_t.length() + BRANCHING_FACTOR - 1) / BRANCHING_FACTOR
#| let new_children = FixedArray::makei(count, i => {
#| let lo = i * BRANCHING_FACTOR
#| let hi = min(lo + BRANCHING_FACTOR, new_t.length())
#| let chunk = FixedArray::makei(hi - lo, j => new_t[lo + j])
#| Node(chunk, compute_sizes(chunk, shift - NUM_BITS)) // height H
#| })
#| 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[_])
#| let mut old_leaf_len = 0
#| for i in 0.. Bool {
#| match self {
#| Leaf(_) => true
#| Node(_, None) => true
#| Node(_, Some(_)) => false
#| Empty => false
#| }
#|}
#|fn[A] compute_sizes(
#| children : FixedArray[Tree[A]],
#| shift : Int,
#|) -> 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..)]>,
#| #| Some(),
#| #|)
#| ),
#| )
#| @debug.debug_inspect(
#| Node([Empty, Leaf([42])], Some([0, 1])),
#| content=(
#| #|Node(
#| #| )]>,
#| #| Some(),
#| #|)
#| ),
#| )
#|}
),
"tree_append.mbt": (
#|fn append_sizes_last(sizes : FixedArray[Int]?, delta : Int) -> FixedArray[Int]? {
#| match sizes {
#| Some(sizes) => {
#| let new_sizes = sizes.copy()
#| new_sizes[new_sizes.length() - 1] += delta
#| Some(new_sizes)
#| }
#| None => None
#| }
#|}
#|fn push_sizes_last(sizes : FixedArray[Int]?, delta : Int) -> FixedArray[Int]? {
#| match sizes {
#| Some(sizes) =>
#| Some(immutable_push(sizes, delta + sizes[sizes.length() - 1]))
#| None => None
#| }
#|}
#|fn[T] radix_append_sizes(
#| children : FixedArray[Tree[T]],
#| child_shift : Int,
#| delta : Int,
#|) -> FixedArray[Int]? {
#| if delta == BRANCHING_FACTOR {
#| None
#| } else {
#| compute_sizes(children, child_shift)
#| }
#|}
#|fn[T] Tree::append_right_leaf(
#| self : Tree[T],
#| shift : Int,
#| leaf : FixedArray[T],
#|) -> (Tree[T], Int) {
#| let delta = leaf.length()
#| guard delta > 0 else { return (self, shift) }
#| fn worker(
#| node : Tree[T],
#| shift : Int,
#| leaf : FixedArray[T],
#| delta : Int,
#| ) -> Tree[T]? {
#| match node {
#| Leaf(elems) => {
#| guard shift == 0 else {
#| abort("Unreachable: Leaf should only appear at shift 0")
#| }
#| if elems.length() + delta <= BRANCHING_FACTOR {
#| Some(Leaf(immutable_concat(elems, leaf)))
#| } else {
#| None
#| }
#| }
#| Node(nodes, sizes) => {
#| let len = nodes.length()
#| match worker(nodes[len - 1], shift - NUM_BITS, leaf, delta) {
#| Some(new_node) => {
#| let new_nodes = immutable_set(nodes, len - 1, new_node)
#| let new_sizes = match sizes {
#| Some(_) => append_sizes_last(sizes, delta)
#| None => radix_append_sizes(new_nodes, shift - NUM_BITS, delta)
#| }
#| Some(Node(new_nodes, new_sizes))
#| }
#| None =>
#| if len < BRANCHING_FACTOR {
#| let new_nodes = immutable_push(
#| nodes,
#| new_branch_left(leaf, shift - NUM_BITS),
#| )
#| let new_sizes = match sizes {
#| Some(_) => push_sizes_last(sizes, delta)
#| None => radix_append_sizes(new_nodes, shift - NUM_BITS, delta)
#| }
#| Some(Node(new_nodes, new_sizes))
#| } else {
#| None
#| }
#| }
#| }
#| Empty => Some(Leaf(leaf))
#| }
#| }
#| match worker(self, shift, leaf, delta) {
#| Some(new_tree) => (new_tree, shift)
#| None => {
#| let new_branch = new_branch_left(leaf, shift)
#| let self_radix = match self {
#| Node(_, None) => true
#| Leaf(elems) => elems.length() == BRANCHING_FACTOR
#| Node(_, Some(_)) => false
#| Empty =>
#| abort("Unreachable: Empty tree should have been handled in worker")
#| }
#| let new_sizes : FixedArray[Int]? = if self_radix &&
#| delta == BRANCHING_FACTOR {
#| None
#| } else {
#| let len = self.size(shift)
#| Some([len, len + delta])
#| }
#| (Node([self, new_branch], new_sizes), shift + NUM_BITS)
#| }
#| }
#|}
#|fn[T] Tree::concat_with_suffix(
#| left : Tree[T],
#| left_shift : Int,
#| suffix : FixedArray[T],
#| right : Tree[T],
#| right_shift : Int,
#| top : Bool,
#|) -> (Tree[T], Int) {
#| if suffix.is_empty() {
#| return Tree::concat(left, left_shift, right, right_shift, top)
#| }
#| if left_shift > right_shift {
#| let (c, c_shift) = Tree::concat_with_suffix(
#| left.right_child(),
#| left_shift - NUM_BITS,
#| suffix,
#| right,
#| right_shift,
#| false,
#| )
#| guard! c_shift == left_shift
#| rebalance(left, c, Empty, left_shift, top)
#| } else if right_shift > left_shift {
#| let (c, c_shift) = Tree::concat_with_suffix(
#| left,
#| left_shift,
#| suffix,
#| right.left_child(),
#| right_shift - NUM_BITS,
#| false,
#| )
#| guard! c_shift == right_shift
#| rebalance(Empty, c, right, right_shift, top)
#| } else if left_shift == 0 {
#| let leaves = FixedArray::from_array([left, Leaf(suffix), right])
#| let (node_counts, new_len) = redis_plan(leaves)
#| let new_children = redis(leaves, node_counts, new_len, 0)
#| if top && new_len == 1 {
#| (new_children[0], 0)
#| } else {
#| let node = Node(new_children, compute_sizes(new_children, 0))
#| (node, NUM_BITS)
#| }
#| } else {
#| let (c, c_shift) = Tree::concat_with_suffix(
#| left.right_child(),
#| left_shift - NUM_BITS,
#| suffix,
#| right.left_child(),
#| right_shift - NUM_BITS,
#| false,
#| )
#| guard! c_shift == left_shift
#| guard! c_shift == right_shift
#| rebalance(left, c, right, left_shift, top)
#| }
#|}
),
"tree_pop.mbt": (
#|fn[A] Tree::last_leaf_elements(self : Tree[A]) -> FixedArray[A] {
#| match self {
#| Leaf(leaf) => leaf
#| Node(children, _) => children[children.length() - 1].last_leaf_elements()
#| Empty => abort("Empty tree has no last leaf")
#| }
#|}
#|fn[A] Tree::pop_rightmost_leaf(self : Tree[A], shift : Int) -> Tree[A] {
#| match self {
#| Empty | Leaf(_) => Empty
#| Node(children, _) => {
#| let last_index = children.length() - 1
#| let new_last = children[last_index].pop_rightmost_leaf(shift - NUM_BITS)
#| if new_last is Empty {
#| if last_index == 0 {
#| Empty
#| } else {
#| let new_children = immutable_slice(children, 0, last_index)
#| Node(new_children, compute_sizes(new_children, shift - NUM_BITS))
#| }
#| } else {
#| let new_children = immutable_set(children, last_index, new_last)
#| Node(new_children, compute_sizes(new_children, shift - NUM_BITS))
#| }
#| }
#| }
#|}
#|fn[A] Tree::shrink_top(self : Tree[A], shift : Int) -> (Tree[A], Int) {
#| let mut current_shift = shift
#| for tree = self {
#| match tree {
#| Node(children, _) if current_shift > 0 && children.length() == 1 => {
#| current_shift -= NUM_BITS
#| continue children[0]
#| }
#| Empty => break (Empty, 0)
#| current => break (current, current_shift)
#| }
#| }
#|}
),
"tree_slice.mbt": (
#|fn[A] Tree::slice_right(self : Tree[A], shift : Int, end : Int) -> Tree[A] {
#| guard end > 0 else { return Empty }
#| guard end < self.size(shift) else { return self }
#| match self {
#| Empty => Empty
#| Leaf(leaf) => Leaf(immutable_slice(leaf, 0, end))
#| Node(children, sizes) => {
#| let child_shift = shift - NUM_BITS
#| let child_index = match sizes {
#| Some(sizes) => get_branch_index(sizes, end - 1)
#| None => radix_indexing(end - 1, shift)
#| }
#| let child_start = match sizes {
#| Some(sizes) => if child_index == 0 { 0 } else { sizes[child_index - 1] }
#| None => child_index * (1 << shift)
#| }
#| let new_len = child_index + 1
#| let new_children = FixedArray::make(new_len, children[0])
#| for i in 0.. Tree[A] {
#| guard start > 0 else { return self }
#| match self {
#| Empty => Empty
#| Leaf(leaf) => Leaf(immutable_slice(leaf, start, leaf.length()))
#| Node(children, sizes) => {
#| let child_shift = shift - NUM_BITS
#| let child_index = match sizes {
#| Some(sizes) => get_branch_index(sizes, start)
#| None => radix_indexing(start, shift)
#| }
#| let child_start = match sizes {
#| Some(sizes) =>
#| if child_index == 0 {
#| start
#| } else {
#| start - sizes[child_index - 1]
#| }
#| None => start - child_index * (1 << shift)
#| }
#| let new_len = children.length() - child_index
#| let new_children = FixedArray::make(
#| new_len,
#| children[child_index].slice_left(child_shift, child_start),
#| )
#| for i in 1.. 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 Vector[A] {
#| tree : Tree[A]
#| tail : FixedArray[A]
#| size : Int
#| shift : Int
#|}
#|#unsafe_cycle_free
#|priv enum Tree[A] {
#| Empty
#| Node(FixedArray[Tree[A]], FixedArray[Int]?) // (Subtrees, Sizes of subtrees)
#| Leaf(FixedArray[A])
#|} derive(Eq, @debug.Debug)
),
"utils.mbt": (
#|#owned(v)
#|fn[T] immutable_set(arr : FixedArray[T], i : Int, v : T) -> FixedArray[T] {
#| let arr = arr.copy()
#| arr[i] = v
#| arr
#|}
#|#owned(val)
#|fn[T] immutable_push(arr : FixedArray[T], val : T) -> FixedArray[T] {
#| let len = arr.length()
#| let new_arr = FixedArray::make_and_blit(
#| arr,
#| allocate_len=len + 1,
#| init=val,
#| len~,
#| )
#| new_arr[len] = val
#| new_arr
#|}
#|fn[T] immutable_concat(
#| left : FixedArray[T],
#| right : FixedArray[T],
#|) -> FixedArray[T] {
#| let left_len = left.length()
#| let right_len = right.length()
#| if left_len == 0 {
#| right.copy()
#| } else if right_len == 0 {
#| left.copy()
#| } else {
#| FixedArray::makei(left_len + right_len, i => {
#| if i < left_len {
#| left[i]
#| } else {
#| right[i - left_len]
#| }
#| })
#| }
#|}
#|fn[T] immutable_slice(
#| arr : FixedArray[T],
#| start : Int,
#| end : Int,
#|) -> FixedArray[T] {
#| let len = end - start
#| if len <= 0 {
#| []
#| } else {
#| FixedArray::makei(len, i => arr[start + i])
#| }
#|}
#|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 lo = for lo = 0, hi = sizes.length(); LINEAR_THRESHOLD < hi - lo; {
#| let mid = (lo + hi) / 2
#| if sizes[mid] <= index {
#| continue mid, hi
#| } else {
#| continue lo, mid
#| }
#| } nobreak {
#| lo
#| }
#| for lo = lo; sizes[lo] <= index; {
#| continue lo + 1
#| } nobreak {
#| 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")
#|}
),
"vector.mbt": (
#|#as_free_fn
#|pub fn[A] Vector::new() -> Vector[A] {
#| make_t(Tree::empty(), [], 0, 0)
#|}
#|#as_free_fn
#|#owned(value)
#|pub fn[A] Vector::singleton(value : A) -> Vector[A] {
#| make_t(Tree::empty(), [value], 1, 0)
#|}
#|#as_free_fn
#|#owned(value)
#|pub fn[A] Vector::make(len : Int, value : A) -> Vector[A] {
#| guard len > 0 else { new() }
#| let tail_len = tail_len_of_size(len)
#| let tree_len = len - tail_len
#| let tail = FixedArray::make(tail_len, value)
#| let (tree, shift) = if tree_len == 0 {
#| (Tree::empty(), 0)
#| } else {
#| let leaves = Array::make(
#| tree_len / BRANCHING_FACTOR,
#| FixedArray::make(BRANCHING_FACTOR, value),
#| )
#| let shift = shift_of_leaf_count(leaves.length())
#| (from_leaves(leaves, shift), shift)
#| }
#| make_t(tree, tail, len, shift)
#|}
#|#as_free_fn
#|pub fn[A] Vector::makei(len : Int, f : (Int) -> A raise?) -> Vector[A] raise? {
#| guard len > 0 else { new() }
#| let tail_len = tail_len_of_size(len)
#| let tree_len = len - tail_len
#| let tail = FixedArray::makei(tail_len, i => f(tree_len + i))
#| let (tree, shift) = if tree_len == 0 {
#| (Tree::empty(), 0)
#| } else {
#| let quot = tree_len / BRANCHING_FACTOR
#| let leaves : Array[FixedArray[A]] = Array::make(quot, [])
#| for k in 0.. {
#| f(k * BRANCHING_FACTOR + i)
#| })
#| }
#| let shift = shift_of_leaf_count(leaves.length())
#| (from_leaves(leaves, shift), shift)
#| }
#| make_t(tree, tail, len, shift)
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[A] Vector::Vector(arr : ArrayView[A]) -> Vector[A] {
#| Vector::makei(arr.length(), i => arr[i])
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[A] Vector::from_iter(iter : Iter[A]) -> Vector[A] {
#| let mut buf : FixedArray[A] = []
#| let mut index = 0
#| let leaves = []
#| while iter.next() is Some(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 == 0 {
#| return new()
#| }
#| let tail = if index == BRANCHING_FACTOR {
#| if leaves.is_empty() {
#| buf
#| } else {
#| leaves.push(buf)
#| []
#| }
#| } else {
#| FixedArray::make_and_blit(buf, allocate_len=index, init=buf[0], len=index)
#| }
#| let tree_len = tree_len_of_leaf_count(leaves.length())
#| let (tree, shift) = if tree_len == 0 {
#| (Tree::empty(), 0)
#| } else {
#| let shift = shift_of_leaf_count(leaves.length())
#| (from_leaves(leaves, shift), shift)
#| }
#| make_t(tree, tail, checked_size_add(tree_len, tail.length()), shift)
#|}
#|pub fn[A] Vector::to_array(self : Vector[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] Vector::is_empty(self : Vector[A]) -> Bool {
#| self.size == 0
#|}
#|pub fn[A] Vector::length(self : Vector[A]) -> Int {
#| self.size
#|}
#|fn[A] Vector::tail_offset(self : Vector[A]) -> Int {
#| self.size - self.tail.length()
#|}
#|#alias("_[_]")
#|pub fn[A] Vector::at(self : Vector[A], index : Int) -> A {
#| guard! index >= 0 && index < self.size
#| let tail_offset = self.tail_offset()
#| if index >= tail_offset {
#| self.tail[index - tail_offset]
#| } else {
#| self.tree.get(index, self.shift)
#| }
#|}
#|pub fn[A] Vector::get(self : Vector[A], index : Int) -> A? {
#| guard 0 <= index && index < self.size else { None }
#| Some(self[index])
#|}
#|pub fn[A] Vector::peek(self : Vector[A]) -> A? {
#| if self.size == 0 {
#| None
#| } else {
#| Some(self[self.size - 1])
#| }
#|}
#|pub fn[A : Eq] Vector::contains(self : Vector[A], value : A) -> Bool {
#| if self.tree.contains(value) {
#| return true
#| }
#| self.tail.contains(value)
#|}
#|#owned(value)
#|pub fn[A] Vector::set(self : Vector[A], index : Int, value : A) -> Vector[A] {
#| guard! index >= 0 && index < self.size
#| let tail_len = self.tail.length()
#| if tail_len == 0 {
#| make_t(
#| self.tree.set(index, self.shift, value),
#| self.tail,
#| self.size,
#| self.shift,
#| )
#| } else {
#| let tail_offset = self.tail_offset()
#| if index >= tail_offset {
#| make_t(
#| self.tree,
#| immutable_set(self.tail, index - tail_offset, value),
#| self.size,
#| self.shift,
#| )
#| } else {
#| make_t(
#| self.tree.set(index, self.shift, value),
#| self.tail,
#| self.size,
#| self.shift,
#| )
#| }
#| }
#|}
#|#owned(value)
#|pub fn[A] Vector::push(self : Vector[A], value : A) -> Vector[A] {
#| let size = checked_size_add(self.size, 1)
#| if self.tail.length() < BRANCHING_FACTOR {
#| make_t(self.tree, immutable_push(self.tail, value), size, self.shift)
#| } else {
#| let (tree, shift) = if self.tree is Empty {
#| (Leaf(self.tail), 0)
#| } else {
#| self.tree.append_right_leaf(self.shift, self.tail)
#| }
#| make_t(tree, [value], size, shift)
#| }
#|}
#|pub fn[A] Vector::pop(self : Vector[A]) -> Vector[A]? {
#| if self.size == 0 {
#| None
#| } else if self.size == 1 {
#| Some(new())
#| } else if self.tail.length() > 1 {
#| Some(
#| make_t(
#| self.tree,
#| immutable_slice(self.tail, 0, self.tail.length() - 1),
#| self.size - 1,
#| self.shift,
#| ),
#| )
#| } else if self.tail.length() == 1 {
#| let new_tail = self.tree.last_leaf_elements()
#| let (tree, shift) = self.tree
#| .pop_rightmost_leaf(self.shift)
#| .shrink_top(self.shift)
#| Some(make_t(tree, new_tail, self.size - 1, shift))
#| } else {
#| let last_leaf = self.tree.last_leaf_elements()
#| if last_leaf.length() > 1 {
#| let (tree, shift) = self.tree
#| .pop_rightmost_leaf(self.shift)
#| .shrink_top(self.shift)
#| Some(
#| make_t(
#| tree,
#| immutable_slice(last_leaf, 0, last_leaf.length() - 1),
#| self.size - 1,
#| shift,
#| ),
#| )
#| } else {
#| let stripped = self.tree.pop_rightmost_leaf(self.shift)
#| let (promoted_tree, promoted_shift) = stripped.shrink_top(self.shift)
#| if promoted_tree is Empty {
#| Some(new())
#| } else {
#| let new_tail = promoted_tree.last_leaf_elements()
#| let (tree, shift) = promoted_tree
#| .pop_rightmost_leaf(promoted_shift)
#| .shrink_top(promoted_shift)
#| Some(make_t(tree, new_tail, self.size - 1, shift))
#| }
#| }
#| }
#|}
#|pub fn[A] Vector::concat(self : Vector[A], other : Vector[A]) -> Vector[A] {
#| if self.is_empty() {
#| return other
#| }
#| if other.is_empty() {
#| return self
#| }
#| let size = checked_size_add(self.size, other.size)
#| if other.tree is Empty {
#| let combined_tail_len = self.tail.length() + other.tail.length()
#| if combined_tail_len <= BRANCHING_FACTOR {
#| return make_t(
#| self.tree,
#| immutable_concat(self.tail, other.tail),
#| size,
#| self.shift,
#| )
#| } else if self.tail.is_empty() {
#| return make_t(self.tree, other.tail, size, self.shift)
#| } else {
#| let (tree, shift) = self.normalize_tree()
#| return make_t(tree, other.tail, size, shift)
#| }
#| }
#| let (tree, shift) = if self.tree is Empty {
#| Tree::concat(Leaf(self.tail), 0, other.tree, other.shift, true)
#| } else if self.tail.is_empty() {
#| Tree::concat(self.tree, self.shift, other.tree, other.shift, true)
#| } else {
#| Tree::concat_with_suffix(
#| self.tree,
#| self.shift,
#| self.tail,
#| other.tree,
#| other.shift,
#| true,
#| )
#| }
#| make_t(tree, other.tail, size, shift)
#|}
#|pub fn[A] Vector::split(
#| self : Vector[A],
#| index : Int,
#|) -> (Vector[A], Vector[A]) {
#| guard 0 <= index && index <= self.size else { abort("Index out of bounds") }
#| (self.slice_unchecked(0, index), self.slice_unchecked(index, self.size))
#|}
#|pub fn[A] Vector::take(self : Vector[A], count : Int) -> Vector[A] {
#| let end = if count <= 0 { 0 } else { min(count, self.size) }
#| self.slice_unchecked(0, end)
#|}
#|pub fn[A] Vector::drop(self : Vector[A], count : Int) -> Vector[A] {
#| let start = if count <= 0 { 0 } else { min(count, self.size) }
#| self.slice_unchecked(start, self.size)
#|}
#|pub fn[A] Vector::slice(self : Vector[A], start : Int, end : Int) -> Vector[A] {
#| guard start <= end else { abort("start index greater than end index") }
#| guard 0 <= start && end <= self.size else { abort("Index out of bounds") }
#| self.slice_unchecked(start, end)
#|}
#|pub impl[A] Add for Vector[A] with fn add(self, other) {
#| self.concat(other)
#|}
#|#alias(iterator, deprecated)
#|pub fn[A] Vector::iter(self : Vector[A]) -> Iter[A] {
#| let mut in_tree = true
#| let mut curr_tree = self.tree
#| let mut curr_index = 0
#| let mut curr_leaf : FixedArray[A] = []
#| let mut leaf_index = 0
#| let mut leaf_len = 0
#| let parents = []
#| let mut tail_index = 0
#| let tail_len = self.tail.length()
#| Iter::new(
#| fn() {
#| if leaf_index < leaf_len {
#| let elem = curr_leaf.unsafe_get(leaf_index)
#| leaf_index += 1
#| return Some(elem)
#| }
#| let tree_result = if in_tree {
#| for tree = curr_tree {
#| match tree {
#| Node(children, _) as t if curr_index < children.length() => {
#| let child = children.unsafe_get(curr_index)
#| parents.push((t, curr_index + 1))
#| curr_tree = child
#| curr_index = 0
#| continue child
#| }
#| Leaf(elems) if curr_index < elems.length() => {
#| let len = elems.length()
#| let elem = elems.unsafe_get(curr_index)
#| curr_leaf = elems
#| leaf_len = len
#| leaf_index = curr_index + 1
#| curr_index = len
#| break Some(elem)
#| }
#| _ if parents.pop() is Some((parent_tree, parent_index)) => {
#| curr_tree = parent_tree
#| curr_index = parent_index
#| continue parent_tree
#| }
#| _ => {
#| in_tree = false
#| break None
#| }
#| }
#| }
#| } else {
#| None
#| }
#| match tree_result {
#| Some(_) => tree_result
#| None =>
#| if tail_index < tail_len {
#| let elem = self.tail.unsafe_get(tail_index)
#| tail_index += 1
#| Some(elem)
#| } else {
#| None
#| }
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|pub fn[A] Vector::each(self : Vector[A], f : (A) -> Unit raise?) -> Unit raise? {
#| self.tree.each(f)
#| self.tail.each(f)
#|}
#|pub fn[A] Vector::eachi(
#| self : Vector[A],
#| f : (Int, A) -> Unit raise?,
#|) -> Unit raise? {
#| self.tree.eachi(f, self.shift, 0)
#| let tail_offset = self.tail_offset()
#| for i, x in self.tail {
#| f(tail_offset + i, x)
#| }
#|}
#|#alias(fold_left, deprecated)
#|pub fn[A, B] Vector::fold(
#| self : Vector[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| let acc = self.tree.fold(init, f)
#| self.tail.fold(f, init=acc)
#|}
#|#alias(fold_right, deprecated)
#|pub fn[A, B] Vector::rev_fold(
#| self : Vector[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| let acc = self.tail.rev_fold(f, init~)
#| self.tree.rev_fold(acc, f)
#|}
#|pub fn[A, B] Vector::map(
#| self : Vector[A],
#| f : (A) -> B raise?,
#|) -> Vector[B] raise? {
#| make_t(self.tree.map(f), self.tail.map(f), self.size, self.shift)
#|}
#|pub fn[A] Vector::filter(
#| self : Vector[A],
#| f : (A) -> Bool raise?,
#|) -> Vector[A] raise? {
#| let arr : Array[A] = Array(capacity=self.size)
#| self.each(value => if f(value) { arr.push(value) })
#| from_array(arr)
#|}
#|pub fn[A] Vector::rev(self : Vector[A]) -> Vector[A] {
#| if self.size == 0 {
#| new()
#| } else {
#| let arr = Array::make(self.size, self[0])
#| self.eachi((i, value) => arr[self.size - 1 - i] = value)
#| from_array(arr)
#| }
#|}
#|pub impl[A : Hash] Hash for Vector[A] with fn hash_combine(self, hasher) {
#| for e in self {
#| hasher.combine(e)
#| }
#|}
#|pub impl[A : Eq] Eq for Vector[A] with fn equal(self, other) {
#| if physical_equal(self, other) {
#| true
#| } else if self.size != other.size {
#| false
#| } else {
#| let left = self.iter()
#| let right = other.iter()
#| for _ in 0.. if a != b { return false }
#| _ => return false
#| }
#| }
#| true
#| }
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for Vector[A]
#|pub impl[A : Show] Show for Vector[A] with fn output(self, logger) {
#| logger.write_iter(
#| self.iter(),
#| prefix="@immut/vector.from_array([",
#| suffix="])",
#| )
#|}
#|pub impl[A : ToJson] ToJson for Vector[A] with fn to_json(self) {
#| [
#| for value in self => value
#| ]
#|}
#|pub impl[A : @json.FromJson] @json.FromJson for Vector[A] with fn from_json(
#| json,
#| path,
#|) {
#| guard json is Array(arr) else {
#| raise JsonDecodeError((path, "@immut/vector.from_json: expected array"))
#| }
#| let len = arr.length()
#| guard len != 0 else { return new() }
#| let values : Array[A] = Array(capacity=len)
#| for i, value in arr {
#| values.push(A::from_json(value, path.add_index(i)))
#| }
#| Vector::from_array(values)
#|}
#|pub impl[A : Compare] Compare for Vector[A] with fn 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.. Int {
#| let required = size + added
#| guard required >= size else { abort("Vector capacity overflow") }
#| required
#|}
#|#owned(tree, tail)
#|fn[A] make_t(
#| tree : Tree[A],
#| tail : FixedArray[A],
#| size : Int,
#| shift : Int,
#|) -> Vector[A] {
#| { tree, tail, size, shift, }
#|}
#|fn[A] from_leaves(leaves : ArrayView[FixedArray[A]], shift : Int) -> Tree[A] {
#| guard shift > 0 else { return Leaf(leaves[0]) }
#| let child_shift = shift - NUM_BITS
#| let leaves_per_child = 1 << child_shift
#| let full = leaves.length() / leaves_per_child
#| let len = if leaves.length() % leaves_per_child == 0 {
#| full
#| } else {
#| full + 1
#| }
#| let arr = FixedArray::makei(len, i => {
#| let lo = i * leaves_per_child
#| let hi = min(lo + leaves_per_child, leaves.length())
#| from_leaves(leaves[lo:hi], child_shift)
#| })
#| Node(arr, None)
#|}
#|fn shift_of_leaf_count(leaf_count : Int) -> Int {
#| guard leaf_count >= 0 else { abort("Vector capacity overflow") }
#| for capacity = 1, shift = 0; capacity < leaf_count; {
#| let next = capacity * BRANCHING_FACTOR
#| guard next > capacity else { abort("Vector capacity overflow") }
#| continue next, shift + NUM_BITS
#| } nobreak {
#| shift
#| }
#|}
#|fn tree_len_of_leaf_count(leaf_count : Int) -> Int {
#| guard leaf_count >= 0 else { abort("Vector capacity overflow") }
#| let len = leaf_count * BRANCHING_FACTOR
#| guard len / BRANCHING_FACTOR == leaf_count else {
#| abort("Vector capacity overflow")
#| }
#| len
#|}
#|fn tail_len_of_size(size : Int) -> Int {
#| if size <= BRANCHING_FACTOR {
#| size
#| } else {
#| let rem = size % BRANCHING_FACTOR
#| if rem == 0 {
#| 0
#| } else {
#| rem
#| }
#| }
#|}
#|fn[A] Vector::normalize_tree(self : Vector[A]) -> (Tree[A], Int) {
#| if self.size == 0 {
#| (Tree::empty(), 0)
#| } else if self.tail.is_empty() {
#| (self.tree, self.shift)
#| } else if self.tail_offset() == 0 {
#| (Leaf(self.tail), 0)
#| } else if self.tail.length() == 1 {
#| self.tree.push_end(self.shift, self.tail[0])
#| } else {
#| self.tree.append_right_leaf(self.shift, self.tail)
#| }
#|}
#|fn[A] Vector::slice_unchecked(
#| self : Vector[A],
#| start : Int,
#| end : Int,
#|) -> Vector[A] {
#| let len = end - start
#| if len == 0 {
#| new()
#| } else if start == 0 && end == self.size {
#| self
#| } else {
#| let tail_offset = self.tail_offset()
#| if start >= tail_offset {
#| make_t(
#| Empty,
#| immutable_slice(self.tail, start - tail_offset, end - tail_offset),
#| len,
#| 0,
#| )
#| } else {
#| let tree_end = min(end, tail_offset)
#| let sliced_tree = if tree_end == tail_offset {
#| self.tree
#| } else {
#| self.tree.slice_right(self.shift, tree_end)
#| }
#| let sliced_tree = if start == 0 {
#| sliced_tree
#| } else {
#| sliced_tree.slice_left(self.shift, start)
#| }
#| let (tree, shift) = sliced_tree.shrink_top(self.shift)
#| let tail = if end > tail_offset {
#| immutable_slice(self.tail, 0, end - tail_offset)
#| } else {
#| []
#| }
#| make_t(tree, tail, len, shift)
#| }
#| }
#|}
),
},
)
///|
let moonbitlang_core_immut_vector_map_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/immut/vector_map",
deps={},
files={
"extends.mbt": (
#|pub extend VectorMap with Eq::{equal}
#|pub extend VectorMap with Hash::{hash}
#|#deprecated("Use `Json(x)` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend VectorMap with ToJson::{to_json}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend VectorMap with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend VectorMap with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend VectorMap with Hash::{hash_combine}
#|#deprecated("Use `@json.from_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend VectorMap with @json.FromJson::{from_json}
),
"iter.mbt": (
#|pub fn[K, V] VectorMap::each(
#| self : VectorMap[K, V],
#| f : (K, V) -> Unit raise?,
#|) -> Unit raise? {
#| self.spine.each(entry => if entry is Some((k, v)) { f(k, v) })
#|}
#|pub fn[K, V] VectorMap::eachi(
#| self : VectorMap[K, V],
#| f : (Int, K, V) -> Unit raise?,
#|) -> Unit raise? {
#| let mut i = 0
#| self.spine.each(entry => {
#| if entry is Some((k, v)) {
#| f(i, k, v)
#| i += 1
#| }
#| })
#|}
#|#alias(iterator, deprecated)
#|pub fn[K, V] VectorMap::iter(self : VectorMap[K, V]) -> Iter[(K, V)] {
#| self.spine.iter().filter_map(entry => entry)
#|}
#|#alias(iterator2, deprecated)
#|pub fn[K, V] VectorMap::iter2(self : VectorMap[K, V]) -> Iter2[K, V] {
#| self.iter()
#|}
#|pub fn[K, V] VectorMap::keys(self : VectorMap[K, V]) -> Iter[K] {
#| self.iter().map(kv => kv.0)
#|}
#|#alias(elems, deprecated)
#|pub fn[K, V] VectorMap::values(self : VectorMap[K, V]) -> Iter[V] {
#| self.iter().map(kv => kv.1)
#|}
#|pub fn[K, V, A] VectorMap::fold(
#| self : VectorMap[K, V],
#| init~ : A,
#| f : (A, K, V) -> A raise?,
#|) -> A raise? {
#| self.spine.fold(init~, (acc, entry) => {
#| match entry {
#| Some((k, v)) => f(acc, k, v)
#| None => acc
#| }
#| })
#|}
#|pub fn[K, V] VectorMap::to_array(self : VectorMap[K, V]) -> Array[(K, V)] {
#| let result : Array[(K, V)] = Array(capacity=self.size)
#| self.each((k, v) => result.push((k, v)))
#| result
#|}
#|#alias(map_with_key, deprecated)
#|pub fn[K, V, A] VectorMap::map(
#| self : VectorMap[K, V],
#| f : (K, V) -> A raise?,
#|) -> VectorMap[K, A] raise? {
#| {
#| index: self.index,
#| spine: self.spine.map(entry => {
#| match entry {
#| Some((k, v)) => Some((k, f(k, v)))
#| None => None
#| }
#| }),
#| size: self.size,
#| }
#|}
#|#alias(filter_with_key, deprecated)
#|pub fn[K, V] VectorMap::filter(
#| self : VectorMap[K, V],
#| pred : (K, V) -> Bool raise?,
#|) -> VectorMap[K, V] raise? {
#| let remap = FixedArray::make(self.spine.length(), -1)
#| let kept : Array[(K, V)?] = []
#| self.spine.eachi((slot, entry) => {
#| if entry is Some((k, v)) {
#| if pred(k, v) {
#| remap[slot] = kept.length()
#| kept.push(entry)
#| }
#| }
#| })
#| if kept.length() == self.size {
#| return self
#| }
#| {
#| index: self.index
#| .filter((_, slot) => remap[slot] >= 0)
#| .map((_, slot) => remap[slot]),
#| spine: @vector.from_iter(kept.iter()),
#| size: kept.length(),
#| }
#|}
),
"traits_impl.mbt": (
#|pub impl[K : Eq, V : Eq] Eq for VectorMap[K, V] with fn equal(self, other) {
#| if physical_equal(self, other) {
#| return true
#| }
#| guard self.size == other.size else { return false }
#| let left = self.iter()
#| let right = other.iter()
#| for _ in 0.. (Repr(k), Repr(v)) ]),
#| )
#|}
#|pub impl[K : ToJson, V : ToJson] ToJson for VectorMap[K, V] with fn to_json(
#| self,
#|) {
#| [
#| for k, v in self => ([k, v] : Json)
#| ]
#|}
#|pub impl[K : @json.FromJson + Eq + Hash, V : @json.FromJson] @json.FromJson for VectorMap[
#| K,
#| V,
#|] with fn from_json(json, path) {
#| guard json is Array(pairs) else {
#| raise JsonDecodeError((path, "@immut/vector_map.from_json: expected array"))
#| }
#| let entries : Array[(K, V)] = Array(capacity=pairs.length())
#| for i, pair in pairs {
#| let entry_path = path.add_index(i)
#| guard pair is Array([key, value]) else {
#| raise JsonDecodeError(
#| (entry_path, "@immut/vector_map.from_json: expected [key, value] pair"),
#| )
#| }
#| entries.push(
#| (
#| @json.FromJson::from_json(key, entry_path.add_index(0)),
#| @json.FromJson::from_json(value, entry_path.add_index(1)),
#| ),
#| )
#| }
#| from_pairs(entries.iter())
#|}
),
"types.mbt": (
#|struct VectorMap[K, V] {
#| index : @hashmap.HashMap[K, Int]
#| spine : @vector.Vector[(K, V)?]
#| size : Int
#|}
#|const MIN_COMPACT_LENGTH : Int = 32
),
"vector_map.mbt": (
#|#as_free_fn
#|pub fn[K, V] VectorMap::new() -> VectorMap[K, V] {
#| { index: @hashmap.new(), spine: @vector.new(), size: 0, }
#|}
#|#as_free_fn
#|pub fn[K : Hash, V] VectorMap::singleton(key : K, value : V) -> VectorMap[K, V] {
#| {
#| index: @hashmap.singleton(key, 0),
#| spine: @vector.singleton(Some((key, value))),
#| size: 1,
#| }
#|}
#|pub fn[K : Eq + Hash, V] VectorMap::VectorMap(
#| arr : ArrayView[(K, V)],
#|) -> VectorMap[K, V] {
#| from_pairs(arr.iter())
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[K : Eq + Hash, V] VectorMap::from_iter(
#| iter : Iter[(K, V)],
#|) -> VectorMap[K, V] {
#| from_pairs(iter)
#|}
#|fn[K : Eq + Hash, V] from_pairs(iter : Iter[(K, V)]) -> VectorMap[K, V] {
#| let entries : Array[(K, V)] = []
#| let mut index : @hashmap.HashMap[K, Int] = @hashmap.new()
#| for kv in iter {
#| let (key, value) = kv
#| match index.get(key) {
#| Some(slot) => entries[slot] = (entries[slot].0, value)
#| None => {
#| index = index.add(key, entries.length())
#| entries.push((key, value))
#| }
#| }
#| }
#| {
#| index,
#| spine: @vector.from_iter(entries.iter().map(kv => Some(kv))),
#| size: entries.length(),
#| }
#|}
#|#alias(size, deprecated)
#|pub fn[K, V] VectorMap::length(self : VectorMap[K, V]) -> Int {
#| self.size
#|}
#|pub fn[K, V] VectorMap::is_empty(self : VectorMap[K, V]) -> Bool {
#| self.size == 0
#|}
#|#alias(find, deprecated)
#|pub fn[K : Eq + Hash, V] VectorMap::get(self : VectorMap[K, V], key : K) -> V? {
#| guard self.index.get(key) is Some(slot) else { return None }
#| guard self.spine.get(slot) is Some(Some((_, value))) else { return None }
#| Some(value)
#|}
#|#alias("_[_]")
#|pub fn[K : Eq + Hash, V] VectorMap::at(self : VectorMap[K, V], key : K) -> V {
#| guard! self.get(key) is Some(value)
#| value
#|}
#|pub fn[K : Eq + Hash, V] VectorMap::contains(
#| self : VectorMap[K, V],
#| key : K,
#|) -> Bool {
#| self.index.contains(key)
#|}
#|pub fn[K : Eq + Hash, V] VectorMap::add(
#| self : VectorMap[K, V],
#| key : K,
#| value : V,
#|) -> VectorMap[K, V] {
#| match self.index.get(key) {
#| Some(slot) => {
#| guard! self.spine.get(slot) is Some(Some((old_key, _)))
#| {
#| index: self.index,
#| spine: self.spine.set(slot, Some((old_key, value))),
#| size: self.size,
#| }
#| }
#| None => {
#| let map = {
#| index: self.index.add(key, self.spine.length()),
#| spine: self.spine.push(Some((key, value))),
#| size: self.size + 1,
#| }
#| if map.should_compact() {
#| map.compact()
#| } else {
#| map
#| }
#| }
#| }
#|}
#|pub fn[K : Eq + Hash, V] VectorMap::remove(
#| self : VectorMap[K, V],
#| key : K,
#|) -> VectorMap[K, V] {
#| guard self.index.get(key) is Some(slot) else { return self }
#| let map = {
#| index: self.index.remove(key),
#| spine: trim_trailing(self.spine.set(slot, None)),
#| size: self.size - 1,
#| }
#| if map.should_compact() {
#| map.compact()
#| } else {
#| map
#| }
#|}
#|pub fn[K : Eq + Hash, V] VectorMap::update(
#| self : VectorMap[K, V],
#| key : K,
#| f : (V?) -> V? raise?,
#|) -> VectorMap[K, V] raise? {
#| match f(self.get(key)) {
#| Some(value) => self.add(key, value)
#| None => self.remove(key)
#| }
#|}
#|fn[K, V] trim_trailing(
#| spine : @vector.Vector[(K, V)?],
#|) -> @vector.Vector[(K, V)?] {
#| for s = spine {
#| guard s.peek() is Some(None) else { break s }
#| guard s.pop() is Some(rest) else { break s }
#| continue rest
#| }
#|}
#|fn[K, V] VectorMap::should_compact(self : VectorMap[K, V]) -> Bool {
#| let length = self.spine.length()
#| length >= MIN_COMPACT_LENGTH && length - self.size > self.size
#|}
#|fn[K, V] VectorMap::compact(self : VectorMap[K, V]) -> VectorMap[K, V] {
#| let remap = FixedArray::make(self.spine.length(), 0)
#| let kept : Array[(K, V)?] = Array(capacity=self.size)
#| self.spine.eachi((slot, entry) => {
#| if entry is Some(_) {
#| remap[slot] = kept.length()
#| kept.push(entry)
#| }
#| })
#| {
#| index: self.index.map((_, slot) => remap[slot]),
#| spine: @vector.from_iter(kept.iter()),
#| size: kept.length(),
#| }
#|}
),
},
)
///|
let moonbitlang_core_int_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/int",
deps={},
files={
"int.mbt": (
#|pub const MAX_VALUE = 2147483647
#|#deprecated("Use `MAX_VALUE` instead")
#|pub let max_value = 2147483647
#|pub const MIN_VALUE = -2147483648
#|#deprecated("Use `MIN_VALUE` instead")
#|pub let min_value = -2147483648
#|#deprecated("Use Int::abs instead")
#|pub fn abs(x : Int) -> Int {
#| Int::abs(x)
#|}
#|#deprecated
#|#doc(hidden)
#|pub fn Int::to_be_bytes(self : Int) -> Bytes {
#| let self = self.reinterpret_as_uint()
#| [
#| (self >> 24).to_byte(),
#| (self >> 16).to_byte(),
#| (self >> 8).to_byte(),
#| self.to_byte(),
#| ]
#|}
#|#deprecated
#|#doc(hidden)
#|pub fn Int::to_le_bytes(self : Int) -> Bytes {
#| let self = self.reinterpret_as_uint()
#| [
#| self.to_byte(),
#| (self >> 8).to_byte(),
#| (self >> 16).to_byte(),
#| (self >> 24).to_byte(),
#| ]
#|}
),
},
)
///|
let moonbitlang_core_int16_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/int16",
deps={},
files={
"extends.mbt": (
#|pub extend Int16 with Add::{add}
#|pub extend Int16 with BitAnd::{land}
#|pub extend Int16 with BitOr::{lor}
#|pub extend Int16 with BitXOr::{lxor}
#|pub extend Int16 with Compare::{compare}
#|pub extend Int16 with Div::{div}
#|pub extend Int16 with Eq::{equal}
#|pub extend Int16 with Hash::{hash}
#|pub extend Int16 with Mod::{mod}
#|pub extend Int16 with Mul::{mul}
#|pub extend Int16 with Neg::{neg}
#|pub extend Int16 with Shl::{shl}
#|pub extend Int16 with Shr::{shr}
#|pub extend Int16 with Sub::{sub}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int16 with Compare::{op_ge, op_gt, op_le, op_lt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int16 with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int16 with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int16 with Hash::{hash_combine}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int16 with Show::{output}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Int16 with ToJson::{to_json}
),
"int16.mbt": (
#|pub const MAX_VALUE : Int16 = 32767
#|#deprecated("Use `MAX_VALUE` instead")
#|pub let max_value : Int16 = 32767
#|pub const MIN_VALUE : Int16 = -32768
#|#deprecated("Use `MIN_VALUE` instead")
#|pub let min_value : Int16 = -32768
#|pub impl Add for Int16 with fn add(self : Int16, that : Int16) -> Int16 {
#| Int16::from_int(self.to_int() + that.to_int())
#|}
#|pub impl Sub for Int16 with fn sub(self : Int16, that : Int16) -> Int16 {
#| Int16::from_int(self.to_int() - that.to_int())
#|}
#|pub impl Mul for Int16 with fn mul(self : Int16, that : Int16) -> Int16 {
#| Int16::from_int(self.to_int() * that.to_int())
#|}
#|pub impl Div for Int16 with fn div(self : Int16, that : Int16) -> Int16 {
#| Int16::from_int(self.to_int() / that.to_int())
#|}
#|pub impl Mod for Int16 with fn mod(self : Int16, that : Int16) -> Int16 {
#| Int16::from_int(self.to_int() % that.to_int())
#|}
#|pub impl Eq for Int16 with fn equal(self, that) {
#| self.to_int() == that.to_int()
#|}
#|pub impl Eq for Int16 with fn not_equal(self, that) {
#| self.to_int() != that.to_int()
#|}
#|pub impl Compare for Int16 with fn compare(self, that) {
#| self.to_int().compare(that.to_int())
#|}
#|pub impl Compare for Int16 with fn op_lt(x, y) {
#| x.to_int() < y.to_int()
#|}
#|pub impl Compare for Int16 with fn op_le(x, y) {
#| x.to_int() <= y.to_int()
#|}
#|pub impl Compare for Int16 with fn op_gt(x, y) {
#| x.to_int() > y.to_int()
#|}
#|pub impl Compare for Int16 with fn op_ge(x, y) {
#| x.to_int() >= y.to_int()
#|}
#|pub impl Hash for Int16 with fn hash_combine(self, hasher) {
#| hasher.combine_int(self.to_int())
#|}
#|pub impl Shl for Int16 with fn shl(self : Int16, that : Int) -> Int16 {
#| Int16::from_int(self.to_int() << that)
#|}
#|pub impl Shr for Int16 with fn shr(self : Int16, that : Int) -> Int16 {
#| Int16::from_int(self.to_int() >> that)
#|}
#|pub impl BitOr for Int16 with fn lor(self : Int16, that : Int16) -> Int16 {
#| Int16::from_int(self.to_int() | that.to_int())
#|}
#|pub impl BitAnd for Int16 with fn land(self : Int16, that : Int16) -> Int16 {
#| Int16::from_int(self.to_int() & that.to_int())
#|}
#|pub impl BitXOr for Int16 with fn lxor(self : Int16, that : Int16) -> Int16 {
#| Int16::from_int(self.to_int() ^ that.to_int())
#|}
#|pub fn Int16::lnot(self : Int16) -> Int16 {
#| Int16::from_int(self.to_int().lnot())
#|}
#|pub impl Neg for Int16 with fn neg(self : Int16) -> Int16 {
#| Int16::from_int(-self.to_int())
#|}
#|pub fn Int16::abs(self : Int16) -> Int16 {
#| if self < 0 {
#| -self
#| } else {
#| self
#| }
#|}
#|pub impl Default for Int16 with fn default() {
#| 0
#|}
#|pub impl ToJson for Int16 with fn to_json(self : Int16) -> Json {
#| Json::number(self.to_int().to_double())
#|}
#|pub impl Show for Int16 with fn to_string(self) {
#| Int16::to_string(self)
#|}
#|pub fn Int16::reinterpret_as_uint16(self : Int16) -> UInt16 {
#| self.to_int().to_uint16()
#|}
#|pub fn Int16::reinterpret_from_uint16(self : UInt16) -> Int16 {
#| Int16::from_int(self.to_int())
#|}
#|pub fn Int16::from_int(self : Int) -> Int16 = "%i32_to_i16"
#|pub fn Int16::from_byte(self : Byte) -> Int16 = "%byte_to_i16"
#|#cfg(not(target="js"))
#|pub fn Int16::from_int64(self : Int64) -> Int16 = "%i64_to_i16"
#|#cfg(target="js")
#|pub fn Int16::from_int64(self : Int64) -> Int16 {
#| Int16::from_int(self.to_int())
#|}
#|#cfg(target="js")
#|pub fn Int16::to_int64(self : Int16) -> Int64 {
#| self.to_int().to_int64()
#|}
#|#cfg(not(target="js"))
#|pub fn Int16::to_int64(self : Int16) -> Int64 = "%i16_to_i64"
#|pub fn Int16::to_int(self : Int16) -> Int = "%i16_to_i32"
#|pub fn Int16::to_byte(self : Int16) -> Byte = "%i16_to_byte"
#|pub fn Int16::to_string(self : Int16, radix? : Int = 10) -> String {
#| self.to_int().to_string(radix~)
#|}
),
},
)
///|
let moonbitlang_core_int64_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/int64",
deps={},
files={
"int64.mbt": (
#|pub const MAX_VALUE = 9223372036854775807L
#|#deprecated("Use `MAX_VALUE` instead")
#|pub let max_value = 9223372036854775807L
#|pub const MIN_VALUE = -9223372036854775808L
#|#deprecated("Use `MIN_VALUE` instead")
#|pub let min_value = -9223372036854775808L
#|#deprecated("Use Int64::from_int instead")
#|#doc(hidden)
#|pub fn from_int(i : Int) -> Int64 {
#| i.to_int64()
#|}
#|#deprecated("Use Int64::abs instead")
#|#doc(hidden)
#|pub fn abs(x : Int64) -> Int64 {
#| Int64::abs(x)
#|}
#|#deprecated
#|#doc(hidden)
#|pub fn Int64::to_be_bytes(self : Int64) -> Bytes {
#| self.reinterpret_as_uint64().to_be_bytes()
#|}
#|#deprecated
#|#doc(hidden)
#|pub fn Int64::to_le_bytes(self : Int64) -> Bytes {
#| self.reinterpret_as_uint64().to_le_bytes()
#|}
#|#deprecated("Use `Int16::from_int64` instead")
#|pub fn Int64::to_int16(self : Int64) -> Int16 {
#| Int16::from_int64(self)
#|}
),
},
)
///|
let moonbitlang_core_internal_edit_distance_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/internal/edit_distance",
deps={},
files={
"edit_distance.mbt": (
#|priv trait LevInput {
#| fn a_length(Self) -> Int
#| fn b_length(Self) -> Int
#| fn eq(Self, Int, Int) -> Bool
#|}
#|priv struct ViewPair[T] {
#| a : ArrayView[T]
#| b : ArrayView[T]
#|}
#|impl[T : Eq] LevInput for ViewPair[T] with fn a_length(self) {
#| self.a.length()
#|}
#|impl[T : Eq] LevInput for ViewPair[T] with fn b_length(self) {
#| self.b.length()
#|}
#|impl[T : Eq] LevInput for ViewPair[T] with fn eq(self, i, j) {
#| self.a[i] == self.b[j]
#|}
#|priv struct StrPair {
#| a : StringView
#| b : StringView
#|}
#|impl LevInput for StrPair with fn a_length(self) {
#| self.a.length()
#|}
#|impl LevInput for StrPair with fn b_length(self) {
#| self.b.length()
#|}
#|impl LevInput for StrPair with fn eq(self, i, j) {
#| self.a[i] == self.b[j]
#|}
#|fn[S : LevInput] lev_distance(s : S) -> Int {
#| let alen = s.a_length()
#| let blen = s.b_length()
#| let mut p = 0
#| while p < blen && s.eq(p, p) {
#| p += 1
#| }
#| let mut suffix = 0
#| while suffix < blen - p && s.eq(alen - 1 - suffix, blen - 1 - suffix) {
#| suffix += 1
#| }
#| let m = alen - p - suffix
#| let n = blen - p - suffix
#| if n == 0 {
#| return m
#| }
#| guard m < @int.MAX_VALUE else { abort("edit_distance: input too large") }
#| let mut prev = FixedArray::makei(n + 1, j => j)
#| let mut cur = FixedArray::make(n + 1, 0)
#| for i0 in 0.. Int? {
#| let alen = s.a_length()
#| let blen = s.b_length()
#| let mut p = 0
#| while p < blen && s.eq(p, p) {
#| p += 1
#| }
#| let mut suffix = 0
#| while suffix < blen - p && s.eq(alen - 1 - suffix, blen - 1 - suffix) {
#| suffix += 1
#| }
#| let m = alen - p - suffix
#| let n = blen - p - suffix
#| if m - n > max_distance {
#| return None
#| }
#| if max_distance >= m {
#| return Some(lev_distance(s))
#| }
#| guard m < @int.MAX_VALUE else {
#| abort("edit_distance_within: input too large")
#| }
#| let k = max_distance
#| let inf = k + 1
#| let mut prev = FixedArray::makei(n + 1, j => if j <= k { j } else { inf })
#| let mut cur = FixedArray::make(n + 1, inf)
#| for i0 in 0.. 1 { i - k } else { 1 }
#| let hi = if k >= n - i { n } else { i + k }
#| cur[lo - 1] = if lo == 1 && i <= k { i } else { inf }
#| let mut row_min = inf
#| for j in lo..<(hi + 1) {
#| let sub = prev[j - 1] + (if s.eq(p + i - 1, p + j - 1) { 0 } else { 1 })
#| let del = prev[j] + 1
#| let ins = cur[j - 1] + 1
#| let mut best = sub
#| if del < best {
#| best = del
#| }
#| if ins < best {
#| best = ins
#| }
#| if best > inf {
#| best = inf
#| }
#| cur[j] = best
#| if best < row_min {
#| row_min = best
#| }
#| }
#| if row_min > k {
#| return None
#| }
#| if hi < n {
#| cur[hi + 1] = inf
#| }
#| let t = prev
#| prev = cur
#| cur = t
#| }
#| if prev[n] <= k {
#| Some(prev[n])
#| } else {
#| None
#| }
#|}
#|pub fn[T : Eq] edit_distance(a : ArrayView[T], b : ArrayView[T]) -> Int {
#| let (a, b) = if a.length() >= b.length() { (a, b) } else { (b, a) }
#| let s : ViewPair[T] = { a, b, }
#| lev_distance(s)
#|}
#|pub fn[T : Eq] edit_distance_within(
#| a : ArrayView[T],
#| b : ArrayView[T],
#| max_distance~ : Int,
#|) -> Int? {
#| if max_distance < 0 {
#| return None
#| }
#| let (a, b) = if a.length() >= b.length() { (a, b) } else { (b, a) }
#| let s : ViewPair[T] = { a, b, }
#| lev_within(s, max_distance)
#|}
#|pub fn edit_distance_str(a : StringView, b : StringView) -> Int {
#| let (a, b) = if a.length() >= b.length() { (a, b) } else { (b, a) }
#| let s : StrPair = { a, b, }
#| lev_distance(s)
#|}
#|pub fn edit_distance_str_within(
#| a : StringView,
#| b : StringView,
#| max_distance~ : Int,
#|) -> Int? {
#| if max_distance < 0 {
#| return None
#| }
#| let (a, b) = if a.length() >= b.length() { (a, b) } else { (b, a) }
#| let s : StrPair = { a, b, }
#| lev_within(s, max_distance)
#|}
),
},
)
///|
let moonbitlang_core_internal_os_string_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/internal/os_string",
deps={},
files={
"os_string.mbt": (
#|#cfg(any(not(target="native"), platform="windows"))
#|struct OsString(String)
#|#cfg(all(target="native", not(platform="windows")))
#|struct OsString(Bytes)
#|#cfg(any(not(target="native"), platform="windows"))
#|pub impl Show for OsString with fn to_string(self) {
#| self.0
#|}
#|#cfg(all(target="native", not(platform="windows")))
#|pub impl Show for OsString with fn to_string(self) {
#| @utf8.decode_lossy(self.0)
#|}
#|#deprecated
#|pub extend OsString with @builtin.Show::{output}
#|pub extend OsString with @builtin.Show::{to_string}
#|#cfg(any(not(target="native"), platform="windows"))
#|pub fn OsString::from_string(str : StringView) -> OsString {
#| OsString(str.to_owned())
#|}
#|#cfg(all(target="native", not(platform="windows")))
#|pub fn OsString::from_string(str : StringView) -> OsString {
#| OsString(@utf8.encode(str))
#|}
#|#cfg(any(not(target="native"), platform="windows"))
#|let _unused_import : Unit = ignore(@utf8.encode(""))
),
},
)
///|
let moonbitlang_core_internal_regex_engine_automata_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/internal/regex_engine/automata",
deps={},
files={
"context.mbt": (
#|struct Context {
#| mut next_expr_id : Int
#| mut book : SlotBook
#| mut book_dirty : Bool
#|}
#|#alias(new, deprecated="Use `Context()` instead")
#|pub fn Context::Context() -> Context {
#| {
#| next_expr_id: EXPR_ID_RESERVED + 1,
#| book: SlotBook::empty(),
#| book_dirty: false,
#| }
#|}
#|fn Context::new_expr_id(ctx : Context) -> ExprId {
#| let id = ctx.next_expr_id
#| ctx.next_expr_id += 1
#| id
#|}
),
"delta.mbt": (
#|#valtype
#|priv struct DeltaContext {
#| c : @shared_types.Rechar
#| prev_cat : @shared_types.Category
#| next_cat : @shared_types.Category
#|}
#|fn delta_rep(
#| outer : Expr,
#| mode : @shared_types.QuantifierMode,
#| pref : @shared_types.Preference,
#| inner : Expr,
#| c : DeltaContext,
#| marks : MarkSlotMap,
#|) -> ThreadSet {
#| let inner_delta = delta_expr(inner, c, marks)
#| let first_match_marks = inner_delta.find_first_match()
#| match mode {
#| Greedy => {
#| let (marks, inner_delta) = match first_match_marks {
#| None => (marks, inner_delta)
#| Some(marks) => (marks, inner_delta.remove_matches())
#| }
#| ts_seq(pref, inner_delta, outer) + ts_end(marks)
#| }
#| NonGreedy =>
#| ts_end(marks) + ts_seq(pref, inner_delta.remove_matches(), outer)
#| }
#|}
#|fn delta_expr(expr : Expr, c : DeltaContext, marks : MarkSlotMap) -> ThreadSet {
#| match expr.def {
#| Chr(cs) => if cs.contains(c.c) { ts_exp(marks, e_eps) } else { ts_empty }
#| Alt(exprs) =>
#| exprs.fold(init=ts_empty, (acc, expr) => acc + delta_expr(expr, c, marks))
#| Seq(pref, first, next) => {
#| let first_delta = delta_expr(first, c, marks)
#| delta_seq(pref, first_delta, next, c)
#| }
#| Rep(mode, pref, body) => delta_rep(expr, mode, pref, body, c, marks)
#| Eps => ts_end(marks)
#| Mark(mark) => ts_end(marks.add_mark(mark))
#| Before(cat) =>
#| if @shared_types.Category::intersects(c.next_cat, cat) {
#| ts_end(marks)
#| } else {
#| ts_empty
#| }
#| After(cat) =>
#| if @shared_types.Category::intersects(c.prev_cat, cat) {
#| ts_end(marks)
#| } else {
#| ts_empty
#| }
#| }
#|}
#|fn delta_seq(
#| pref : @shared_types.Preference,
#| first : ThreadSet,
#| next : Expr,
#| c : DeltaContext,
#|) -> ThreadSet {
#| match first.find_first_match() {
#| None => ts_seq(pref, first, next)
#| Some(marks) =>
#| match pref {
#| Longest =>
#| ts_seq(pref, first.remove_matches(), next) +
#| delta_expr(next, c, marks)
#| Shortest =>
#| delta_expr(next, c, marks) +
#| ts_seq(pref, first.remove_matches(), next)
#| First => {
#| let (until_first_match, after_first_match) = first.split_at_first_match()
#| ts_seq(pref, until_first_match, next) +
#| delta_expr(next, c, marks) +
#| ts_seq(pref, after_first_match.remove_matches(), next)
#| }
#| }
#| }
#|}
#|fn delta_thread(
#| thread : Thread,
#| c : DeltaContext,
#| marks : MarkSlotMap,
#|) -> ThreadSet {
#| match thread {
#| End(_) => ts_one(thread)
#| Exp(marks, expr) => delta_expr(expr, c, marks)
#| Seq(pref, first, next) => {
#| let first_delta = delta_threads(first, c, marks)
#| delta_seq(pref, first_delta, next, c)
#| }
#| }
#|}
#|fn delta_threads(
#| curr : ThreadSet,
#| c : DeltaContext,
#| marks : MarkSlotMap,
#|) -> ThreadSet {
#| curr.flat_map(thread => delta_thread(thread, c, marks))
#|}
#|fn find_slot(ctx~ : Context, desc : ThreadSet) -> Slot {
#| if ctx.book_dirty {
#| ctx.book.clear()
#| }
#| let has_unassigned_slots = for
#| marks in desc.iter_marks()
#| has_unassigned_slots = false {
#| for _mark, slot in marks; has_unassigned_slots = has_unassigned_slots {
#| if slot.is_assigned() {
#| ctx.book.mark_used(slot)
#| continue has_unassigned_slots
#| } else {
#| continue true
#| }
#| } nobreak {
#| continue has_unassigned_slots
#| }
#| } nobreak {
#| has_unassigned_slots
#| }
#| if !has_unassigned_slots {
#| Slot::unassigned()
#| } else {
#| let slot = ctx.book.find_unused()
#| if ctx.book.need_grow(slot) {
#| ctx.book = ctx.book.grow()
#| ctx.book_dirty = false
#| } else {
#| ctx.book_dirty = true
#| }
#| slot
#| }
#|}
#|pub fn delta(
#| ctx~ : Context,
#| state : State,
#| c : @shared_types.Rechar,
#| next_cat~ : @shared_types.Category,
#|) -> State {
#| let prev_cat = state.cat
#| let desc = delta_threads(
#| state.desc,
#| { prev_cat, next_cat, c, },
#| MarkSlotMap::empty(),
#| )
#| let desc = desc.remove_duplicates(e_eps)
#| let slot = find_slot(ctx~, desc)
#| let desc = if slot.is_assigned() { desc.assign_slot(slot) } else { desc }
#| State::new(slot, next_cat, desc)
#|}
),
"expr.mbt": (
#|struct Expr {
#| id : ExprId
#| def : ExprDef
#|}
#|type ExprId = Int
#|const EXPR_ID_EMPTY : ExprId = 0
#|const EXPR_ID_EPS : ExprId = 1
#|const EXPR_ID_RESERVED : ExprId = 1
#|priv enum ExprDef {
#| Chr(@shared_types.RecharSet)
#| Alt(Array[Expr])
#| Seq(@shared_types.Preference, Expr, Expr)
#| Rep(@shared_types.QuantifierMode, @shared_types.Preference, Expr)
#| Eps
#| Mark(Mark)
#| Before(@shared_types.Category)
#| After(@shared_types.Category)
#|}
#|impl Eq for Expr with fn equal(self, other) {
#| self.id == other.id
#|}
#|impl Hash for Expr with fn hash_combine(self, hasher) {
#| hasher.combine(self.id)
#|}
#|pub fn e_copy(ctx~ : Context, e : Expr) -> Expr {
#| match e.def {
#| Chr(c) => e_cset(ctx~, c)
#| Alt(xs) => e_alt(ctx~, xs.map(x => e_copy(ctx~, x)))
#| Seq(pref, x, y) => e_seq(ctx~, pref, e_copy(ctx~, x), e_copy(ctx~, y))
#| Rep(mode, pref, x) => e_rep(ctx~, mode, pref, e_copy(ctx~, x))
#| Eps => e_eps
#| Mark(m) => e_mark(ctx~, m)
#| Before(cat) => e_before(ctx~, cat)
#| After(cat) => e_after(ctx~, cat)
#| }
#|}
#|let e_empty : Expr = { id: EXPR_ID_EMPTY, def: Alt([]), }
#|pub let e_eps : Expr = { id: EXPR_ID_EPS, def: Eps, }
#|pub fn is_eps(e : Expr) -> Bool {
#| e.def is Eps
#|}
#|pub fn e_cset(ctx~ : Context, c : @shared_types.RecharSet) -> Expr {
#| if c.is_empty() {
#| e_empty
#| } else {
#| { id: ctx.new_expr_id(), def: Chr(c), }
#| }
#|}
#|pub fn e_rep(
#| ctx~ : Context,
#| mode : @shared_types.QuantifierMode,
#| pref : @shared_types.Preference,
#| x : Expr,
#|) -> Expr {
#| { id: ctx.new_expr_id(), def: Rep(mode, pref, x), }
#|}
#|pub fn e_mark(ctx~ : Context, m : Mark) -> Expr {
#| { id: ctx.new_expr_id(), def: Mark(m), }
#|}
#|pub fn e_before(ctx~ : Context, cat : @shared_types.Category) -> Expr {
#| { id: ctx.new_expr_id(), def: Before(cat), }
#|}
#|pub fn e_after(ctx~ : Context, cat : @shared_types.Category) -> Expr {
#| { id: ctx.new_expr_id(), def: After(cat), }
#|}
#|pub fn e_alt(ctx~ : Context, xs : Array[Expr]) -> Expr {
#| match xs {
#| [x] | ([] with x = e_empty) => x
#| xs => { id: ctx.new_expr_id(), def: Alt(xs), }
#| }
#|}
#|pub fn e_seq(
#| ctx~ : Context,
#| pref : @shared_types.Preference,
#| x : Expr,
#| y : Expr,
#|) -> Expr {
#| match (x.def, y.def) {
#| (Alt([]), _) => x
#| (_, Alt([])) => y
#| (Eps, _) => y
#| (_, Eps) if pref is First => x
#| _ => { id: ctx.new_expr_id(), def: Seq(pref, x, y), }
#| }
#|}
),
"extends.mbt": (
#|pub extend Mark with Compare::{compare}
#|pub extend Mark with Eq::{equal}
#|pub extend Mark with Hash::{hash}
#|pub extend MarkSlotMap with Eq::{equal}
#|pub extend MarkSlotMap with Hash::{hash}
#|pub extend Slot with Eq::{equal}
#|pub extend Slot with Hash::{hash}
#|pub extend State with Eq::{equal}
#|pub extend State with Hash::{hash}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Mark with Compare::{op_ge, op_gt, op_le, op_lt}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Mark with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Mark with Hash::{hash_combine}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend MarkSlotMap with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend MarkSlotMap with Hash::{hash_combine}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Slot with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Slot with Hash::{hash_combine}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend State with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend State with Hash::{hash_combine}
),
"mark.mbt": (
#|pub(all) struct Mark(Int) derive(Eq, Hash, Compare)
),
"mark_slot_map.mbt": (
#|struct MarkSlotMap(@immut/sorted_map.SortedMap[Mark, Slot]) derive(Eq, Hash)
#|fn MarkSlotMap::empty() -> MarkSlotMap {
#| MarkSlotMap(@immut/sorted_map.SortedMap::new())
#|}
#|fn MarkSlotMap::add_mark(self : MarkSlotMap, mark : Mark) -> MarkSlotMap {
#| MarkSlotMap(self.0.add(mark, Slot::unassigned()))
#|}
#|fn MarkSlotMap::assign_slot(self : MarkSlotMap, slot : Slot) -> MarkSlotMap {
#| MarkSlotMap(
#| self.0.map((_mark, prev_slot) => {
#| if prev_slot.is_assigned() {
#| prev_slot
#| } else {
#| slot
#| }
#| }),
#| )
#|}
#|pub fn MarkSlotMap::get_slot(self : MarkSlotMap, mark : Mark) -> Slot {
#| match self.0.get(mark) {
#| None => Slot::unassigned()
#| Some(slot) => slot
#| }
#|}
#|pub fn MarkSlotMap::iter2(self : MarkSlotMap) -> Iter2[Mark, Slot] {
#| self.0.iter2()
#|}
),
"slot.mbt": (
#|#valtype
#|pub struct Slot {
#| index : Int
#|} derive(Eq, Hash)
#|pub fn Slot::from_index(index : Int) -> Slot {
#| { index, }
#|}
#|pub fn Slot::unassigned() -> Slot {
#| { index: 0, }
#|}
#|pub fn Slot::is_assigned(self : Slot) -> Bool {
#| self.index > 0
#|}
),
"slot_book.mbt": (
#|priv struct SlotBook(FixedArray[Int])
#|fn SlotBook::empty() -> SlotBook {
#| let book = FixedArray::make(4, 0)
#| book[0] = 1 // Reserve index 0 as unassigned slot
#| SlotBook(book)
#|}
#|fn SlotBook::mark_used(self : SlotBook, slot : Slot) -> Unit {
#| debug_assert(() => slot.is_assigned())
#| let index = slot.index / 32
#| let bit = slot.index % 32
#| self.0[index] = self.0[index] | (1 << bit)
#|}
#|fn SlotBook::find_unused(self : SlotBook) -> Slot {
#| for i, word in self.0 {
#| if word != -1 {
#| let bit = word.lnot().ctz()
#| return Slot::from_index(i * 32 + bit)
#| }
#| }
#| Slot::from_index(self.0.length() * 32)
#|}
#|fn SlotBook::clear(self : SlotBook) -> Unit {
#| self.0.fill(0)
#| self.0[0] = 1 // Reserve index 0 as unassigned slot
#|}
#|fn next_pow_of_two(n : Int) -> Int {
#| if n <= 1 {
#| 1
#| } else {
#| guard n <= 0x40000000 else { panic() }
#| 1 << (32 - (n - 1).clz())
#| }
#|}
#|fn SlotBook::need_grow(self : SlotBook, slot : Slot) -> Bool {
#| slot.index >= 32 * self.0.length()
#|}
#|fn SlotBook::grow(self : SlotBook) -> SlotBook {
#| let book = FixedArray::make(next_pow_of_two(self.0.length() + 1), 0)
#| book[0] = 1 // Reserve index 0 as unassigned slot
#| SlotBook(book)
#|}
),
"state.mbt": (
#|pub struct State {
#| priv slot : Slot
#| priv cat : @shared_types.Category
#| priv desc : ThreadSet
#| priv hash : Int
#|}
#|pub let st_dummy : State = {
#| slot: Slot::unassigned(),
#| cat: @shared_types.Category::dummy(),
#| desc: ts_empty,
#| hash: -1,
#|}
#|pub enum Status {
#| Failed
#| Match(MarkSlotMap)
#| Running
#|}
#|pub impl Eq for State with fn equal(self, other) {
#| self.hash == other.hash &&
#| self.slot == other.slot &&
#| self.cat == other.cat &&
#| self.desc == other.desc
#|}
#|pub impl Hash for State with fn hash_combine(self, hasher) {
#| hasher.combine(self.hash)
#|}
#|fn State::new(
#| slot : Slot,
#| cat : @shared_types.Category,
#| desc : ThreadSet,
#|) -> State {
#| { slot, cat, desc, hash: Hash::hash((slot, cat, desc)), }
#|}
#|pub fn State::start(cat : @shared_types.Category, expr : Expr) -> State {
#| State::new(Slot::unassigned(), cat, ts_exp(MarkSlotMap::empty(), expr))
#|}
#|pub fn State::slot(self : State) -> Slot {
#| self.slot
#|}
#|pub fn State::status(self : State) -> Status {
#| match self.desc.first() {
#| None => Failed
#| Some(End(marks)) => Match(marks)
#| Some(Exp(_) | Seq(_)) => Running
#| }
#|}
),
"thread.mbt": (
#|priv enum Thread {
#| End(MarkSlotMap)
#| Exp(MarkSlotMap, Expr)
#| Seq(@shared_types.Preference, ThreadSet, Expr)
#|} derive(Eq, Hash)
),
"thread_set.mbt": (
#|priv enum ThreadSet {
#| Empty
#| Node(
#| i~ : ThreadSetNodeInfo,
#| l~ : ThreadSet,
#| t~ : Thread,
#| r~ : ThreadSet,
#| p~ : Int
#| )
#|}
#|#valtype
#|priv struct ThreadSetNodeInfo {
#| no_match : Bool
#|}
#|fn ThreadSet::is_empty(self : ThreadSet) -> Bool {
#| self is Empty
#|}
#|fn ThreadSet::is_singleton(self : ThreadSet) -> Bool {
#| self is Node(l=Empty, r=Empty, ..)
#|}
#|fn ThreadSet::first(self : ThreadSet) -> Thread? {
#| match self {
#| Empty => None
#| Node(l=Empty, t~, ..) => Some(t)
#| Node(l~, ..) => l.first()
#| }
#|}
#|fn ThreadSet::choose(self : ThreadSet) -> Thread {
#| match self {
#| Node(l=Empty, t~, r=Empty, ..) => t
#| _ => panic()
#| }
#|}
#|fn ThreadSet::no_match(self : ThreadSet) -> Bool {
#| match self {
#| Empty => true
#| Node(i~, ..) => i.no_match
#| }
#|}
#|fn ThreadSet::make_node(
#| l : ThreadSet,
#| t : Thread,
#| r : ThreadSet,
#| p~ : Int,
#|) -> ThreadSet {
#| let i = ThreadSetNodeInfo::{
#| no_match: !(t is End(_)) && l.no_match() && r.no_match(),
#| }
#| Node(i~, t~, l~, r~, p~)
#|}
#|let rand_state : @ref.Ref[Int] = Ref(0)
#|fn rand_int() -> Int {
#| rand_state.val = rand_state.val * 1664525 + 1013904223
#| rand_state.val
#|}
#|fn ThreadSet::singleton(t : Thread) -> ThreadSet {
#| ThreadSet::make_node(Empty, t, Empty, p=rand_int())
#|}
#|fn ThreadSet::merge(l : ThreadSet, r : ThreadSet) -> ThreadSet {
#| match (l, r) {
#| (Empty, r) => r
#| (l, Empty) => l
#| (Node(..) as l, Node(..) as r) =>
#| if l.p > r.p {
#| ThreadSet::make_node(l.l, l.t, ThreadSet::merge(l.r, r), p=l.p)
#| } else {
#| ThreadSet::make_node(ThreadSet::merge(l, r.l), r.t, r.r, p=r.p)
#| }
#| }
#|}
#|impl Add for ThreadSet with fn add(self, other) {
#| ThreadSet::merge(self, other)
#|}
#|fn ThreadSet::flat_map(
#| self : ThreadSet,
#| f : (Thread) -> ThreadSet,
#|) -> ThreadSet {
#| match self {
#| Empty => Empty
#| Node(l~, t~, r~, ..) => {
#| let l2 = l.flat_map(f)
#| let t2 = f(t)
#| let r2 = r.flat_map(f)
#| l2 + t2 + r2
#| }
#| }
#|}
#|fn ThreadSet::find_first_match(self : ThreadSet) -> MarkSlotMap? {
#| match self {
#| Empty | Node(i={ no_match: true, }, ..) => None
#| Node(l=Empty, t=End(marks), ..) => Some(marks)
#| Node(l~, t~, r~, ..) =>
#| match l.find_first_match() {
#| Some(marks) => Some(marks)
#| None =>
#| match t {
#| End(marks) => Some(marks)
#| Exp(_) | Seq(_) => r.find_first_match()
#| }
#| }
#| }
#|}
#|fn ThreadSet::remove_matches(self : ThreadSet) -> ThreadSet {
#| match self {
#| Empty => Empty
#| Node(i={ no_match: true, }, ..) => self
#| Node(l~, t~, r~, p~, ..) =>
#| match t {
#| End(_) => l.remove_matches() + r.remove_matches()
#| Exp(_) | Seq(_) =>
#| ThreadSet::make_node(l.remove_matches(), t, r.remove_matches(), p~)
#| }
#| }
#|}
#|fn ThreadSet::split_at_first_match(self : ThreadSet) -> (ThreadSet, ThreadSet) {
#| match self {
#| Empty => (Empty, Empty)
#| Node(i={ no_match: true, }, ..) => (self, Empty)
#| Node(l=Empty | Node(i={ no_match: true, }, ..) as l, t=End(_), r~, ..) =>
#| (l, r)
#| Node(
#| l=Empty
#| | Node(i={ no_match: true, }, ..) as l,
#| t=Exp(_)
#| | Seq(_) as t,
#| r~,
#| p~,
#| ..
#| ) => {
#| let (r1, r2) = r.split_at_first_match()
#| (ThreadSet::make_node(l, t, r1, p~), r2)
#| }
#| Node(l=Node(i={ no_match: false, }, ..) as l, t~, r~, p~, ..) => {
#| let (l1, l2) = l.split_at_first_match()
#| (l1, ThreadSet::make_node(l2, t, r, p~))
#| }
#| }
#|}
#|fn ThreadSet::remove_duplicates(self : ThreadSet, next : Expr) -> ThreadSet {
#| let seen = @hashset.HashSet([])
#| self.remove_duplicates_with_seen(next, seen)
#|}
#|fn ThreadSet::remove_duplicates_with_seen(
#| self : ThreadSet,
#| next : Expr,
#| seen : @hashset.HashSet[ExprId],
#|) -> ThreadSet {
#| for thread in self; result = ts_empty {
#| match thread {
#| End(_) => break result + ts_one(thread)
#| Exp(_, { def: Eps, .. }) =>
#| if !seen.contains(next.id) {
#| seen.add(next.id)
#| continue result + ts_one(thread)
#| } else {
#| continue result
#| }
#| Exp(_, { id, .. }) =>
#| if !seen.contains(id) {
#| seen.add(id)
#| continue result + ts_one(thread)
#| } else {
#| continue result
#| }
#| Seq(pref, first, next) => {
#| let first_dedup = first.remove_duplicates_with_seen(next, seen)
#| continue result + ts_seq(pref, first_dedup, next)
#| }
#| }
#| } nobreak {
#| result
#| }
#|}
#|fn ThreadSet::assign_slot(desc : ThreadSet, slot : Slot) -> ThreadSet {
#| guard slot.is_assigned() else { panic() }
#| desc.map(thread => {
#| match thread {
#| End(marks) => End(marks.assign_slot(slot))
#| Exp(marks, expr) => Exp(marks.assign_slot(slot), expr)
#| Seq(pref, first, next) => Seq(pref, first.assign_slot(slot), next)
#| }
#| })
#|}
#|fn ThreadSet::iter(self : ThreadSet) -> Iter[Thread] {
#| let mut node = self
#| let parents = []
#| Iter::new(() => {
#| for curr = node {
#| match curr {
#| Node(t=thread, l=Empty, r=right, ..) => {
#| node = right
#| break Some(thread)
#| }
#| Node(t=thread, l=left, r=right, ..) => {
#| parents.push((thread, right))
#| continue left
#| }
#| Empty if parents.pop() is Some((thread, right)) => {
#| node = right
#| break Some(thread)
#| }
#| Empty => break None
#| }
#| }
#| })
#|}
#|fn ThreadSet::iter_marks(self : ThreadSet) -> Iter[MarkSlotMap] {
#| self
#| .iter()
#| .flat_map(thread => {
#| match thread {
#| End(marks) | Exp(marks, _) => [|marks|]
#| Seq(_pref, first, _next) => first.iter_marks()
#| }
#| })
#|}
#|fn ThreadSet::map(self : ThreadSet, f : (Thread) -> Thread) -> ThreadSet {
#| match self {
#| Empty => Empty
#| Node(l~, t~, r~, p~, ..) => {
#| let l2 = l.map(f)
#| let b2 = f(t)
#| let r2 = r.map(f)
#| ThreadSet::make_node(l2, b2, r2, p~)
#| }
#| }
#|}
#|let ts_empty : ThreadSet = Empty
#|fn ts_one(t : Thread) -> ThreadSet {
#| ThreadSet::singleton(t)
#|}
#|fn ts_end(marks : MarkSlotMap) -> ThreadSet {
#| ts_one(End(marks))
#|}
#|fn ts_exp(marks : MarkSlotMap, expr : Expr) -> ThreadSet {
#| ts_one(Exp(marks, expr))
#|}
#|fn ts_seq(
#| pref : @shared_types.Preference,
#| first : ThreadSet,
#| next : Expr,
#|) -> ThreadSet {
#| if first.is_empty() {
#| ts_empty
#| } else if first.is_singleton() &&
#| first.choose() is Exp(marks, { def: Eps, .. }) {
#| ts_exp(marks, next)
#| } else {
#| ts_one(Seq(pref, first, next))
#| }
#|}
#|impl Eq for ThreadSet with fn equal(self, other) {
#| let it1 = self.iter()
#| let it2 = other.iter()
#| for v1 = it1.next(), v2 = it2.next() {
#| match (v1, v2) {
#| (None, None) => break true
#| (None, Some(_)) | (Some(_), None) => break false
#| (Some(b1), Some(b2)) =>
#| if b1 == b2 {
#| continue it1.next(), it2.next()
#| } else {
#| break false
#| }
#| }
#| }
#|}
#|impl Hash for ThreadSet with fn hash_combine(self, hasher) {
#| for thread in self {
#| hasher.combine(thread)
#| }
#|}
),
"using.mbt": "",
},
)
///|
let moonbitlang_core_internal_regex_engine_shared_types_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/internal/regex_engine/shared_types",
deps={},
files={
"category.mbt": (
#|pub struct Category(Int) derive(Eq, Hash)
#|pub fn Category::dummy() -> Category {
#| Category(-1)
#|}
#|pub fn Category::inexistant() -> Category {
#| Category(1)
#|}
#|pub fn Category::word() -> Category {
#| Category(2)
#|}
#|pub fn Category::not_word_start() -> Category {
#| Category(4)
#|}
#|pub fn Category::not_word_end() -> Category {
#| Category(8)
#|}
#|pub fn Category::not_word() -> Category {
#| Category(4 | 8)
#|}
#|pub fn Category::newline() -> Category {
#| Category(16)
#|}
#|pub fn Category::inexistant_or_newline() -> Category {
#| Category(1 | 16)
#|}
#|pub fn Category::inexistant_or_non_word_start() -> Category {
#| Category(1 | 4)
#|}
#|pub fn Category::inexistant_or_non_word_end() -> Category {
#| Category(1 | 8)
#|}
#|pub impl Add for Category with fn add(cat1, cat2) {
#| Category(cat1.0 | cat2.0)
#|}
#|pub fn Category::intersects(a : Category, b : Category) -> Bool {
#| (a.0 & b.0) != 0
#|}
),
"extends.mbt": (
#|pub extend Category with Add::{add}
#|pub extend Category with Eq::{equal}
#|pub extend Category with Hash::{hash}
#|pub extend Preference with Eq::{equal}
#|pub extend Preference with Hash::{hash}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Category with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Category with Hash::{hash_combine}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Preference with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Preference with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Preference with Hash::{hash_combine}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend QuantifierMode with @debug.Debug::{to_repr}
),
"preference.mbt": (
#|pub(all) enum Preference {
#| Shortest
#| Longest
#| First
#|} derive(Eq, Hash, @debug.Debug)
),
"profile.mbt": (
#|pub struct Profile {
#| lb : Rechar
#| ub : Rechar
#| valid : RecharSet
#| word : RecharSet
#| word_symbolize_splits : ReadOnlyArray[RecharSet]
#| category : (Rechar) -> Category
#|}
#|#alias(new, deprecated="Use `Profile()` instead")
#|pub fn Profile::Profile(
#| valid~ : RecharSet,
#| word~ : RecharSet,
#| word_symbolize_splits? : ReadOnlyArray[RecharSet] = [word],
#| category~ : (Rechar) -> Category,
#|) -> Profile {
#| guard valid.first_interval() is Some((lb, _)) else { panic() }
#| guard valid.last_interval() is Some((_, ub)) else { panic() }
#| { lb, ub, valid, word, word_symbolize_splits, category, }
#|}
),
"quantifier_mode.mbt": (
#|pub(all) enum QuantifierMode {
#| Greedy
#| NonGreedy
#|} derive(@debug.Debug)
),
"rechar.mbt": (
#|pub using @rechar_set {type Rechar}
),
"rechar_set.mbt": (
#|pub using @rechar_set {type RecharSet}
),
"using.mbt": "",
},
)
///|
let moonbitlang_core_internal_regex_engine_shared_types_rechar_set_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/internal/regex_engine/shared_types/rechar_set",
deps={},
files={
"extends.mbt": (
#|pub extend RecharSet with Add::{add}
#|pub extend RecharSet with BitAnd::{land}
#|pub extend RecharSet with Sub::{sub}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend RecharSet with @debug.Debug::{to_repr}
),
"rechar.mbt": (
#|pub type Rechar = Int
),
"rechar_set.mbt": (
#|struct RecharSet(Tree)
#|pub fn RecharSet::empty() -> RecharSet {
#| RecharSet(Empty)
#|}
#|pub fn RecharSet::char(c : Rechar) -> RecharSet {
#| RecharSet(nn(Empty, c, c, Empty))
#|}
#|pub fn RecharSet::char_range(lo : Rechar, hi : Rechar) -> RecharSet {
#| guard lo <= hi else { panic() }
#| RecharSet(nn(Empty, lo, hi, Empty))
#|}
#|pub fn RecharSet::is_empty(self : RecharSet) -> Bool {
#| self.0 is Empty
#|}
#|pub fn RecharSet::is_subset(self : RecharSet, other : RecharSet) -> Bool {
#| difference(self.0, other.0) is Empty
#|}
#|pub fn RecharSet::first_interval(self : RecharSet) -> (Rechar, Rechar)? {
#| leftmost(self.0)
#|}
#|pub fn RecharSet::last_interval(self : RecharSet) -> (Rechar, Rechar)? {
#| rightmost(self.0)
#|}
#|pub fn RecharSet::contains(self : RecharSet, c : Rechar) -> Bool {
#| for node = self.0 {
#| match node {
#| Empty => break false
#| Node(l~, lo~, hi~, r~, ..) =>
#| if c < lo {
#| continue l
#| } else if c > hi {
#| continue r
#| } else {
#| break true
#| }
#| }
#| }
#|}
#|fn slice_from(t : Tree, c : Rechar) -> Tree {
#| match t {
#| Empty => Empty
#| Node(l~, lo~, hi~, r~, ..) =>
#| if c < lo {
#| bal(slice_from(l, c), lo, hi, r)
#| } else if c > hi {
#| slice_from(r, c)
#| } else {
#| bal(Empty, c, hi, r)
#| }
#| }
#|}
#|fn slice_until(t : Tree, c : Rechar) -> Tree {
#| match t {
#| Empty => Empty
#| Node(l~, lo~, hi~, r~, ..) =>
#| if c < lo {
#| slice_until(l, c)
#| } else if c > hi {
#| bal(l, lo, hi, slice_until(r, c))
#| } else {
#| bal(l, lo, c, Empty)
#| }
#| }
#|}
#|fn slice_before(t : Tree, c : Rechar) -> Tree {
#| if c - 1 >= c {
#| Empty
#| } else {
#| slice_until(t, c - 1)
#| }
#|}
#|fn slice_after(tree : Tree, c : Rechar) -> Tree {
#| if c + 1 <= c {
#| Empty
#| } else {
#| slice_from(tree, c + 1)
#| }
#|}
#|fn leftmost(t : Tree) -> (Rechar, Rechar)? {
#| for cur = t {
#| match cur {
#| Empty => break None
#| Node(l=Empty, lo~, hi~, ..) => break Some((lo, hi))
#| Node(l~, ..) => continue l
#| }
#| }
#|}
#|fn rightmost(t : Tree) -> (Rechar, Rechar)? {
#| for cur = t {
#| match cur {
#| Empty => break None
#| Node(lo~, hi~, r=Empty, ..) => break Some((lo, hi))
#| Node(r~, ..) => continue r
#| }
#| }
#|}
#|fn try_merge_left(lo : Rechar, t : Tree) -> (Rechar, Tree) {
#| fn remove_leftmost(t : Tree) -> Tree {
#| match t {
#| Empty => panic()
#| Node(l=Empty, r~, ..) => r
#| Node(l~, lo~, hi~, r~, ..) => bal(remove_leftmost(l), lo, hi, r)
#| }
#| }
#| if leftmost(t) is Some((lo2, hi2)) && hi2 + 1 >= lo {
#| (lo2, remove_leftmost(t))
#| } else {
#| (lo, t)
#| }
#|}
#|fn try_merge_right(hi : Rechar, t : Tree) -> (Rechar, Tree) {
#| fn remove_rightmost(t : Tree) -> Tree {
#| match t {
#| Empty => panic()
#| Node(l~, r=Empty, ..) => l
#| Node(l~, lo~, hi~, r~, ..) => bal(l, lo, hi, remove_rightmost(r))
#| }
#| }
#| if rightmost(t) is Some((lo2, hi2)) && lo2 - 1 <= hi {
#| (hi2, remove_rightmost(t))
#| } else {
#| (hi, t)
#| }
#|}
#|fn union(t1 : Tree, t2 : Tree) -> Tree {
#| match (t1, t2) {
#| (Empty, t) | (t, Empty) => t
#| (Node(w=w1, ..), Node(w=w2, ..)) => {
#| let (larger, smaller) = if w1 >= w2 { (t1, t2) } else { (t2, t1) }
#| guard larger is Node(l~, lo~, hi~, r~, ..) else { panic() }
#| let (lo, l) = {
#| let p = lo - 1
#| if p >= lo {
#| (lo, Empty)
#| } else {
#| let l = union(l, slice_before(smaller, lo))
#| try_merge_left(lo, l)
#| }
#| }
#| let (hi, r) = {
#| let s = hi + 1
#| if s <= hi {
#| (hi, Empty)
#| } else {
#| let r = union(r, slice_after(smaller, hi))
#| try_merge_right(hi, r)
#| }
#| }
#| bal(l, lo, hi, r)
#| }
#| }
#|}
#|fn intersection(t1 : Tree, t2 : Tree) -> Tree {
#| match (t1, t2) {
#| (Empty, _) | (_, Empty) => Empty
#| (Node(w=w1, ..), Node(w=w2, ..)) => {
#| let (larger, smaller) = if w1 >= w2 { (t1, t2) } else { (t2, t1) }
#| guard larger is Node(l~, lo~, hi~, r~, ..) else { panic() }
#| let left = intersection(l, slice_before(smaller, lo))
#| let right = intersection(r, slice_after(smaller, hi))
#| let middle = slice_until(slice_from(smaller, lo), hi)
#| cat(left, cat(middle, right))
#| }
#| }
#|}
#|fn complement(t : Tree) -> Tree {
#| fn aux(lo : Rechar, hi : Rechar, t : Tree) -> Tree {
#| match t {
#| Empty => nn(Empty, lo, hi, Empty)
#| Node(l~, lo=ilo, hi=ihi, r~, ..) => {
#| let left = {
#| let p = ilo - 1
#| if p < ilo {
#| aux(lo, p, l)
#| } else {
#| Empty
#| }
#| }
#| let right = {
#| let s = ihi + 1
#| if s > ihi {
#| aux(s, hi, r)
#| } else {
#| Empty
#| }
#| }
#| cat(left, right)
#| }
#| }
#| }
#| aux(-0x80000000, 0x7FFFFFFF, t)
#|}
#|fn difference(t1 : Tree, t2 : Tree) -> Tree {
#| intersection(t1, complement(t2))
#|}
#|pub fn RecharSet::union(self : RecharSet, other : RecharSet) -> RecharSet {
#| RecharSet(union(self.0, other.0))
#|}
#|pub fn RecharSet::intersection(
#| self : RecharSet,
#| other : RecharSet,
#|) -> RecharSet {
#| RecharSet(intersection(self.0, other.0))
#|}
#|pub fn RecharSet::difference(self : RecharSet, other : RecharSet) -> RecharSet {
#| RecharSet(difference(self.0, other.0))
#|}
#|pub fn RecharSet::offset_by(self : RecharSet, f : (Int) -> Int) -> RecharSet {
#| fn aux(t : Tree) -> Tree {
#| match t {
#| Empty => Empty
#| Node(l~, lo~, hi~, r~, ..) => bal(aux(l), f(lo), f(hi), aux(r))
#| }
#| }
#| RecharSet(aux(self.0))
#|}
#|pub fn RecharSet::intervals(self : RecharSet) -> Iter[(Rechar, Rechar)] {
#| let mut node = self.0
#| let parents = []
#| Iter::new(fn() {
#| for curr = node {
#| match curr {
#| Node(l=Empty, lo~, hi~, r~, ..) => {
#| node = r
#| break Some((lo, hi))
#| }
#| Node(l~, lo~, hi~, r~, ..) => {
#| parents.push((lo, hi, r))
#| continue l
#| }
#| Empty if parents.pop() is Some((lo, hi, r)) => {
#| node = r
#| break Some((lo, hi))
#| }
#| Empty => break None
#| }
#| }
#| })
#|}
#|pub fn RecharSet::from_sorted_array(
#| arr : ArrayView[(Rechar, Rechar)],
#|) -> RecharSet {
#| RecharSet(build(arr, 0, arr.length() - 1))
#|}
#|pub impl Add for RecharSet with fn add(self, other) {
#| RecharSet::union(self, other)
#|}
#|pub impl Sub for RecharSet with fn sub(self, other) {
#| RecharSet::difference(self, other)
#|}
#|pub impl BitAnd for RecharSet with fn land(self, other) {
#| RecharSet::intersection(self, other)
#|}
#|pub impl @debug.Debug for RecharSet with fn to_repr(self) {
#| Repr(self.intervals().to_array())
#|}
),
"tree.mbt": (
#|priv enum Tree {
#| Empty
#| Node(l~ : Tree, lo~ : Rechar, hi~ : Rechar, r~ : Tree, w~ : Int)
#|}
#|#inline
#|fn nw(tree : Tree) -> Int {
#| match tree {
#| Empty => 1
#| Node(..) as n => n.w
#| }
#|}
#|#inline
#|fn nnw(l : Tree, lo : Rechar, hi : Rechar, r : Tree, w : Int) -> Tree {
#| Node(l~, lo~, hi~, r~, w~)
#|}
#|#inline
#|fn nn(l : Tree, lo : Rechar, hi : Rechar, r : Tree) -> Tree {
#| nnw(l, lo, hi, r, nw(l) + nw(r))
#|}
#|fn bal(l : Tree, lo : Rechar, hi : Rechar, r : Tree) -> Tree {
#| let lw = nw(l)
#| let rw = nw(r)
#| if rw > 3 * lw {
#| guard r is (Node(..) as r) else { panic() }
#| let rlw = nw(r.l)
#| let rrw = nw(r.r)
#| if rlw < 2 * rrw {
#| let lw = lw + rlw
#| nnw(nnw(l, lo, hi, r.l, lw), r.lo, r.hi, r.r, lw + rrw)
#| } else {
#| guard r.l is (Node(..) as rl) else { panic() }
#| let lw = lw + rlw
#| let rw = nw(rl.r) + rrw
#| nnw(
#| nnw(l, lo, hi, rl.l, lw),
#| rl.lo,
#| rl.hi,
#| nnw(rl.r, r.lo, r.hi, r.r, rw),
#| lw + rw,
#| )
#| }
#| } else if lw > 3 * rw {
#| guard l is (Node(..) as l) else { panic() }
#| let llw = nw(l.l)
#| let lrw = nw(l.r)
#| if lrw < 2 * llw {
#| let rw = rw + lrw
#| nnw(l.l, l.lo, l.hi, nnw(l.r, lo, hi, r, lrw + rw), llw + rw)
#| } else {
#| guard l.r is (Node(..) as lr) else { panic() }
#| let lw = nw(lr.l) + llw
#| let rw = rw + lrw
#| nnw(
#| nnw(l.l, l.lo, l.hi, lr.l, lw),
#| lr.lo,
#| lr.hi,
#| nnw(lr.r, lo, hi, r, rw),
#| lw + rw,
#| )
#| }
#| } else {
#| nn(l, lo, hi, r)
#| }
#|}
#|fn cat(l : Tree, r : Tree) -> Tree {
#| match (l, r) {
#| (Empty, r) => r
#| (l, Empty) => l
#| (Node(..) as l, Node(..) as r) => {
#| fn go(r : Tree) -> Tree {
#| match r {
#| Empty => panic()
#| Node(l=Empty, lo~, hi~, r~, ..) => nn(l, lo, hi, r)
#| Node(l=Node(_) as l, lo~, hi~, r~, ..) => bal(go(l), lo, hi, r)
#| }
#| }
#| go(r)
#| }
#| }
#|}
#|fn build(arr : ArrayView[(Rechar, Rechar)], lo : Int, hi : Int) -> Tree {
#| if lo > hi {
#| Empty
#| } else if lo == hi {
#| let (l, h) = arr[lo]
#| nn(Empty, l, h, Empty)
#| } else {
#| let mid = (lo + hi) / 2
#| let (l, h) = arr[mid]
#| let left = build(arr, lo, mid - 1)
#| let right = build(arr, mid + 1, hi)
#| nn(left, l, h, right)
#| }
#|}
),
},
)
///|
let moonbitlang_core_internal_strconv_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/internal/strconv",
deps={},
files={
"strconv_bool.mbt": (
#|pub fn parse_bool(str : StringView) -> Bool raise {
#| lexmatch str with longest {
#| re"^(true|TRUE|True|t|T|1)$" => true
#| re"^(false|FALSE|False|f|F|0)$" => 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 t in tests {
#| @test.assert_eq(
#| Result::Ok(parse_bool(t.0)) catch {
#| Failure::Failure(err) => Err(err)
#| err => Err(err.to_string())
#| },
#| t.1,
#| )
#| }
#|}
),
"strconv_decimal.mbt": (
#|let max_shift = 59
#|priv struct Decimal {
#| digits : FixedArray[Byte]
#| mut digits_num : Int
#| mut decimal_point : Int
#| mut negative : Bool
#| mut truncated : Bool
#| mut overflowed : Int
#|}
#|let powtab : ReadOnlyArray[Int] = [
#| 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, b'\x00'),
#| digits_num: 0,
#| decimal_point: 0,
#| negative: false,
#| truncated: false,
#| overflowed: 0,
#| }
#|}
#|fn Decimal::from_int64_priv(v : Int64) -> Decimal {
#| let d = Decimal::new_priv()
#| d.assign(v)
#| d
#|}
#|fn parse_decimal_priv(str : StringView) -> Decimal raise {
#| parse_decimal_from_view(str)
#|}
#|fn parse_decimal_from_view(str : StringView) -> Decimal raise {
#| 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 = for rest = rest {
#| match 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 !has_dp {
#| d.overflowed += 1
#| }
#| if digit != '0' {
#| d.truncated = true
#| }
#| }
#| continue rest
#| }
#| rest => break 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 effective_dp = d.decimal_point + d.overflowed
#| let exp_limit = if exp_sign > 0 {
#| if effective_dp < 311 {
#| 311 - effective_dp
#| } else {
#| 0
#| }
#| } else if effective_dp > -331 {
#| effective_dp + 331
#| } else {
#| 0
#| }
#| let mut exp = 0
#| let rest = for rest = rest {
#| match rest {
#| ['_', .. rest] => continue rest
#| ['0'..='9' as digit, .. rest] => {
#| if exp < exp_limit {
#| exp = exp * 10 + (digit.to_int() - '0')
#| if exp > exp_limit {
#| exp = exp_limit
#| }
#| }
#| continue rest
#| }
#| rest => break rest
#| }
#| }
#| d.decimal_point += exp_sign * exp
#| rest
#| }
#| rest => rest
#| }
#| guard rest is [] else { syntax_err() }
#| d.trim()
#| d
#|}
#|fn Decimal::to_double_priv(self : Decimal) -> Double raise {
#| let mut exponent = 0
#| let mut mantissa = 0L
#| let effective_dp = self.decimal_point + self.overflowed
#| if self.digits_num == 0 || effective_dp < -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()
#| }
#| self.decimal_point += self.overflowed
#| 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 Decimal::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 Decimal::rounded_integer(self : Decimal) -> Int64 {
#| if self.decimal_point > 20 {
#| return 0xFFFFFFFFFFFFFFFFL
#| }
#| let (n, i) = for n = 0L, i = 0; i < self.decimal_point && i < self.digits_num; {
#| continue n * 10L + self.digits[i].to_int64(), i + 1
#| } nobreak {
#| (n, i)
#| }
#| let n = for n = n, i = i; i < self.decimal_point; {
#| continue n * 10L, i + 1
#| } nobreak {
#| n
#| }
#| if self.should_round_up(self.decimal_point) {
#| n + 1L
#| } else {
#| n
#| }
#|}
#|fn Decimal::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 Decimal::assign(self : Decimal, v : Int64) -> Unit {
#| let buf = FixedArray::make(24, b'\x00')
#| let n = for n = 0, v = v; v > 0; {
#| let v1 = v / 10
#| buf[n] = (v - v1 * 10).to_byte()
#| continue n + 1, v1
#| } nobreak {
#| n
#| }
#| self.digits_num = 0
#| for i in n>..0 {
#| self.digits[self.digits_num] = buf[i]
#| self.digits_num += 1
#| }
#| self.decimal_point = self.digits_num
#| self.trim()
#|}
#|fn Decimal::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 *= 10
#| }
#| self.digits_num = write_index
#| self.trim()
#|}
#|let left_shift_cheats : ReadOnlyArray[(Int, String)] = [
#| (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 Decimal::new_digits(self : Decimal, s : Int) -> Int {
#| let new_digits = left_shift_cheats[s].0
#| let cheat_num = left_shift_cheats[s].1
#| let less = for i, code_unit in cheat_num.code_units() {
#| if i >= self.digits_num {
#| break true
#| }
#| let d = code_unit.to_int() - '0'
#| if self.digits[i].to_int() != d {
#| break self.digits[i].to_int() < d
#| }
#| } nobreak {
#| false
#| }
#| if less {
#| new_digits - 1
#| } else {
#| new_digits
#| }
#|}
#|fn Decimal::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 Decimal::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
#| }
#|}
#|impl Show for Decimal with fn output(self, logger) {
#| if self.digits_num == 0 {
#| logger.write_char('0')
#| return
#| }
#| if self.decimal_point <= 0 {
#| logger.write_string("0.")
#| for _ 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"
#| @test.assert_eq(parse_decimal_priv(s).to_string(), s)
#| @test.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 t in tests {
#| let d = Decimal::from_int64_priv(t.0)
#| d.shift_priv(t.1)
#| @test.assert_eq(d.to_string(), t.2)
#| }
#|}
#|test "parse decimal with underscore" {
#| inspect(parse_decimal_priv("1e1_2"), content="1000000000000")
#| inspect(parse_decimal_priv("1e12"), content="1000000000000")
#| inspect(parse_decimal_priv("1_2_3"), content="123")
#|}
#|test "parse decimal error" {
#| assert_true(
#| @test.expect_error(() => parse_decimal_priv("1e"))
#| is Failure("invalid syntax"),
#| )
#| assert_true(
#| @test.expect_error(() => parse_decimal_priv("1e+"))
#| is Failure("invalid syntax"),
#| )
#| assert_true(
#| @test.expect_error(() => parse_decimal_priv("1e_"))
#| is Failure("invalid syntax"),
#| )
#| assert_true(
#| @test.expect_error(() => parse_decimal_priv("1-23"))
#| is Failure("invalid syntax"),
#| )
#| assert_true(
#| @test.expect_error(() => parse_decimal_priv("1.2.3"))
#| is Failure("invalid syntax"),
#| )
#|}
#|test "parse decimal with large numbers" {
#| let s = String::make(100, '9')
#| inspect(parse_decimal_priv(s), content=s)
#|}
#|test "should_round_up when truncated and half-way" {
#| let decimal = parse_decimal_priv("12.50")
#| inspect(decimal.to_double_priv(), content="12.5")
#|}
#|test "parse_decimal with large numbers and truncation" {
#| let s = String::make(1000, '9')
#| inspect(parse_decimal_priv(s), content=String::make(800, '9'))
#|}
#|test "rounded_integer overflow when decimal_point > 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" {
#| let _ = parse_decimal_priv(".123")
#| assert_true(
#| @test.expect_error(() => parse_decimal_priv("."))
#| is Failure("invalid syntax"),
#| )
#| assert_true(
#| @test.expect_error(() => parse_decimal_priv("-"))
#| is Failure("invalid syntax"),
#| )
#|}
#|test "parse_double mantissa normalization boundary" {
#| inspect(parse_double("1.9999999999999999"), content="2")
#| inspect(parse_double("9007199254740991.5"), content="9007199254740992")
#|}
#|test "parse_double large magnitude cancellation" {
#| let input = "1" + String::make(800, '0') + "e-800"
#| inspect(parse_double(input), content="1")
#| let input = "-1" + String::make(800, '0') + "e-800"
#| inspect(parse_double(input), content="-1")
#| let input = "1." + String::make(800, '0')
#| inspect(parse_double(input), content="1")
#| let input = "1" + String::make(1999, '0') + "e-1999"
#| inspect(parse_double(input), content="1")
#| let input = "1" + String::make(399, '0') + ".5"
#| try parse_double(input) catch {
#| e => inspect(e, content="Failure(value out of range)")
#| } noraise {
#| _ => fail("expected parse_double to raise")
#| }
#| let input = "1" + String::make(800, '0') + ".5"
#| try parse_double(input) catch {
#| e => inspect(e, content="Failure(value out of range)")
#| } noraise {
#| _ => fail("expected parse_double to raise")
#| }
#| let input = "1" + String::make(1499, '0') + "e-1499"
#| inspect(parse_double(input), content="1")
#| let input = "0." + String::make(1999, '0') + "1"
#| inspect(parse_double(input), content="0")
#|}
),
"strconv_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 : StringView) -> Double raise {
#| guard !str.is_empty() else { syntax_err() }
#| guard check_underscore(str) else { syntax_err() }
#| match parse_number(str) {
#| None => parse_inf_nan(str)
#| Some(num) =>
#| match num.try_fast_path() {
#| Some(value) => value
#| None => {
#| let fast = if num.many_digits {
#| @double.not_a_number
#| } else {
#| try_eisel_lemire64(num.mantissa, num.exponent, num.negative)
#| }
#| if fast.is_nan() {
#| parse_decimal_priv(str).to_double_priv() // fallback to slow path
#| } else {
#| fast
#| }
#| }
#| }
#| }
#|}
#|fn Number::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 : ReadOnlyArray[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 : ReadOnlyArray[UInt64] = [
#| 1UL, 10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL, 100000000UL,
#| 1000000000UL, 10000000000UL, 100000000000UL, 1000000000000UL, 10000000000000UL,
#| 100000000000000UL, 1000000000000000UL,
#|]
#|fn Number::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
#| guard checked_mul(self.mantissa, int_pow10[shift.to_int()])
#| is Some(mantissa) else {
#| 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 t in tests {
#| @test.assert_eq(
#| Result::Ok(parse_double(t.0)) catch {
#| Failure::Failure(err) => Err(err)
#| err => Err(err.to_string())
#| },
#| t.1,
#| )
#| }
#|}
#|test "parse_double_inf" {
#| @test.assert_eq(parse_double("inf"), @double.infinity)
#| @test.assert_eq(parse_double("+Inf"), @double.infinity)
#| @test.assert_eq(parse_double("-Inf"), @double.neg_infinity)
#| @test.assert_eq(parse_double("+Infinity"), @double.infinity)
#| @test.assert_eq(parse_double("-Infinity"), @double.neg_infinity)
#| @test.assert_eq(parse_double("+INFINITY"), @double.infinity)
#| @test.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())
#|}
),
"strconv_eisel_lemire.mbt": (
#|#valtype
#|priv struct EiselProduct {
#| lo : UInt64
#| hi : UInt64
#|}
#|fn eisel_umul128(a : UInt64, b : UInt64) -> EiselProduct {
#| let a_lo = a & 0xffffffffUL
#| let a_hi = a >> 32
#| let b_lo = b & 0xffffffffUL
#| let b_hi = b >> 32
#| let x = a_lo * b_lo
#| let y = a_hi * b_lo + (x >> 32)
#| let z = a_lo * b_hi + (y & 0xffffffffUL)
#| let hi = a_hi * b_hi + (y >> 32) + (z >> 32)
#| { lo: a * b, hi, }
#|}
#|fn eisel_mul_log2_10(exponent : Int) -> Int {
#| (exponent * 108853) >> 15
#|}
#|#doc(hidden)
#|pub fn try_eisel_lemire64(
#| mantissa : UInt64,
#| exponent : Int64,
#| negative : Bool,
#|) -> Double {
#| if mantissa == 0UL {
#| return if negative {
#| 0x8000000000000000UL.reinterpret_as_double()
#| } else {
#| 0.0
#| }
#| }
#| if exponent < EISEL_LEMIRE_POW10_MIN.to_int64() ||
#| exponent > EISEL_LEMIRE_POW10_MAX.to_int64() {
#| return @double.not_a_number
#| }
#| let exponent = exponent.to_int()
#| let table_index = (exponent - EISEL_LEMIRE_POW10_MIN) * 2
#| let pow_hi = eisel_lemire_pow10_table[table_index]
#| let pow_lo = eisel_lemire_pow10_table[table_index + 1]
#| let pow_exp2 = 1 + eisel_mul_log2_10(exponent)
#| let leading_zeros = mantissa.clz()
#| let normalized = mantissa << leading_zeros
#| let mut result_exp2 = pow_exp2 + 63 + 1023 - leading_zeros
#| let product = eisel_umul128(normalized, pow_hi)
#| let mut product_hi = product.hi
#| let mut product_lo = product.lo
#| if (product_hi & 0x1ffUL) == 0x1ffUL && product_lo + normalized < normalized {
#| let wider = eisel_umul128(normalized, pow_lo)
#| let mut merged_hi = product_hi
#| let merged_lo = product_lo + wider.hi
#| if merged_lo < product_lo {
#| merged_hi += 1UL
#| }
#| if (merged_hi & 0x1ffUL) == 0x1ffUL &&
#| merged_lo + 1UL == 0UL &&
#| wider.lo + normalized < normalized {
#| return @double.not_a_number
#| }
#| product_hi = merged_hi
#| product_lo = merged_lo
#| }
#| let top_bit = (product_hi >> 63).to_int()
#| let mut result_mantissa = product_hi >> (top_bit + 9)
#| result_exp2 -= 1 - top_bit
#| if product_lo == 0UL &&
#| (product_hi & 0x1ffUL) == 0UL &&
#| (result_mantissa & 3UL) == 1UL {
#| return @double.not_a_number
#| }
#| result_mantissa += result_mantissa & 1UL
#| result_mantissa = result_mantissa >> 1
#| if result_mantissa >> 53 > 0UL {
#| result_mantissa = result_mantissa >> 1
#| result_exp2 += 1
#| }
#| if result_exp2 <= 0 || result_exp2 >= 0x7ff {
#| return @double.not_a_number
#| }
#| let exponent_bits = UInt64::extend_uint(result_exp2.reinterpret_as_uint()) <<
#| 52
#| let mut result_bits = exponent_bits | (result_mantissa & 0x000fffffffffffffUL)
#| if negative {
#| result_bits = result_bits | 0x8000000000000000UL
#| }
#| result_bits.reinterpret_as_double()
#|}
),
"strconv_eisel_lemire_table.mbt": (
#|const EISEL_LEMIRE_POW10_MIN : Int = -348
#|const EISEL_LEMIRE_POW10_MAX : Int = 347
#|let eisel_lemire_pow10_table : ReadOnlyArray[UInt64] = [
#| 0xfa8fd5a0081c0288UL, 0x1732c869cd60e453UL, // 1e-348 * 2**1284
#| 0x9c99e58405118195UL, 0x0e7fbd42205c8eb4UL, // 1e-347 * 2**1280
#| 0xc3c05ee50655e1faUL, 0x521fac92a873b261UL, // 1e-346 * 2**1277
#| 0xf4b0769e47eb5a78UL, 0xe6a797b752909ef9UL, // 1e-345 * 2**1274
#| 0x98ee4a22ecf3188bUL, 0x9028bed2939a635cUL, // 1e-344 * 2**1270
#| 0xbf29dcaba82fdeaeUL, 0x7432ee873880fc33UL, // 1e-343 * 2**1267
#| 0xeef453d6923bd65aUL, 0x113faa2906a13b3fUL, // 1e-342 * 2**1264
#| 0x9558b4661b6565f8UL, 0x4ac7ca59a424c507UL, // 1e-341 * 2**1260
#| 0xbaaee17fa23ebf76UL, 0x5d79bcf00d2df649UL, // 1e-340 * 2**1257
#| 0xe95a99df8ace6f53UL, 0xf4d82c2c107973dcUL, // 1e-339 * 2**1254
#| 0x91d8a02bb6c10594UL, 0x79071b9b8a4be869UL, // 1e-338 * 2**1250
#| 0xb64ec836a47146f9UL, 0x9748e2826cdee284UL, // 1e-337 * 2**1247
#| 0xe3e27a444d8d98b7UL, 0xfd1b1b2308169b25UL, // 1e-336 * 2**1244
#| 0x8e6d8c6ab0787f72UL, 0xfe30f0f5e50e20f7UL, // 1e-335 * 2**1240
#| 0xb208ef855c969f4fUL, 0xbdbd2d335e51a935UL, // 1e-334 * 2**1237
#| 0xde8b2b66b3bc4723UL, 0xad2c788035e61382UL, // 1e-333 * 2**1234
#| 0x8b16fb203055ac76UL, 0x4c3bcb5021afcc31UL, // 1e-332 * 2**1230
#| 0xaddcb9e83c6b1793UL, 0xdf4abe242a1bbf3dUL, // 1e-331 * 2**1227
#| 0xd953e8624b85dd78UL, 0xd71d6dad34a2af0dUL, // 1e-330 * 2**1224
#| 0x87d4713d6f33aa6bUL, 0x8672648c40e5ad68UL, // 1e-329 * 2**1220
#| 0xa9c98d8ccb009506UL, 0x680efdaf511f18c2UL, // 1e-328 * 2**1217
#| 0xd43bf0effdc0ba48UL, 0x0212bd1b2566def2UL, // 1e-327 * 2**1214
#| 0x84a57695fe98746dUL, 0x014bb630f7604b57UL, // 1e-326 * 2**1210
#| 0xa5ced43b7e3e9188UL, 0x419ea3bd35385e2dUL, // 1e-325 * 2**1207
#| 0xcf42894a5dce35eaUL, 0x52064cac828675b9UL, // 1e-324 * 2**1204
#| 0x818995ce7aa0e1b2UL, 0x7343efebd1940993UL, // 1e-323 * 2**1200
#| 0xa1ebfb4219491a1fUL, 0x1014ebe6c5f90bf8UL, // 1e-322 * 2**1197
#| 0xca66fa129f9b60a6UL, 0xd41a26e077774ef6UL, // 1e-321 * 2**1194
#| 0xfd00b897478238d0UL, 0x8920b098955522b4UL, // 1e-320 * 2**1191
#| 0x9e20735e8cb16382UL, 0x55b46e5f5d5535b0UL, // 1e-319 * 2**1187
#| 0xc5a890362fddbc62UL, 0xeb2189f734aa831dUL, // 1e-318 * 2**1184
#| 0xf712b443bbd52b7bUL, 0xa5e9ec7501d523e4UL, // 1e-317 * 2**1181
#| 0x9a6bb0aa55653b2dUL, 0x47b233c92125366eUL, // 1e-316 * 2**1177
#| 0xc1069cd4eabe89f8UL, 0x999ec0bb696e840aUL, // 1e-315 * 2**1174
#| 0xf148440a256e2c76UL, 0xc00670ea43ca250dUL, // 1e-314 * 2**1171
#| 0x96cd2a865764dbcaUL, 0x380406926a5e5728UL, // 1e-313 * 2**1167
#| 0xbc807527ed3e12bcUL, 0xc605083704f5ecf2UL, // 1e-312 * 2**1164
#| 0xeba09271e88d976bUL, 0xf7864a44c633682eUL, // 1e-311 * 2**1161
#| 0x93445b8731587ea3UL, 0x7ab3ee6afbe0211dUL, // 1e-310 * 2**1157
#| 0xb8157268fdae9e4cUL, 0x5960ea05bad82964UL, // 1e-309 * 2**1154
#| 0xe61acf033d1a45dfUL, 0x6fb92487298e33bdUL, // 1e-308 * 2**1151
#| 0x8fd0c16206306babUL, 0xa5d3b6d479f8e056UL, // 1e-307 * 2**1147
#| 0xb3c4f1ba87bc8696UL, 0x8f48a4899877186cUL, // 1e-306 * 2**1144
#| 0xe0b62e2929aba83cUL, 0x331acdabfe94de87UL, // 1e-305 * 2**1141
#| 0x8c71dcd9ba0b4925UL, 0x9ff0c08b7f1d0b14UL, // 1e-304 * 2**1137
#| 0xaf8e5410288e1b6fUL, 0x07ecf0ae5ee44dd9UL, // 1e-303 * 2**1134
#| 0xdb71e91432b1a24aUL, 0xc9e82cd9f69d6150UL, // 1e-302 * 2**1131
#| 0x892731ac9faf056eUL, 0xbe311c083a225cd2UL, // 1e-301 * 2**1127
#| 0xab70fe17c79ac6caUL, 0x6dbd630a48aaf406UL, // 1e-300 * 2**1124
#| 0xd64d3d9db981787dUL, 0x092cbbccdad5b108UL, // 1e-299 * 2**1121
#| 0x85f0468293f0eb4eUL, 0x25bbf56008c58ea5UL, // 1e-298 * 2**1117
#| 0xa76c582338ed2621UL, 0xaf2af2b80af6f24eUL, // 1e-297 * 2**1114
#| 0xd1476e2c07286faaUL, 0x1af5af660db4aee1UL, // 1e-296 * 2**1111
#| 0x82cca4db847945caUL, 0x50d98d9fc890ed4dUL, // 1e-295 * 2**1107
#| 0xa37fce126597973cUL, 0xe50ff107bab528a0UL, // 1e-294 * 2**1104
#| 0xcc5fc196fefd7d0cUL, 0x1e53ed49a96272c8UL, // 1e-293 * 2**1101
#| 0xff77b1fcbebcdc4fUL, 0x25e8e89c13bb0f7aUL, // 1e-292 * 2**1098
#| 0x9faacf3df73609b1UL, 0x77b191618c54e9acUL, // 1e-291 * 2**1094
#| 0xc795830d75038c1dUL, 0xd59df5b9ef6a2417UL, // 1e-290 * 2**1091
#| 0xf97ae3d0d2446f25UL, 0x4b0573286b44ad1dUL, // 1e-289 * 2**1088
#| 0x9becce62836ac577UL, 0x4ee367f9430aec32UL, // 1e-288 * 2**1084
#| 0xc2e801fb244576d5UL, 0x229c41f793cda73fUL, // 1e-287 * 2**1081
#| 0xf3a20279ed56d48aUL, 0x6b43527578c1110fUL, // 1e-286 * 2**1078
#| 0x9845418c345644d6UL, 0x830a13896b78aaa9UL, // 1e-285 * 2**1074
#| 0xbe5691ef416bd60cUL, 0x23cc986bc656d553UL, // 1e-284 * 2**1071
#| 0xedec366b11c6cb8fUL, 0x2cbfbe86b7ec8aa8UL, // 1e-283 * 2**1068
#| 0x94b3a202eb1c3f39UL, 0x7bf7d71432f3d6a9UL, // 1e-282 * 2**1064
#| 0xb9e08a83a5e34f07UL, 0xdaf5ccd93fb0cc53UL, // 1e-281 * 2**1061
#| 0xe858ad248f5c22c9UL, 0xd1b3400f8f9cff68UL, // 1e-280 * 2**1058
#| 0x91376c36d99995beUL, 0x23100809b9c21fa1UL, // 1e-279 * 2**1054
#| 0xb58547448ffffb2dUL, 0xabd40a0c2832a78aUL, // 1e-278 * 2**1051
#| 0xe2e69915b3fff9f9UL, 0x16c90c8f323f516cUL, // 1e-277 * 2**1048
#| 0x8dd01fad907ffc3bUL, 0xae3da7d97f6792e3UL, // 1e-276 * 2**1044
#| 0xb1442798f49ffb4aUL, 0x99cd11cfdf41779cUL, // 1e-275 * 2**1041
#| 0xdd95317f31c7fa1dUL, 0x40405643d711d583UL, // 1e-274 * 2**1038
#| 0x8a7d3eef7f1cfc52UL, 0x482835ea666b2572UL, // 1e-273 * 2**1034
#| 0xad1c8eab5ee43b66UL, 0xda3243650005eecfUL, // 1e-272 * 2**1031
#| 0xd863b256369d4a40UL, 0x90bed43e40076a82UL, // 1e-271 * 2**1028
#| 0x873e4f75e2224e68UL, 0x5a7744a6e804a291UL, // 1e-270 * 2**1024
#| 0xa90de3535aaae202UL, 0x711515d0a205cb36UL, // 1e-269 * 2**1021
#| 0xd3515c2831559a83UL, 0x0d5a5b44ca873e03UL, // 1e-268 * 2**1018
#| 0x8412d9991ed58091UL, 0xe858790afe9486c2UL, // 1e-267 * 2**1014
#| 0xa5178fff668ae0b6UL, 0x626e974dbe39a872UL, // 1e-266 * 2**1011
#| 0xce5d73ff402d98e3UL, 0xfb0a3d212dc8128fUL, // 1e-265 * 2**1008
#| 0x80fa687f881c7f8eUL, 0x7ce66634bc9d0b99UL, // 1e-264 * 2**1004
#| 0xa139029f6a239f72UL, 0x1c1fffc1ebc44e80UL, // 1e-263 * 2**1001
#| 0xc987434744ac874eUL, 0xa327ffb266b56220UL, // 1e-262 * 2**998
#| 0xfbe9141915d7a922UL, 0x4bf1ff9f0062baa8UL, // 1e-261 * 2**995
#| 0x9d71ac8fada6c9b5UL, 0x6f773fc3603db4a9UL, // 1e-260 * 2**991
#| 0xc4ce17b399107c22UL, 0xcb550fb4384d21d3UL, // 1e-259 * 2**988
#| 0xf6019da07f549b2bUL, 0x7e2a53a146606a48UL, // 1e-258 * 2**985
#| 0x99c102844f94e0fbUL, 0x2eda7444cbfc426dUL, // 1e-257 * 2**981
#| 0xc0314325637a1939UL, 0xfa911155fefb5308UL, // 1e-256 * 2**978
#| 0xf03d93eebc589f88UL, 0x793555ab7eba27caUL, // 1e-255 * 2**975
#| 0x96267c7535b763b5UL, 0x4bc1558b2f3458deUL, // 1e-254 * 2**971
#| 0xbbb01b9283253ca2UL, 0x9eb1aaedfb016f16UL, // 1e-253 * 2**968
#| 0xea9c227723ee8bcbUL, 0x465e15a979c1cadcUL, // 1e-252 * 2**965
#| 0x92a1958a7675175fUL, 0x0bfacd89ec191ec9UL, // 1e-251 * 2**961
#| 0xb749faed14125d36UL, 0xcef980ec671f667bUL, // 1e-250 * 2**958
#| 0xe51c79a85916f484UL, 0x82b7e12780e7401aUL, // 1e-249 * 2**955
#| 0x8f31cc0937ae58d2UL, 0xd1b2ecb8b0908810UL, // 1e-248 * 2**951
#| 0xb2fe3f0b8599ef07UL, 0x861fa7e6dcb4aa15UL, // 1e-247 * 2**948
#| 0xdfbdcece67006ac9UL, 0x67a791e093e1d49aUL, // 1e-246 * 2**945
#| 0x8bd6a141006042bdUL, 0xe0c8bb2c5c6d24e0UL, // 1e-245 * 2**941
#| 0xaecc49914078536dUL, 0x58fae9f773886e18UL, // 1e-244 * 2**938
#| 0xda7f5bf590966848UL, 0xaf39a475506a899eUL, // 1e-243 * 2**935
#| 0x888f99797a5e012dUL, 0x6d8406c952429603UL, // 1e-242 * 2**931
#| 0xaab37fd7d8f58178UL, 0xc8e5087ba6d33b83UL, // 1e-241 * 2**928
#| 0xd5605fcdcf32e1d6UL, 0xfb1e4a9a90880a64UL, // 1e-240 * 2**925
#| 0x855c3be0a17fcd26UL, 0x5cf2eea09a55067fUL, // 1e-239 * 2**921
#| 0xa6b34ad8c9dfc06fUL, 0xf42faa48c0ea481eUL, // 1e-238 * 2**918
#| 0xd0601d8efc57b08bUL, 0xf13b94daf124da26UL, // 1e-237 * 2**915
#| 0x823c12795db6ce57UL, 0x76c53d08d6b70858UL, // 1e-236 * 2**911
#| 0xa2cb1717b52481edUL, 0x54768c4b0c64ca6eUL, // 1e-235 * 2**908
#| 0xcb7ddcdda26da268UL, 0xa9942f5dcf7dfd09UL, // 1e-234 * 2**905
#| 0xfe5d54150b090b02UL, 0xd3f93b35435d7c4cUL, // 1e-233 * 2**902
#| 0x9efa548d26e5a6e1UL, 0xc47bc5014a1a6dafUL, // 1e-232 * 2**898
#| 0xc6b8e9b0709f109aUL, 0x359ab6419ca1091bUL, // 1e-231 * 2**895
#| 0xf867241c8cc6d4c0UL, 0xc30163d203c94b62UL, // 1e-230 * 2**892
#| 0x9b407691d7fc44f8UL, 0x79e0de63425dcf1dUL, // 1e-229 * 2**888
#| 0xc21094364dfb5636UL, 0x985915fc12f542e4UL, // 1e-228 * 2**885
#| 0xf294b943e17a2bc4UL, 0x3e6f5b7b17b2939dUL, // 1e-227 * 2**882
#| 0x979cf3ca6cec5b5aUL, 0xa705992ceecf9c42UL, // 1e-226 * 2**878
#| 0xbd8430bd08277231UL, 0x50c6ff782a838353UL, // 1e-225 * 2**875
#| 0xece53cec4a314ebdUL, 0xa4f8bf5635246428UL, // 1e-224 * 2**872
#| 0x940f4613ae5ed136UL, 0x871b7795e136be99UL, // 1e-223 * 2**868
#| 0xb913179899f68584UL, 0x28e2557b59846e3fUL, // 1e-222 * 2**865
#| 0xe757dd7ec07426e5UL, 0x331aeada2fe589cfUL, // 1e-221 * 2**862
#| 0x9096ea6f3848984fUL, 0x3ff0d2c85def7621UL, // 1e-220 * 2**858
#| 0xb4bca50b065abe63UL, 0x0fed077a756b53a9UL, // 1e-219 * 2**855
#| 0xe1ebce4dc7f16dfbUL, 0xd3e8495912c62894UL, // 1e-218 * 2**852
#| 0x8d3360f09cf6e4bdUL, 0x64712dd7abbbd95cUL, // 1e-217 * 2**848
#| 0xb080392cc4349decUL, 0xbd8d794d96aacfb3UL, // 1e-216 * 2**845
#| 0xdca04777f541c567UL, 0xecf0d7a0fc5583a0UL, // 1e-215 * 2**842
#| 0x89e42caaf9491b60UL, 0xf41686c49db57244UL, // 1e-214 * 2**838
#| 0xac5d37d5b79b6239UL, 0x311c2875c522ced5UL, // 1e-213 * 2**835
#| 0xd77485cb25823ac7UL, 0x7d633293366b828bUL, // 1e-212 * 2**832
#| 0x86a8d39ef77164bcUL, 0xae5dff9c02033197UL, // 1e-211 * 2**828
#| 0xa8530886b54dbdebUL, 0xd9f57f830283fdfcUL, // 1e-210 * 2**825
#| 0xd267caa862a12d66UL, 0xd072df63c324fd7bUL, // 1e-209 * 2**822
#| 0x8380dea93da4bc60UL, 0x4247cb9e59f71e6dUL, // 1e-208 * 2**818
#| 0xa46116538d0deb78UL, 0x52d9be85f074e608UL, // 1e-207 * 2**815
#| 0xcd795be870516656UL, 0x67902e276c921f8bUL, // 1e-206 * 2**812
#| 0x806bd9714632dff6UL, 0x00ba1cd8a3db53b6UL, // 1e-205 * 2**808
#| 0xa086cfcd97bf97f3UL, 0x80e8a40eccd228a4UL, // 1e-204 * 2**805
#| 0xc8a883c0fdaf7df0UL, 0x6122cd128006b2cdUL, // 1e-203 * 2**802
#| 0xfad2a4b13d1b5d6cUL, 0x796b805720085f81UL, // 1e-202 * 2**799
#| 0x9cc3a6eec6311a63UL, 0xcbe3303674053bb0UL, // 1e-201 * 2**795
#| 0xc3f490aa77bd60fcUL, 0xbedbfc4411068a9cUL, // 1e-200 * 2**792
#| 0xf4f1b4d515acb93bUL, 0xee92fb5515482d44UL, // 1e-199 * 2**789
#| 0x991711052d8bf3c5UL, 0x751bdd152d4d1c4aUL, // 1e-198 * 2**785
#| 0xbf5cd54678eef0b6UL, 0xd262d45a78a0635dUL, // 1e-197 * 2**782
#| 0xef340a98172aace4UL, 0x86fb897116c87c34UL, // 1e-196 * 2**779
#| 0x9580869f0e7aac0eUL, 0xd45d35e6ae3d4da0UL, // 1e-195 * 2**775
#| 0xbae0a846d2195712UL, 0x8974836059cca109UL, // 1e-194 * 2**772
#| 0xe998d258869facd7UL, 0x2bd1a438703fc94bUL, // 1e-193 * 2**769
#| 0x91ff83775423cc06UL, 0x7b6306a34627ddcfUL, // 1e-192 * 2**765
#| 0xb67f6455292cbf08UL, 0x1a3bc84c17b1d542UL, // 1e-191 * 2**762
#| 0xe41f3d6a7377eecaUL, 0x20caba5f1d9e4a93UL, // 1e-190 * 2**759
#| 0x8e938662882af53eUL, 0x547eb47b7282ee9cUL, // 1e-189 * 2**755
#| 0xb23867fb2a35b28dUL, 0xe99e619a4f23aa43UL, // 1e-188 * 2**752
#| 0xdec681f9f4c31f31UL, 0x6405fa00e2ec94d4UL, // 1e-187 * 2**749
#| 0x8b3c113c38f9f37eUL, 0xde83bc408dd3dd04UL, // 1e-186 * 2**745
#| 0xae0b158b4738705eUL, 0x9624ab50b148d445UL, // 1e-185 * 2**742
#| 0xd98ddaee19068c76UL, 0x3badd624dd9b0957UL, // 1e-184 * 2**739
#| 0x87f8a8d4cfa417c9UL, 0xe54ca5d70a80e5d6UL, // 1e-183 * 2**735
#| 0xa9f6d30a038d1dbcUL, 0x5e9fcf4ccd211f4cUL, // 1e-182 * 2**732
#| 0xd47487cc8470652bUL, 0x7647c3200069671fUL, // 1e-181 * 2**729
#| 0x84c8d4dfd2c63f3bUL, 0x29ecd9f40041e073UL, // 1e-180 * 2**725
#| 0xa5fb0a17c777cf09UL, 0xf468107100525890UL, // 1e-179 * 2**722
#| 0xcf79cc9db955c2ccUL, 0x7182148d4066eeb4UL, // 1e-178 * 2**719
#| 0x81ac1fe293d599bfUL, 0xc6f14cd848405530UL, // 1e-177 * 2**715
#| 0xa21727db38cb002fUL, 0xb8ada00e5a506a7cUL, // 1e-176 * 2**712
#| 0xca9cf1d206fdc03bUL, 0xa6d90811f0e4851cUL, // 1e-175 * 2**709
#| 0xfd442e4688bd304aUL, 0x908f4a166d1da663UL, // 1e-174 * 2**706
#| 0x9e4a9cec15763e2eUL, 0x9a598e4e043287feUL, // 1e-173 * 2**702
#| 0xc5dd44271ad3cdbaUL, 0x40eff1e1853f29fdUL, // 1e-172 * 2**699
#| 0xf7549530e188c128UL, 0xd12bee59e68ef47cUL, // 1e-171 * 2**696
#| 0x9a94dd3e8cf578b9UL, 0x82bb74f8301958ceUL, // 1e-170 * 2**692
#| 0xc13a148e3032d6e7UL, 0xe36a52363c1faf01UL, // 1e-169 * 2**689
#| 0xf18899b1bc3f8ca1UL, 0xdc44e6c3cb279ac1UL, // 1e-168 * 2**686
#| 0x96f5600f15a7b7e5UL, 0x29ab103a5ef8c0b9UL, // 1e-167 * 2**682
#| 0xbcb2b812db11a5deUL, 0x7415d448f6b6f0e7UL, // 1e-166 * 2**679
#| 0xebdf661791d60f56UL, 0x111b495b3464ad21UL, // 1e-165 * 2**676
#| 0x936b9fcebb25c995UL, 0xcab10dd900beec34UL, // 1e-164 * 2**672
#| 0xb84687c269ef3bfbUL, 0x3d5d514f40eea742UL, // 1e-163 * 2**669
#| 0xe65829b3046b0afaUL, 0x0cb4a5a3112a5112UL, // 1e-162 * 2**666
#| 0x8ff71a0fe2c2e6dcUL, 0x47f0e785eaba72abUL, // 1e-161 * 2**662
#| 0xb3f4e093db73a093UL, 0x59ed216765690f56UL, // 1e-160 * 2**659
#| 0xe0f218b8d25088b8UL, 0x306869c13ec3532cUL, // 1e-159 * 2**656
#| 0x8c974f7383725573UL, 0x1e414218c73a13fbUL, // 1e-158 * 2**652
#| 0xafbd2350644eeacfUL, 0xe5d1929ef90898faUL, // 1e-157 * 2**649
#| 0xdbac6c247d62a583UL, 0xdf45f746b74abf39UL, // 1e-156 * 2**646
#| 0x894bc396ce5da772UL, 0x6b8bba8c328eb783UL, // 1e-155 * 2**642
#| 0xab9eb47c81f5114fUL, 0x066ea92f3f326564UL, // 1e-154 * 2**639
#| 0xd686619ba27255a2UL, 0xc80a537b0efefebdUL, // 1e-153 * 2**636
#| 0x8613fd0145877585UL, 0xbd06742ce95f5f36UL, // 1e-152 * 2**632
#| 0xa798fc4196e952e7UL, 0x2c48113823b73704UL, // 1e-151 * 2**629
#| 0xd17f3b51fca3a7a0UL, 0xf75a15862ca504c5UL, // 1e-150 * 2**626
#| 0x82ef85133de648c4UL, 0x9a984d73dbe722fbUL, // 1e-149 * 2**622
#| 0xa3ab66580d5fdaf5UL, 0xc13e60d0d2e0ebbaUL, // 1e-148 * 2**619
#| 0xcc963fee10b7d1b3UL, 0x318df905079926a8UL, // 1e-147 * 2**616
#| 0xffbbcfe994e5c61fUL, 0xfdf17746497f7052UL, // 1e-146 * 2**613
#| 0x9fd561f1fd0f9bd3UL, 0xfeb6ea8bedefa633UL, // 1e-145 * 2**609
#| 0xc7caba6e7c5382c8UL, 0xfe64a52ee96b8fc0UL, // 1e-144 * 2**606
#| 0xf9bd690a1b68637bUL, 0x3dfdce7aa3c673b0UL, // 1e-143 * 2**603
#| 0x9c1661a651213e2dUL, 0x06bea10ca65c084eUL, // 1e-142 * 2**599
#| 0xc31bfa0fe5698db8UL, 0x486e494fcff30a62UL, // 1e-141 * 2**596
#| 0xf3e2f893dec3f126UL, 0x5a89dba3c3efccfaUL, // 1e-140 * 2**593
#| 0x986ddb5c6b3a76b7UL, 0xf89629465a75e01cUL, // 1e-139 * 2**589
#| 0xbe89523386091465UL, 0xf6bbb397f1135823UL, // 1e-138 * 2**586
#| 0xee2ba6c0678b597fUL, 0x746aa07ded582e2cUL, // 1e-137 * 2**583
#| 0x94db483840b717efUL, 0xa8c2a44eb4571cdcUL, // 1e-136 * 2**579
#| 0xba121a4650e4ddebUL, 0x92f34d62616ce413UL, // 1e-135 * 2**576
#| 0xe896a0d7e51e1566UL, 0x77b020baf9c81d17UL, // 1e-134 * 2**573
#| 0x915e2486ef32cd60UL, 0x0ace1474dc1d122eUL, // 1e-133 * 2**569
#| 0xb5b5ada8aaff80b8UL, 0x0d819992132456baUL, // 1e-132 * 2**566
#| 0xe3231912d5bf60e6UL, 0x10e1fff697ed6c69UL, // 1e-131 * 2**563
#| 0x8df5efabc5979c8fUL, 0xca8d3ffa1ef463c1UL, // 1e-130 * 2**559
#| 0xb1736b96b6fd83b3UL, 0xbd308ff8a6b17cb2UL, // 1e-129 * 2**556
#| 0xddd0467c64bce4a0UL, 0xac7cb3f6d05ddbdeUL, // 1e-128 * 2**553
#| 0x8aa22c0dbef60ee4UL, 0x6bcdf07a423aa96bUL, // 1e-127 * 2**549
#| 0xad4ab7112eb3929dUL, 0x86c16c98d2c953c6UL, // 1e-126 * 2**546
#| 0xd89d64d57a607744UL, 0xe871c7bf077ba8b7UL, // 1e-125 * 2**543
#| 0x87625f056c7c4a8bUL, 0x11471cd764ad4972UL, // 1e-124 * 2**539
#| 0xa93af6c6c79b5d2dUL, 0xd598e40d3dd89bcfUL, // 1e-123 * 2**536
#| 0xd389b47879823479UL, 0x4aff1d108d4ec2c3UL, // 1e-122 * 2**533
#| 0x843610cb4bf160cbUL, 0xcedf722a585139baUL, // 1e-121 * 2**529
#| 0xa54394fe1eedb8feUL, 0xc2974eb4ee658828UL, // 1e-120 * 2**526
#| 0xce947a3da6a9273eUL, 0x733d226229feea32UL, // 1e-119 * 2**523
#| 0x811ccc668829b887UL, 0x0806357d5a3f525fUL, // 1e-118 * 2**519
#| 0xa163ff802a3426a8UL, 0xca07c2dcb0cf26f7UL, // 1e-117 * 2**516
#| 0xc9bcff6034c13052UL, 0xfc89b393dd02f0b5UL, // 1e-116 * 2**513
#| 0xfc2c3f3841f17c67UL, 0xbbac2078d443ace2UL, // 1e-115 * 2**510
#| 0x9d9ba7832936edc0UL, 0xd54b944b84aa4c0dUL, // 1e-114 * 2**506
#| 0xc5029163f384a931UL, 0x0a9e795e65d4df11UL, // 1e-113 * 2**503
#| 0xf64335bcf065d37dUL, 0x4d4617b5ff4a16d5UL, // 1e-112 * 2**500
#| 0x99ea0196163fa42eUL, 0x504bced1bf8e4e45UL, // 1e-111 * 2**496
#| 0xc06481fb9bcf8d39UL, 0xe45ec2862f71e1d6UL, // 1e-110 * 2**493
#| 0xf07da27a82c37088UL, 0x5d767327bb4e5a4cUL, // 1e-109 * 2**490
#| 0x964e858c91ba2655UL, 0x3a6a07f8d510f86fUL, // 1e-108 * 2**486
#| 0xbbe226efb628afeaUL, 0x890489f70a55368bUL, // 1e-107 * 2**483
#| 0xeadab0aba3b2dbe5UL, 0x2b45ac74ccea842eUL, // 1e-106 * 2**480
#| 0x92c8ae6b464fc96fUL, 0x3b0b8bc90012929dUL, // 1e-105 * 2**476
#| 0xb77ada0617e3bbcbUL, 0x09ce6ebb40173744UL, // 1e-104 * 2**473
#| 0xe55990879ddcaabdUL, 0xcc420a6a101d0515UL, // 1e-103 * 2**470
#| 0x8f57fa54c2a9eab6UL, 0x9fa946824a12232dUL, // 1e-102 * 2**466
#| 0xb32df8e9f3546564UL, 0x47939822dc96abf9UL, // 1e-101 * 2**463
#| 0xdff9772470297ebdUL, 0x59787e2b93bc56f7UL, // 1e-100 * 2**460
#| 0x8bfbea76c619ef36UL, 0x57eb4edb3c55b65aUL, // 1e-99 * 2**456
#| 0xaefae51477a06b03UL, 0xede622920b6b23f1UL, // 1e-98 * 2**453
#| 0xdab99e59958885c4UL, 0xe95fab368e45ecedUL, // 1e-97 * 2**450
#| 0x88b402f7fd75539bUL, 0x11dbcb0218ebb414UL, // 1e-96 * 2**446
#| 0xaae103b5fcd2a881UL, 0xd652bdc29f26a119UL, // 1e-95 * 2**443
#| 0xd59944a37c0752a2UL, 0x4be76d3346f0495fUL, // 1e-94 * 2**440
#| 0x857fcae62d8493a5UL, 0x6f70a4400c562ddbUL, // 1e-93 * 2**436
#| 0xa6dfbd9fb8e5b88eUL, 0xcb4ccd500f6bb952UL, // 1e-92 * 2**433
#| 0xd097ad07a71f26b2UL, 0x7e2000a41346a7a7UL, // 1e-91 * 2**430
#| 0x825ecc24c873782fUL, 0x8ed400668c0c28c8UL, // 1e-90 * 2**426
#| 0xa2f67f2dfa90563bUL, 0x728900802f0f32faUL, // 1e-89 * 2**423
#| 0xcbb41ef979346bcaUL, 0x4f2b40a03ad2ffb9UL, // 1e-88 * 2**420
#| 0xfea126b7d78186bcUL, 0xe2f610c84987bfa8UL, // 1e-87 * 2**417
#| 0x9f24b832e6b0f436UL, 0x0dd9ca7d2df4d7c9UL, // 1e-86 * 2**413
#| 0xc6ede63fa05d3143UL, 0x91503d1c79720dbbUL, // 1e-85 * 2**410
#| 0xf8a95fcf88747d94UL, 0x75a44c6397ce912aUL, // 1e-84 * 2**407
#| 0x9b69dbe1b548ce7cUL, 0xc986afbe3ee11abaUL, // 1e-83 * 2**403
#| 0xc24452da229b021bUL, 0xfbe85badce996168UL, // 1e-82 * 2**400
#| 0xf2d56790ab41c2a2UL, 0xfae27299423fb9c3UL, // 1e-81 * 2**397
#| 0x97c560ba6b0919a5UL, 0xdccd879fc967d41aUL, // 1e-80 * 2**393
#| 0xbdb6b8e905cb600fUL, 0x5400e987bbc1c920UL, // 1e-79 * 2**390
#| 0xed246723473e3813UL, 0x290123e9aab23b68UL, // 1e-78 * 2**387
#| 0x9436c0760c86e30bUL, 0xf9a0b6720aaf6521UL, // 1e-77 * 2**383
#| 0xb94470938fa89bceUL, 0xf808e40e8d5b3e69UL, // 1e-76 * 2**380
#| 0xe7958cb87392c2c2UL, 0xb60b1d1230b20e04UL, // 1e-75 * 2**377
#| 0x90bd77f3483bb9b9UL, 0xb1c6f22b5e6f48c2UL, // 1e-74 * 2**373
#| 0xb4ecd5f01a4aa828UL, 0x1e38aeb6360b1af3UL, // 1e-73 * 2**370
#| 0xe2280b6c20dd5232UL, 0x25c6da63c38de1b0UL, // 1e-72 * 2**367
#| 0x8d590723948a535fUL, 0x579c487e5a38ad0eUL, // 1e-71 * 2**363
#| 0xb0af48ec79ace837UL, 0x2d835a9df0c6d851UL, // 1e-70 * 2**360
#| 0xdcdb1b2798182244UL, 0xf8e431456cf88e65UL, // 1e-69 * 2**357
#| 0x8a08f0f8bf0f156bUL, 0x1b8e9ecb641b58ffUL, // 1e-68 * 2**353
#| 0xac8b2d36eed2dac5UL, 0xe272467e3d222f3fUL, // 1e-67 * 2**350
#| 0xd7adf884aa879177UL, 0x5b0ed81dcc6abb0fUL, // 1e-66 * 2**347
#| 0x86ccbb52ea94baeaUL, 0x98e947129fc2b4e9UL, // 1e-65 * 2**343
#| 0xa87fea27a539e9a5UL, 0x3f2398d747b36224UL, // 1e-64 * 2**340
#| 0xd29fe4b18e88640eUL, 0x8eec7f0d19a03aadUL, // 1e-63 * 2**337
#| 0x83a3eeeef9153e89UL, 0x1953cf68300424acUL, // 1e-62 * 2**333
#| 0xa48ceaaab75a8e2bUL, 0x5fa8c3423c052dd7UL, // 1e-61 * 2**330
#| 0xcdb02555653131b6UL, 0x3792f412cb06794dUL, // 1e-60 * 2**327
#| 0x808e17555f3ebf11UL, 0xe2bbd88bbee40bd0UL, // 1e-59 * 2**323
#| 0xa0b19d2ab70e6ed6UL, 0x5b6aceaeae9d0ec4UL, // 1e-58 * 2**320
#| 0xc8de047564d20a8bUL, 0xf245825a5a445275UL, // 1e-57 * 2**317
#| 0xfb158592be068d2eUL, 0xeed6e2f0f0d56712UL, // 1e-56 * 2**314
#| 0x9ced737bb6c4183dUL, 0x55464dd69685606bUL, // 1e-55 * 2**310
#| 0xc428d05aa4751e4cUL, 0xaa97e14c3c26b886UL, // 1e-54 * 2**307
#| 0xf53304714d9265dfUL, 0xd53dd99f4b3066a8UL, // 1e-53 * 2**304
#| 0x993fe2c6d07b7fabUL, 0xe546a8038efe4029UL, // 1e-52 * 2**300
#| 0xbf8fdb78849a5f96UL, 0xde98520472bdd033UL, // 1e-51 * 2**297
#| 0xef73d256a5c0f77cUL, 0x963e66858f6d4440UL, // 1e-50 * 2**294
#| 0x95a8637627989aadUL, 0xdde7001379a44aa8UL, // 1e-49 * 2**290
#| 0xbb127c53b17ec159UL, 0x5560c018580d5d52UL, // 1e-48 * 2**287
#| 0xe9d71b689dde71afUL, 0xaab8f01e6e10b4a6UL, // 1e-47 * 2**284
#| 0x9226712162ab070dUL, 0xcab3961304ca70e8UL, // 1e-46 * 2**280
#| 0xb6b00d69bb55c8d1UL, 0x3d607b97c5fd0d22UL, // 1e-45 * 2**277
#| 0xe45c10c42a2b3b05UL, 0x8cb89a7db77c506aUL, // 1e-44 * 2**274
#| 0x8eb98a7a9a5b04e3UL, 0x77f3608e92adb242UL, // 1e-43 * 2**270
#| 0xb267ed1940f1c61cUL, 0x55f038b237591ed3UL, // 1e-42 * 2**267
#| 0xdf01e85f912e37a3UL, 0x6b6c46dec52f6688UL, // 1e-41 * 2**264
#| 0x8b61313bbabce2c6UL, 0x2323ac4b3b3da015UL, // 1e-40 * 2**260
#| 0xae397d8aa96c1b77UL, 0xabec975e0a0d081aUL, // 1e-39 * 2**257
#| 0xd9c7dced53c72255UL, 0x96e7bd358c904a21UL, // 1e-38 * 2**254
#| 0x881cea14545c7575UL, 0x7e50d64177da2e54UL, // 1e-37 * 2**250
#| 0xaa242499697392d2UL, 0xdde50bd1d5d0b9e9UL, // 1e-36 * 2**247
#| 0xd4ad2dbfc3d07787UL, 0x955e4ec64b44e864UL, // 1e-35 * 2**244
#| 0x84ec3c97da624ab4UL, 0xbd5af13bef0b113eUL, // 1e-34 * 2**240
#| 0xa6274bbdd0fadd61UL, 0xecb1ad8aeacdd58eUL, // 1e-33 * 2**237
#| 0xcfb11ead453994baUL, 0x67de18eda5814af2UL, // 1e-32 * 2**234
#| 0x81ceb32c4b43fcf4UL, 0x80eacf948770ced7UL, // 1e-31 * 2**230
#| 0xa2425ff75e14fc31UL, 0xa1258379a94d028dUL, // 1e-30 * 2**227
#| 0xcad2f7f5359a3b3eUL, 0x096ee45813a04330UL, // 1e-29 * 2**224
#| 0xfd87b5f28300ca0dUL, 0x8bca9d6e188853fcUL, // 1e-28 * 2**221
#| 0x9e74d1b791e07e48UL, 0x775ea264cf55347dUL, // 1e-27 * 2**217
#| 0xc612062576589ddaUL, 0x95364afe032a819dUL, // 1e-26 * 2**214
#| 0xf79687aed3eec551UL, 0x3a83ddbd83f52204UL, // 1e-25 * 2**211
#| 0x9abe14cd44753b52UL, 0xc4926a9672793542UL, // 1e-24 * 2**207
#| 0xc16d9a0095928a27UL, 0x75b7053c0f178293UL, // 1e-23 * 2**204
#| 0xf1c90080baf72cb1UL, 0x5324c68b12dd6338UL, // 1e-22 * 2**201
#| 0x971da05074da7beeUL, 0xd3f6fc16ebca5e03UL, // 1e-21 * 2**197
#| 0xbce5086492111aeaUL, 0x88f4bb1ca6bcf584UL, // 1e-20 * 2**194
#| 0xec1e4a7db69561a5UL, 0x2b31e9e3d06c32e5UL, // 1e-19 * 2**191
#| 0x9392ee8e921d5d07UL, 0x3aff322e62439fcfUL, // 1e-18 * 2**187
#| 0xb877aa3236a4b449UL, 0x09befeb9fad487c2UL, // 1e-17 * 2**184
#| 0xe69594bec44de15bUL, 0x4c2ebe687989a9b3UL, // 1e-16 * 2**181
#| 0x901d7cf73ab0acd9UL, 0x0f9d37014bf60a10UL, // 1e-15 * 2**177
#| 0xb424dc35095cd80fUL, 0x538484c19ef38c94UL, // 1e-14 * 2**174
#| 0xe12e13424bb40e13UL, 0x2865a5f206b06fb9UL, // 1e-13 * 2**171
#| 0x8cbccc096f5088cbUL, 0xf93f87b7442e45d3UL, // 1e-12 * 2**167
#| 0xafebff0bcb24aafeUL, 0xf78f69a51539d748UL, // 1e-11 * 2**164
#| 0xdbe6fecebdedd5beUL, 0xb573440e5a884d1bUL, // 1e-10 * 2**161
#| 0x89705f4136b4a597UL, 0x31680a88f8953030UL, // 1e-9 * 2**157
#| 0xabcc77118461cefcUL, 0xfdc20d2b36ba7c3dUL, // 1e-8 * 2**154
#| 0xd6bf94d5e57a42bcUL, 0x3d32907604691b4cUL, // 1e-7 * 2**151
#| 0x8637bd05af6c69b5UL, 0xa63f9a49c2c1b10fUL, // 1e-6 * 2**147
#| 0xa7c5ac471b478423UL, 0x0fcf80dc33721d53UL, // 1e-5 * 2**144
#| 0xd1b71758e219652bUL, 0xd3c36113404ea4a8UL, // 1e-4 * 2**141
#| 0x83126e978d4fdf3bUL, 0x645a1cac083126e9UL, // 1e-3 * 2**137
#| 0xa3d70a3d70a3d70aUL, 0x3d70a3d70a3d70a3UL, // 1e-2 * 2**134
#| 0xccccccccccccccccUL, 0xccccccccccccccccUL, // 1e-1 * 2**131
#| 0x8000000000000000UL, 0x0000000000000000UL, // 1e0 * 2**127
#| 0xa000000000000000UL, 0x0000000000000000UL, // 1e1 * 2**124
#| 0xc800000000000000UL, 0x0000000000000000UL, // 1e2 * 2**121
#| 0xfa00000000000000UL, 0x0000000000000000UL, // 1e3 * 2**118
#| 0x9c40000000000000UL, 0x0000000000000000UL, // 1e4 * 2**114
#| 0xc350000000000000UL, 0x0000000000000000UL, // 1e5 * 2**111
#| 0xf424000000000000UL, 0x0000000000000000UL, // 1e6 * 2**108
#| 0x9896800000000000UL, 0x0000000000000000UL, // 1e7 * 2**104
#| 0xbebc200000000000UL, 0x0000000000000000UL, // 1e8 * 2**101
#| 0xee6b280000000000UL, 0x0000000000000000UL, // 1e9 * 2**98
#| 0x9502f90000000000UL, 0x0000000000000000UL, // 1e10 * 2**94
#| 0xba43b74000000000UL, 0x0000000000000000UL, // 1e11 * 2**91
#| 0xe8d4a51000000000UL, 0x0000000000000000UL, // 1e12 * 2**88
#| 0x9184e72a00000000UL, 0x0000000000000000UL, // 1e13 * 2**84
#| 0xb5e620f480000000UL, 0x0000000000000000UL, // 1e14 * 2**81
#| 0xe35fa931a0000000UL, 0x0000000000000000UL, // 1e15 * 2**78
#| 0x8e1bc9bf04000000UL, 0x0000000000000000UL, // 1e16 * 2**74
#| 0xb1a2bc2ec5000000UL, 0x0000000000000000UL, // 1e17 * 2**71
#| 0xde0b6b3a76400000UL, 0x0000000000000000UL, // 1e18 * 2**68
#| 0x8ac7230489e80000UL, 0x0000000000000000UL, // 1e19 * 2**64
#| 0xad78ebc5ac620000UL, 0x0000000000000000UL, // 1e20 * 2**61
#| 0xd8d726b7177a8000UL, 0x0000000000000000UL, // 1e21 * 2**58
#| 0x878678326eac9000UL, 0x0000000000000000UL, // 1e22 * 2**54
#| 0xa968163f0a57b400UL, 0x0000000000000000UL, // 1e23 * 2**51
#| 0xd3c21bcecceda100UL, 0x0000000000000000UL, // 1e24 * 2**48
#| 0x84595161401484a0UL, 0x0000000000000000UL, // 1e25 * 2**44
#| 0xa56fa5b99019a5c8UL, 0x0000000000000000UL, // 1e26 * 2**41
#| 0xcecb8f27f4200f3aUL, 0x0000000000000000UL, // 1e27 * 2**38
#| 0x813f3978f8940984UL, 0x4000000000000000UL, // 1e28 * 2**34
#| 0xa18f07d736b90be5UL, 0x5000000000000000UL, // 1e29 * 2**31
#| 0xc9f2c9cd04674edeUL, 0xa400000000000000UL, // 1e30 * 2**28
#| 0xfc6f7c4045812296UL, 0x4d00000000000000UL, // 1e31 * 2**25
#| 0x9dc5ada82b70b59dUL, 0xf020000000000000UL, // 1e32 * 2**21
#| 0xc5371912364ce305UL, 0x6c28000000000000UL, // 1e33 * 2**18
#| 0xf684df56c3e01bc6UL, 0xc732000000000000UL, // 1e34 * 2**15
#| 0x9a130b963a6c115cUL, 0x3c7f400000000000UL, // 1e35 * 2**11
#| 0xc097ce7bc90715b3UL, 0x4b9f100000000000UL, // 1e36 * 2**8
#| 0xf0bdc21abb48db20UL, 0x1e86d40000000000UL, // 1e37 * 2**5
#| 0x96769950b50d88f4UL, 0x1314448000000000UL, // 1e38 * 2**1
#| 0xbc143fa4e250eb31UL, 0x17d955a000000000UL, // 1e39 * 2**-2
#| 0xeb194f8e1ae525fdUL, 0x5dcfab0800000000UL, // 1e40 * 2**-5
#| 0x92efd1b8d0cf37beUL, 0x5aa1cae500000000UL, // 1e41 * 2**-9
#| 0xb7abc627050305adUL, 0xf14a3d9e40000000UL, // 1e42 * 2**-12
#| 0xe596b7b0c643c719UL, 0x6d9ccd05d0000000UL, // 1e43 * 2**-15
#| 0x8f7e32ce7bea5c6fUL, 0xe4820023a2000000UL, // 1e44 * 2**-19
#| 0xb35dbf821ae4f38bUL, 0xdda2802c8a800000UL, // 1e45 * 2**-22
#| 0xe0352f62a19e306eUL, 0xd50b2037ad200000UL, // 1e46 * 2**-25
#| 0x8c213d9da502de45UL, 0x4526f422cc340000UL, // 1e47 * 2**-29
#| 0xaf298d050e4395d6UL, 0x9670b12b7f410000UL, // 1e48 * 2**-32
#| 0xdaf3f04651d47b4cUL, 0x3c0cdd765f114000UL, // 1e49 * 2**-35
#| 0x88d8762bf324cd0fUL, 0xa5880a69fb6ac800UL, // 1e50 * 2**-39
#| 0xab0e93b6efee0053UL, 0x8eea0d047a457a00UL, // 1e51 * 2**-42
#| 0xd5d238a4abe98068UL, 0x72a4904598d6d880UL, // 1e52 * 2**-45
#| 0x85a36366eb71f041UL, 0x47a6da2b7f864750UL, // 1e53 * 2**-49
#| 0xa70c3c40a64e6c51UL, 0x999090b65f67d924UL, // 1e54 * 2**-52
#| 0xd0cf4b50cfe20765UL, 0xfff4b4e3f741cf6dUL, // 1e55 * 2**-55
#| 0x82818f1281ed449fUL, 0xbff8f10e7a8921a4UL, // 1e56 * 2**-59
#| 0xa321f2d7226895c7UL, 0xaff72d52192b6a0dUL, // 1e57 * 2**-62
#| 0xcbea6f8ceb02bb39UL, 0x9bf4f8a69f764490UL, // 1e58 * 2**-65
#| 0xfee50b7025c36a08UL, 0x02f236d04753d5b4UL, // 1e59 * 2**-68
#| 0x9f4f2726179a2245UL, 0x01d762422c946590UL, // 1e60 * 2**-72
#| 0xc722f0ef9d80aad6UL, 0x424d3ad2b7b97ef5UL, // 1e61 * 2**-75
#| 0xf8ebad2b84e0d58bUL, 0xd2e0898765a7deb2UL, // 1e62 * 2**-78
#| 0x9b934c3b330c8577UL, 0x63cc55f49f88eb2fUL, // 1e63 * 2**-82
#| 0xc2781f49ffcfa6d5UL, 0x3cbf6b71c76b25fbUL, // 1e64 * 2**-85
#| 0xf316271c7fc3908aUL, 0x8bef464e3945ef7aUL, // 1e65 * 2**-88
#| 0x97edd871cfda3a56UL, 0x97758bf0e3cbb5acUL, // 1e66 * 2**-92
#| 0xbde94e8e43d0c8ecUL, 0x3d52eeed1cbea317UL, // 1e67 * 2**-95
#| 0xed63a231d4c4fb27UL, 0x4ca7aaa863ee4bddUL, // 1e68 * 2**-98
#| 0x945e455f24fb1cf8UL, 0x8fe8caa93e74ef6aUL, // 1e69 * 2**-102
#| 0xb975d6b6ee39e436UL, 0xb3e2fd538e122b44UL, // 1e70 * 2**-105
#| 0xe7d34c64a9c85d44UL, 0x60dbbca87196b616UL, // 1e71 * 2**-108
#| 0x90e40fbeea1d3a4aUL, 0xbc8955e946fe31cdUL, // 1e72 * 2**-112
#| 0xb51d13aea4a488ddUL, 0x6babab6398bdbe41UL, // 1e73 * 2**-115
#| 0xe264589a4dcdab14UL, 0xc696963c7eed2dd1UL, // 1e74 * 2**-118
#| 0x8d7eb76070a08aecUL, 0xfc1e1de5cf543ca2UL, // 1e75 * 2**-122
#| 0xb0de65388cc8ada8UL, 0x3b25a55f43294bcbUL, // 1e76 * 2**-125
#| 0xdd15fe86affad912UL, 0x49ef0eb713f39ebeUL, // 1e77 * 2**-128
#| 0x8a2dbf142dfcc7abUL, 0x6e3569326c784337UL, // 1e78 * 2**-132
#| 0xacb92ed9397bf996UL, 0x49c2c37f07965404UL, // 1e79 * 2**-135
#| 0xd7e77a8f87daf7fbUL, 0xdc33745ec97be906UL, // 1e80 * 2**-138
#| 0x86f0ac99b4e8dafdUL, 0x69a028bb3ded71a3UL, // 1e81 * 2**-142
#| 0xa8acd7c0222311bcUL, 0xc40832ea0d68ce0cUL, // 1e82 * 2**-145
#| 0xd2d80db02aabd62bUL, 0xf50a3fa490c30190UL, // 1e83 * 2**-148
#| 0x83c7088e1aab65dbUL, 0x792667c6da79e0faUL, // 1e84 * 2**-152
#| 0xa4b8cab1a1563f52UL, 0x577001b891185938UL, // 1e85 * 2**-155
#| 0xcde6fd5e09abcf26UL, 0xed4c0226b55e6f86UL, // 1e86 * 2**-158
#| 0x80b05e5ac60b6178UL, 0x544f8158315b05b4UL, // 1e87 * 2**-162
#| 0xa0dc75f1778e39d6UL, 0x696361ae3db1c721UL, // 1e88 * 2**-165
#| 0xc913936dd571c84cUL, 0x03bc3a19cd1e38e9UL, // 1e89 * 2**-168
#| 0xfb5878494ace3a5fUL, 0x04ab48a04065c723UL, // 1e90 * 2**-171
#| 0x9d174b2dcec0e47bUL, 0x62eb0d64283f9c76UL, // 1e91 * 2**-175
#| 0xc45d1df942711d9aUL, 0x3ba5d0bd324f8394UL, // 1e92 * 2**-178
#| 0xf5746577930d6500UL, 0xca8f44ec7ee36479UL, // 1e93 * 2**-181
#| 0x9968bf6abbe85f20UL, 0x7e998b13cf4e1ecbUL, // 1e94 * 2**-185
#| 0xbfc2ef456ae276e8UL, 0x9e3fedd8c321a67eUL, // 1e95 * 2**-188
#| 0xefb3ab16c59b14a2UL, 0xc5cfe94ef3ea101eUL, // 1e96 * 2**-191
#| 0x95d04aee3b80ece5UL, 0xbba1f1d158724a12UL, // 1e97 * 2**-195
#| 0xbb445da9ca61281fUL, 0x2a8a6e45ae8edc97UL, // 1e98 * 2**-198
#| 0xea1575143cf97226UL, 0xf52d09d71a3293bdUL, // 1e99 * 2**-201
#| 0x924d692ca61be758UL, 0x593c2626705f9c56UL, // 1e100 * 2**-205
#| 0xb6e0c377cfa2e12eUL, 0x6f8b2fb00c77836cUL, // 1e101 * 2**-208
#| 0xe498f455c38b997aUL, 0x0b6dfb9c0f956447UL, // 1e102 * 2**-211
#| 0x8edf98b59a373fecUL, 0x4724bd4189bd5eacUL, // 1e103 * 2**-215
#| 0xb2977ee300c50fe7UL, 0x58edec91ec2cb657UL, // 1e104 * 2**-218
#| 0xdf3d5e9bc0f653e1UL, 0x2f2967b66737e3edUL, // 1e105 * 2**-221
#| 0x8b865b215899f46cUL, 0xbd79e0d20082ee74UL, // 1e106 * 2**-225
#| 0xae67f1e9aec07187UL, 0xecd8590680a3aa11UL, // 1e107 * 2**-228
#| 0xda01ee641a708de9UL, 0xe80e6f4820cc9495UL, // 1e108 * 2**-231
#| 0x884134fe908658b2UL, 0x3109058d147fdcddUL, // 1e109 * 2**-235
#| 0xaa51823e34a7eedeUL, 0xbd4b46f0599fd415UL, // 1e110 * 2**-238
#| 0xd4e5e2cdc1d1ea96UL, 0x6c9e18ac7007c91aUL, // 1e111 * 2**-241
#| 0x850fadc09923329eUL, 0x03e2cf6bc604ddb0UL, // 1e112 * 2**-245
#| 0xa6539930bf6bff45UL, 0x84db8346b786151cUL, // 1e113 * 2**-248
#| 0xcfe87f7cef46ff16UL, 0xe612641865679a63UL, // 1e114 * 2**-251
#| 0x81f14fae158c5f6eUL, 0x4fcb7e8f3f60c07eUL, // 1e115 * 2**-255
#| 0xa26da3999aef7749UL, 0xe3be5e330f38f09dUL, // 1e116 * 2**-258
#| 0xcb090c8001ab551cUL, 0x5cadf5bfd3072cc5UL, // 1e117 * 2**-261
#| 0xfdcb4fa002162a63UL, 0x73d9732fc7c8f7f6UL, // 1e118 * 2**-264
#| 0x9e9f11c4014dda7eUL, 0x2867e7fddcdd9afaUL, // 1e119 * 2**-268
#| 0xc646d63501a1511dUL, 0xb281e1fd541501b8UL, // 1e120 * 2**-271
#| 0xf7d88bc24209a565UL, 0x1f225a7ca91a4226UL, // 1e121 * 2**-274
#| 0x9ae757596946075fUL, 0x3375788de9b06958UL, // 1e122 * 2**-278
#| 0xc1a12d2fc3978937UL, 0x0052d6b1641c83aeUL, // 1e123 * 2**-281
#| 0xf209787bb47d6b84UL, 0xc0678c5dbd23a49aUL, // 1e124 * 2**-284
#| 0x9745eb4d50ce6332UL, 0xf840b7ba963646e0UL, // 1e125 * 2**-288
#| 0xbd176620a501fbffUL, 0xb650e5a93bc3d898UL, // 1e126 * 2**-291
#| 0xec5d3fa8ce427affUL, 0xa3e51f138ab4cebeUL, // 1e127 * 2**-294
#| 0x93ba47c980e98cdfUL, 0xc66f336c36b10137UL, // 1e128 * 2**-298
#| 0xb8a8d9bbe123f017UL, 0xb80b0047445d4184UL, // 1e129 * 2**-301
#| 0xe6d3102ad96cec1dUL, 0xa60dc059157491e5UL, // 1e130 * 2**-304
#| 0x9043ea1ac7e41392UL, 0x87c89837ad68db2fUL, // 1e131 * 2**-308
#| 0xb454e4a179dd1877UL, 0x29babe4598c311fbUL, // 1e132 * 2**-311
#| 0xe16a1dc9d8545e94UL, 0xf4296dd6fef3d67aUL, // 1e133 * 2**-314
#| 0x8ce2529e2734bb1dUL, 0x1899e4a65f58660cUL, // 1e134 * 2**-318
#| 0xb01ae745b101e9e4UL, 0x5ec05dcff72e7f8fUL, // 1e135 * 2**-321
#| 0xdc21a1171d42645dUL, 0x76707543f4fa1f73UL, // 1e136 * 2**-324
#| 0x899504ae72497ebaUL, 0x6a06494a791c53a8UL, // 1e137 * 2**-328
#| 0xabfa45da0edbde69UL, 0x0487db9d17636892UL, // 1e138 * 2**-331
#| 0xd6f8d7509292d603UL, 0x45a9d2845d3c42b6UL, // 1e139 * 2**-334
#| 0x865b86925b9bc5c2UL, 0x0b8a2392ba45a9b2UL, // 1e140 * 2**-338
#| 0xa7f26836f282b732UL, 0x8e6cac7768d7141eUL, // 1e141 * 2**-341
#| 0xd1ef0244af2364ffUL, 0x3207d795430cd926UL, // 1e142 * 2**-344
#| 0x8335616aed761f1fUL, 0x7f44e6bd49e807b8UL, // 1e143 * 2**-348
#| 0xa402b9c5a8d3a6e7UL, 0x5f16206c9c6209a6UL, // 1e144 * 2**-351
#| 0xcd036837130890a1UL, 0x36dba887c37a8c0fUL, // 1e145 * 2**-354
#| 0x802221226be55a64UL, 0xc2494954da2c9789UL, // 1e146 * 2**-358
#| 0xa02aa96b06deb0fdUL, 0xf2db9baa10b7bd6cUL, // 1e147 * 2**-361
#| 0xc83553c5c8965d3dUL, 0x6f92829494e5acc7UL, // 1e148 * 2**-364
#| 0xfa42a8b73abbf48cUL, 0xcb772339ba1f17f9UL, // 1e149 * 2**-367
#| 0x9c69a97284b578d7UL, 0xff2a760414536efbUL, // 1e150 * 2**-371
#| 0xc38413cf25e2d70dUL, 0xfef5138519684abaUL, // 1e151 * 2**-374
#| 0xf46518c2ef5b8cd1UL, 0x7eb258665fc25d69UL, // 1e152 * 2**-377
#| 0x98bf2f79d5993802UL, 0xef2f773ffbd97a61UL, // 1e153 * 2**-381
#| 0xbeeefb584aff8603UL, 0xaafb550ffacfd8faUL, // 1e154 * 2**-384
#| 0xeeaaba2e5dbf6784UL, 0x95ba2a53f983cf38UL, // 1e155 * 2**-387
#| 0x952ab45cfa97a0b2UL, 0xdd945a747bf26183UL, // 1e156 * 2**-391
#| 0xba756174393d88dfUL, 0x94f971119aeef9e4UL, // 1e157 * 2**-394
#| 0xe912b9d1478ceb17UL, 0x7a37cd5601aab85dUL, // 1e158 * 2**-397
#| 0x91abb422ccb812eeUL, 0xac62e055c10ab33aUL, // 1e159 * 2**-401
#| 0xb616a12b7fe617aaUL, 0x577b986b314d6009UL, // 1e160 * 2**-404
#| 0xe39c49765fdf9d94UL, 0xed5a7e85fda0b80bUL, // 1e161 * 2**-407
#| 0x8e41ade9fbebc27dUL, 0x14588f13be847307UL, // 1e162 * 2**-411
#| 0xb1d219647ae6b31cUL, 0x596eb2d8ae258fc8UL, // 1e163 * 2**-414
#| 0xde469fbd99a05fe3UL, 0x6fca5f8ed9aef3bbUL, // 1e164 * 2**-417
#| 0x8aec23d680043beeUL, 0x25de7bb9480d5854UL, // 1e165 * 2**-421
#| 0xada72ccc20054ae9UL, 0xaf561aa79a10ae6aUL, // 1e166 * 2**-424
#| 0xd910f7ff28069da4UL, 0x1b2ba1518094da04UL, // 1e167 * 2**-427
#| 0x87aa9aff79042286UL, 0x90fb44d2f05d0842UL, // 1e168 * 2**-431
#| 0xa99541bf57452b28UL, 0x353a1607ac744a53UL, // 1e169 * 2**-434
#| 0xd3fa922f2d1675f2UL, 0x42889b8997915ce8UL, // 1e170 * 2**-437
#| 0x847c9b5d7c2e09b7UL, 0x69956135febada11UL, // 1e171 * 2**-441
#| 0xa59bc234db398c25UL, 0x43fab9837e699095UL, // 1e172 * 2**-444
#| 0xcf02b2c21207ef2eUL, 0x94f967e45e03f4bbUL, // 1e173 * 2**-447
#| 0x8161afb94b44f57dUL, 0x1d1be0eebac278f5UL, // 1e174 * 2**-451
#| 0xa1ba1ba79e1632dcUL, 0x6462d92a69731732UL, // 1e175 * 2**-454
#| 0xca28a291859bbf93UL, 0x7d7b8f7503cfdcfeUL, // 1e176 * 2**-457
#| 0xfcb2cb35e702af78UL, 0x5cda735244c3d43eUL, // 1e177 * 2**-460
#| 0x9defbf01b061adabUL, 0x3a0888136afa64a7UL, // 1e178 * 2**-464
#| 0xc56baec21c7a1916UL, 0x088aaa1845b8fdd0UL, // 1e179 * 2**-467
#| 0xf6c69a72a3989f5bUL, 0x8aad549e57273d45UL, // 1e180 * 2**-470
#| 0x9a3c2087a63f6399UL, 0x36ac54e2f678864bUL, // 1e181 * 2**-474
#| 0xc0cb28a98fcf3c7fUL, 0x84576a1bb416a7ddUL, // 1e182 * 2**-477
#| 0xf0fdf2d3f3c30b9fUL, 0x656d44a2a11c51d5UL, // 1e183 * 2**-480
#| 0x969eb7c47859e743UL, 0x9f644ae5a4b1b325UL, // 1e184 * 2**-484
#| 0xbc4665b596706114UL, 0x873d5d9f0dde1feeUL, // 1e185 * 2**-487
#| 0xeb57ff22fc0c7959UL, 0xa90cb506d155a7eaUL, // 1e186 * 2**-490
#| 0x9316ff75dd87cbd8UL, 0x09a7f12442d588f2UL, // 1e187 * 2**-494
#| 0xb7dcbf5354e9beceUL, 0x0c11ed6d538aeb2fUL, // 1e188 * 2**-497
#| 0xe5d3ef282a242e81UL, 0x8f1668c8a86da5faUL, // 1e189 * 2**-500
#| 0x8fa475791a569d10UL, 0xf96e017d694487bcUL, // 1e190 * 2**-504
#| 0xb38d92d760ec4455UL, 0x37c981dcc395a9acUL, // 1e191 * 2**-507
#| 0xe070f78d3927556aUL, 0x85bbe253f47b1417UL, // 1e192 * 2**-510
#| 0x8c469ab843b89562UL, 0x93956d7478ccec8eUL, // 1e193 * 2**-514
#| 0xaf58416654a6babbUL, 0x387ac8d1970027b2UL, // 1e194 * 2**-517
#| 0xdb2e51bfe9d0696aUL, 0x06997b05fcc0319eUL, // 1e195 * 2**-520
#| 0x88fcf317f22241e2UL, 0x441fece3bdf81f03UL, // 1e196 * 2**-524
#| 0xab3c2fddeeaad25aUL, 0xd527e81cad7626c3UL, // 1e197 * 2**-527
#| 0xd60b3bd56a5586f1UL, 0x8a71e223d8d3b074UL, // 1e198 * 2**-530
#| 0x85c7056562757456UL, 0xf6872d5667844e49UL, // 1e199 * 2**-534
#| 0xa738c6bebb12d16cUL, 0xb428f8ac016561dbUL, // 1e200 * 2**-537
#| 0xd106f86e69d785c7UL, 0xe13336d701beba52UL, // 1e201 * 2**-540
#| 0x82a45b450226b39cUL, 0xecc0024661173473UL, // 1e202 * 2**-544
#| 0xa34d721642b06084UL, 0x27f002d7f95d0190UL, // 1e203 * 2**-547
#| 0xcc20ce9bd35c78a5UL, 0x31ec038df7b441f4UL, // 1e204 * 2**-550
#| 0xff290242c83396ceUL, 0x7e67047175a15271UL, // 1e205 * 2**-553
#| 0x9f79a169bd203e41UL, 0x0f0062c6e984d386UL, // 1e206 * 2**-557
#| 0xc75809c42c684dd1UL, 0x52c07b78a3e60868UL, // 1e207 * 2**-560
#| 0xf92e0c3537826145UL, 0xa7709a56ccdf8a82UL, // 1e208 * 2**-563
#| 0x9bbcc7a142b17ccbUL, 0x88a66076400bb691UL, // 1e209 * 2**-567
#| 0xc2abf989935ddbfeUL, 0x6acff893d00ea435UL, // 1e210 * 2**-570
#| 0xf356f7ebf83552feUL, 0x0583f6b8c4124d43UL, // 1e211 * 2**-573
#| 0x98165af37b2153deUL, 0xc3727a337a8b704aUL, // 1e212 * 2**-577
#| 0xbe1bf1b059e9a8d6UL, 0x744f18c0592e4c5cUL, // 1e213 * 2**-580
#| 0xeda2ee1c7064130cUL, 0x1162def06f79df73UL, // 1e214 * 2**-583
#| 0x9485d4d1c63e8be7UL, 0x8addcb5645ac2ba8UL, // 1e215 * 2**-587
#| 0xb9a74a0637ce2ee1UL, 0x6d953e2bd7173692UL, // 1e216 * 2**-590
#| 0xe8111c87c5c1ba99UL, 0xc8fa8db6ccdd0437UL, // 1e217 * 2**-593
#| 0x910ab1d4db9914a0UL, 0x1d9c9892400a22a2UL, // 1e218 * 2**-597
#| 0xb54d5e4a127f59c8UL, 0x2503beb6d00cab4bUL, // 1e219 * 2**-600
#| 0xe2a0b5dc971f303aUL, 0x2e44ae64840fd61dUL, // 1e220 * 2**-603
#| 0x8da471a9de737e24UL, 0x5ceaecfed289e5d2UL, // 1e221 * 2**-607
#| 0xb10d8e1456105dadUL, 0x7425a83e872c5f47UL, // 1e222 * 2**-610
#| 0xdd50f1996b947518UL, 0xd12f124e28f77719UL, // 1e223 * 2**-613
#| 0x8a5296ffe33cc92fUL, 0x82bd6b70d99aaa6fUL, // 1e224 * 2**-617
#| 0xace73cbfdc0bfb7bUL, 0x636cc64d1001550bUL, // 1e225 * 2**-620
#| 0xd8210befd30efa5aUL, 0x3c47f7e05401aa4eUL, // 1e226 * 2**-623
#| 0x8714a775e3e95c78UL, 0x65acfaec34810a71UL, // 1e227 * 2**-627
#| 0xa8d9d1535ce3b396UL, 0x7f1839a741a14d0dUL, // 1e228 * 2**-630
#| 0xd31045a8341ca07cUL, 0x1ede48111209a050UL, // 1e229 * 2**-633
#| 0x83ea2b892091e44dUL, 0x934aed0aab460432UL, // 1e230 * 2**-637
#| 0xa4e4b66b68b65d60UL, 0xf81da84d5617853fUL, // 1e231 * 2**-640
#| 0xce1de40642e3f4b9UL, 0x36251260ab9d668eUL, // 1e232 * 2**-643
#| 0x80d2ae83e9ce78f3UL, 0xc1d72b7c6b426019UL, // 1e233 * 2**-647
#| 0xa1075a24e4421730UL, 0xb24cf65b8612f81fUL, // 1e234 * 2**-650
#| 0xc94930ae1d529cfcUL, 0xdee033f26797b627UL, // 1e235 * 2**-653
#| 0xfb9b7cd9a4a7443cUL, 0x169840ef017da3b1UL, // 1e236 * 2**-656
#| 0x9d412e0806e88aa5UL, 0x8e1f289560ee864eUL, // 1e237 * 2**-660
#| 0xc491798a08a2ad4eUL, 0xf1a6f2bab92a27e2UL, // 1e238 * 2**-663
#| 0xf5b5d7ec8acb58a2UL, 0xae10af696774b1dbUL, // 1e239 * 2**-666
#| 0x9991a6f3d6bf1765UL, 0xacca6da1e0a8ef29UL, // 1e240 * 2**-670
#| 0xbff610b0cc6edd3fUL, 0x17fd090a58d32af3UL, // 1e241 * 2**-673
#| 0xeff394dcff8a948eUL, 0xddfc4b4cef07f5b0UL, // 1e242 * 2**-676
#| 0x95f83d0a1fb69cd9UL, 0x4abdaf101564f98eUL, // 1e243 * 2**-680
#| 0xbb764c4ca7a4440fUL, 0x9d6d1ad41abe37f1UL, // 1e244 * 2**-683
#| 0xea53df5fd18d5513UL, 0x84c86189216dc5edUL, // 1e245 * 2**-686
#| 0x92746b9be2f8552cUL, 0x32fd3cf5b4e49bb4UL, // 1e246 * 2**-690
#| 0xb7118682dbb66a77UL, 0x3fbc8c33221dc2a1UL, // 1e247 * 2**-693
#| 0xe4d5e82392a40515UL, 0x0fabaf3feaa5334aUL, // 1e248 * 2**-696
#| 0x8f05b1163ba6832dUL, 0x29cb4d87f2a7400eUL, // 1e249 * 2**-700
#| 0xb2c71d5bca9023f8UL, 0x743e20e9ef511012UL, // 1e250 * 2**-703
#| 0xdf78e4b2bd342cf6UL, 0x914da9246b255416UL, // 1e251 * 2**-706
#| 0x8bab8eefb6409c1aUL, 0x1ad089b6c2f7548eUL, // 1e252 * 2**-710
#| 0xae9672aba3d0c320UL, 0xa184ac2473b529b1UL, // 1e253 * 2**-713
#| 0xda3c0f568cc4f3e8UL, 0xc9e5d72d90a2741eUL, // 1e254 * 2**-716
#| 0x8865899617fb1871UL, 0x7e2fa67c7a658892UL, // 1e255 * 2**-720
#| 0xaa7eebfb9df9de8dUL, 0xddbb901b98feeab7UL, // 1e256 * 2**-723
#| 0xd51ea6fa85785631UL, 0x552a74227f3ea565UL, // 1e257 * 2**-726
#| 0x8533285c936b35deUL, 0xd53a88958f87275fUL, // 1e258 * 2**-730
#| 0xa67ff273b8460356UL, 0x8a892abaf368f137UL, // 1e259 * 2**-733
#| 0xd01fef10a657842cUL, 0x2d2b7569b0432d85UL, // 1e260 * 2**-736
#| 0x8213f56a67f6b29bUL, 0x9c3b29620e29fc73UL, // 1e261 * 2**-740
#| 0xa298f2c501f45f42UL, 0x8349f3ba91b47b8fUL, // 1e262 * 2**-743
#| 0xcb3f2f7642717713UL, 0x241c70a936219a73UL, // 1e263 * 2**-746
#| 0xfe0efb53d30dd4d7UL, 0xed238cd383aa0110UL, // 1e264 * 2**-749
#| 0x9ec95d1463e8a506UL, 0xf4363804324a40aaUL, // 1e265 * 2**-753
#| 0xc67bb4597ce2ce48UL, 0xb143c6053edcd0d5UL, // 1e266 * 2**-756
#| 0xf81aa16fdc1b81daUL, 0xdd94b7868e94050aUL, // 1e267 * 2**-759
#| 0x9b10a4e5e9913128UL, 0xca7cf2b4191c8326UL, // 1e268 * 2**-763
#| 0xc1d4ce1f63f57d72UL, 0xfd1c2f611f63a3f0UL, // 1e269 * 2**-766
#| 0xf24a01a73cf2dccfUL, 0xbc633b39673c8cecUL, // 1e270 * 2**-769
#| 0x976e41088617ca01UL, 0xd5be0503e085d813UL, // 1e271 * 2**-773
#| 0xbd49d14aa79dbc82UL, 0x4b2d8644d8a74e18UL, // 1e272 * 2**-776
#| 0xec9c459d51852ba2UL, 0xddf8e7d60ed1219eUL, // 1e273 * 2**-779
#| 0x93e1ab8252f33b45UL, 0xcabb90e5c942b503UL, // 1e274 * 2**-783
#| 0xb8da1662e7b00a17UL, 0x3d6a751f3b936243UL, // 1e275 * 2**-786
#| 0xe7109bfba19c0c9dUL, 0x0cc512670a783ad4UL, // 1e276 * 2**-789
#| 0x906a617d450187e2UL, 0x27fb2b80668b24c5UL, // 1e277 * 2**-793
#| 0xb484f9dc9641e9daUL, 0xb1f9f660802dedf6UL, // 1e278 * 2**-796
#| 0xe1a63853bbd26451UL, 0x5e7873f8a0396973UL, // 1e279 * 2**-799
#| 0x8d07e33455637eb2UL, 0xdb0b487b6423e1e8UL, // 1e280 * 2**-803
#| 0xb049dc016abc5e5fUL, 0x91ce1a9a3d2cda62UL, // 1e281 * 2**-806
#| 0xdc5c5301c56b75f7UL, 0x7641a140cc7810fbUL, // 1e282 * 2**-809
#| 0x89b9b3e11b6329baUL, 0xa9e904c87fcb0a9dUL, // 1e283 * 2**-813
#| 0xac2820d9623bf429UL, 0x546345fa9fbdcd44UL, // 1e284 * 2**-816
#| 0xd732290fbacaf133UL, 0xa97c177947ad4095UL, // 1e285 * 2**-819
#| 0x867f59a9d4bed6c0UL, 0x49ed8eabcccc485dUL, // 1e286 * 2**-823
#| 0xa81f301449ee8c70UL, 0x5c68f256bfff5a74UL, // 1e287 * 2**-826
#| 0xd226fc195c6a2f8cUL, 0x73832eec6fff3111UL, // 1e288 * 2**-829
#| 0x83585d8fd9c25db7UL, 0xc831fd53c5ff7eabUL, // 1e289 * 2**-833
#| 0xa42e74f3d032f525UL, 0xba3e7ca8b77f5e55UL, // 1e290 * 2**-836
#| 0xcd3a1230c43fb26fUL, 0x28ce1bd2e55f35ebUL, // 1e291 * 2**-839
#| 0x80444b5e7aa7cf85UL, 0x7980d163cf5b81b3UL, // 1e292 * 2**-843
#| 0xa0555e361951c366UL, 0xd7e105bcc332621fUL, // 1e293 * 2**-846
#| 0xc86ab5c39fa63440UL, 0x8dd9472bf3fefaa7UL, // 1e294 * 2**-849
#| 0xfa856334878fc150UL, 0xb14f98f6f0feb951UL, // 1e295 * 2**-852
#| 0x9c935e00d4b9d8d2UL, 0x6ed1bf9a569f33d3UL, // 1e296 * 2**-856
#| 0xc3b8358109e84f07UL, 0x0a862f80ec4700c8UL, // 1e297 * 2**-859
#| 0xf4a642e14c6262c8UL, 0xcd27bb612758c0faUL, // 1e298 * 2**-862
#| 0x98e7e9cccfbd7dbdUL, 0x8038d51cb897789cUL, // 1e299 * 2**-866
#| 0xbf21e44003acdd2cUL, 0xe0470a63e6bd56c3UL, // 1e300 * 2**-869
#| 0xeeea5d5004981478UL, 0x1858ccfce06cac74UL, // 1e301 * 2**-872
#| 0x95527a5202df0ccbUL, 0x0f37801e0c43ebc8UL, // 1e302 * 2**-876
#| 0xbaa718e68396cffdUL, 0xd30560258f54e6baUL, // 1e303 * 2**-879
#| 0xe950df20247c83fdUL, 0x47c6b82ef32a2069UL, // 1e304 * 2**-882
#| 0x91d28b7416cdd27eUL, 0x4cdc331d57fa5441UL, // 1e305 * 2**-886
#| 0xb6472e511c81471dUL, 0xe0133fe4adf8e952UL, // 1e306 * 2**-889
#| 0xe3d8f9e563a198e5UL, 0x58180fddd97723a6UL, // 1e307 * 2**-892
#| 0x8e679c2f5e44ff8fUL, 0x570f09eaa7ea7648UL, // 1e308 * 2**-896
#| 0xb201833b35d63f73UL, 0x2cd2cc6551e513daUL, // 1e309 * 2**-899
#| 0xde81e40a034bcf4fUL, 0xf8077f7ea65e58d1UL, // 1e310 * 2**-902
#| 0x8b112e86420f6191UL, 0xfb04afaf27faf782UL, // 1e311 * 2**-906
#| 0xadd57a27d29339f6UL, 0x79c5db9af1f9b563UL, // 1e312 * 2**-909
#| 0xd94ad8b1c7380874UL, 0x18375281ae7822bcUL, // 1e313 * 2**-912
#| 0x87cec76f1c830548UL, 0x8f2293910d0b15b5UL, // 1e314 * 2**-916
#| 0xa9c2794ae3a3c69aUL, 0xb2eb3875504ddb22UL, // 1e315 * 2**-919
#| 0xd433179d9c8cb841UL, 0x5fa60692a46151ebUL, // 1e316 * 2**-922
#| 0x849feec281d7f328UL, 0xdbc7c41ba6bcd333UL, // 1e317 * 2**-926
#| 0xa5c7ea73224deff3UL, 0x12b9b522906c0800UL, // 1e318 * 2**-929
#| 0xcf39e50feae16befUL, 0xd768226b34870a00UL, // 1e319 * 2**-932
#| 0x81842f29f2cce375UL, 0xe6a1158300d46640UL, // 1e320 * 2**-936
#| 0xa1e53af46f801c53UL, 0x60495ae3c1097fd0UL, // 1e321 * 2**-939
#| 0xca5e89b18b602368UL, 0x385bb19cb14bdfc4UL, // 1e322 * 2**-942
#| 0xfcf62c1dee382c42UL, 0x46729e03dd9ed7b5UL, // 1e323 * 2**-945
#| 0x9e19db92b4e31ba9UL, 0x6c07a2c26a8346d1UL, // 1e324 * 2**-949
#| 0xc5a05277621be293UL, 0xc7098b7305241885UL, // 1e325 * 2**-952
#| 0xf70867153aa2db38UL, 0xb8cbee4fc66d1ea7UL, // 1e326 * 2**-955
#| 0x9a65406d44a5c903UL, 0x737f74f1dc043328UL, // 1e327 * 2**-959
#| 0xc0fe908895cf3b44UL, 0x505f522e53053ff2UL, // 1e328 * 2**-962
#| 0xf13e34aabb430a15UL, 0x647726b9e7c68fefUL, // 1e329 * 2**-965
#| 0x96c6e0eab509e64dUL, 0x5eca783430dc19f5UL, // 1e330 * 2**-969
#| 0xbc789925624c5fe0UL, 0xb67d16413d132072UL, // 1e331 * 2**-972
#| 0xeb96bf6ebadf77d8UL, 0xe41c5bd18c57e88fUL, // 1e332 * 2**-975
#| 0x933e37a534cbaae7UL, 0x8e91b962f7b6f159UL, // 1e333 * 2**-979
#| 0xb80dc58e81fe95a1UL, 0x723627bbb5a4adb0UL, // 1e334 * 2**-982
#| 0xe61136f2227e3b09UL, 0xcec3b1aaa30dd91cUL, // 1e335 * 2**-985
#| 0x8fcac257558ee4e6UL, 0x213a4f0aa5e8a7b1UL, // 1e336 * 2**-989
#| 0xb3bd72ed2af29e1fUL, 0xa988e2cd4f62d19dUL, // 1e337 * 2**-992
#| 0xe0accfa875af45a7UL, 0x93eb1b80a33b8605UL, // 1e338 * 2**-995
#| 0x8c6c01c9498d8b88UL, 0xbc72f130660533c3UL, // 1e339 * 2**-999
#| 0xaf87023b9bf0ee6aUL, 0xeb8fad7c7f8680b4UL, // 1e340 * 2**-1002
#| 0xdb68c2ca82ed2a05UL, 0xa67398db9f6820e1UL, // 1e341 * 2**-1005
#| 0x892179be91d43a43UL, 0x88083f8943a1148cUL, // 1e342 * 2**-1009
#| 0xab69d82e364948d4UL, 0x6a0a4f6b948959b0UL, // 1e343 * 2**-1012
#| 0xd6444e39c3db9b09UL, 0x848ce34679abb01cUL, // 1e344 * 2**-1015
#| 0x85eab0e41a6940e5UL, 0xf2d80e0c0c0b4e11UL, // 1e345 * 2**-1019
#| 0xa7655d1d2103911fUL, 0x6f8e118f0f0e2195UL, // 1e346 * 2**-1022
#| 0xd13eb46469447567UL, 0x4b7195f2d2d1a9fbUL, // 1e347 * 2**-1025
#|]
),
"strconv_errors.mbt": (
#|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 {
#| raise Failure::Failure(range_err_str)
#|}
#|fn[T] syntax_err() -> T raise {
#| raise Failure::Failure(syntax_err_str)
#|}
#|fn[T] base_err() -> T raise {
#| raise Failure::Failure(base_err_str)
#|}
),
"strconv_int.mbt": (
#|const INT_MIN = 0x80000000
#|const INT_MAX = 0x7fffffff
#|const INT64_MIN = -0x8000000000000000L
#|const INT64_MAX = 0x7fffffffffffffffL
#|fn check_and_consume_base(
#| view : StringView,
#| base : Int,
#|) -> (Int, StringView, Bool) raise {
#| 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 {
#| assert_true(
#| @test.expect_error(() => parse_int64("0b01", base=3))
#| is Failure("invalid syntax"),
#| )
#| assert_true(
#| @test.expect_error(() => parse_int64("0x01", base=3))
#| is Failure("invalid syntax"),
#| )
#| assert_true(
#| @test.expect_error(() => parse_int64("0o01", base=3))
#| is Failure("invalid syntax"),
#| )
#|}
#|pub fn parse_int64(str : StringView, base? : Int = 0) -> Int64 raise {
#| guard str != "" else { syntax_err() }
#| let (neg, rest) = match str {
#| ['+', .. 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() }
#| for rest = rest, acc = 0L, allow_underscore = allow_underscore {
#| match (rest, acc, 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, _) => break acc
#| }
#| }
#|}
#|pub fn parse_int(str : StringView, base? : Int = 0) -> Int raise {
#| 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 : StringView) -> Bool {
#| guard str.contains_code_unit(('_' : UInt16)) else { return true }
#| let rest = match str {
#| ['+' | '-', .. rest] => rest
#| rest => rest
#| }
#| let (rest, allow_underscore, hex) = lexmatch rest with longest {
#| (re"^0[xX]", after=rest) => (rest, true, true)
#| (re"^0[oO]", after=rest) => (rest, true, false)
#| (re"^0[bB]", after=rest) => (rest, true, false)
#| _ => (rest, false, false)
#| }
#| let follow_underscore = false
#| for rest = rest, allow_underscore = allow_underscore, follow_underscore = follow_underscore {
#| match (rest, allow_underscore, follow_underscore) {
#| ([], _, _) => break true
#| (['_'], _, _) => break false
#| (['_', ..], false, _) => break false
#| (['_', .. rest], true, _) => continue rest, false, true
#| (['0'..='9', .. rest], _, _) => continue rest, true, false
#| (['a'..='f' | 'A'..='F', .. rest], _, _) if hex =>
#| continue rest, true, false
#| (['.' | 'e' | 'E' | '+' | '-', ..], _, true) => break false
#| (['.' | 'e' | 'E' | '+' | '-', .. rest], _, _) =>
#| continue rest, false, false
#| ([_, ..], _, true) => break false
#| ([_, .. rest], _, _) => continue rest, false, false
#| }
#| }
#|}
#|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()
#| }
#|}
),
"strconv_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 : StringView, x : UInt64) -> (StringView, UInt64, Int) {
#| s.fold_digits(x, (digit, acc : UInt64) => {
#| acc * 10UL + UInt64::extend_uint(digit.reinterpret_as_uint())
#| })
#|}
#|fn try_parse_19digits(s : StringView, x : UInt64) -> (StringView, UInt64, Int) {
#| let mut x = x
#| let mut len = 0
#| for s = s {
#| match 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 => break (s, x, len)
#| }
#| }
#|}
#|fn parse_scientific(s : StringView) -> (StringView, Int64)? {
#| let mut s = s
#| 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 : StringView) -> Number? raise {
#| let start = s
#| let (s, negative) = match s {
#| ['-', .. rest] => (rest, true)
#| ['+', .. rest] | rest => (rest, false)
#| }
#| 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 mut exp_number = 0L
#| if s is ['e' | 'E', .. rest] {
#| let (new_s, exp_number_val) = match parse_scientific(rest) {
#| Some(res) => res
#| None => return None
#| }
#| s = new_s
#| exp_number = exp_number_val
#| exponent += exp_number
#| }
#| guard s is "" else { syntax_err() }
#| if n_digits <= 19 {
#| return Some({ exponent, mantissa, negative, many_digits: false, })
#| }
#| n_digits -= 19
#| let mut many_digits = false
#| for s = start {
#| match s {
#| ['0' | '.' as ch, .. rest] => {
#| n_digits -= (ch.to_int() - 46) / 2 // '0' = b'.' + 2
#| continue rest
#| }
#| _ => break
#| }
#| }
#| 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 {
#| guard s is [_, .. s] else { return None }
#| 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, })
#|}
#|fn parse_inf_nan(rest : StringView) -> Double raise {
#| let (pos, rest) = match rest {
#| ['-', .. rest] => (false, rest)
#| ['+', .. rest] | rest => (true, rest)
#| }
#| lexmatch rest with longest {
#| re"^(?i:nan)$" => @double.not_a_number
#| re"^(?i:inf(inity)?)$" =>
#| if pos {
#| @double.infinity
#| } else {
#| @double.neg_infinity
#| }
#| _ => syntax_err()
#| }
#|}
#|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)
#|}
),
"strconv_string_view.mbt": (
#|fn[T] StringView::fold_digits(
#| self : Self,
#| init : T,
#| f : (Int, T) -> T,
#|) -> (Self, T, Int) {
#| for str = self, ret = init, len = 0 {
#| match str {
#| ['0'..='9' as ch, .. rest] =>
#| continue rest, f(ch.to_int() - '0', ret), len + 1
#| ['_', .. rest] => continue rest, ret, len
#| _ => break (str, ret, len)
#| }
#| }
#|}
),
"strconv_uint.mbt": (
#|const UINT_MAX : UInt = 0xffffffff
#|const UINT64_MAX : UInt64 = 0xffffffffffffffffUL
#|pub fn parse_uint64(str : StringView, base? : Int = 0) -> UInt64 raise {
#| 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() }
#| for rest = rest, acc = 0UL, allow_underscore = allow_underscore {
#| match (rest, acc, 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, _) => break acc
#| }
#| }
#|}
#|pub fn parse_uint(str : StringView, base? : Int = 0) -> UInt raise {
#| 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 t in tests {
#| @test.assert_eq(
#| Result::Ok(parse_uint64(t.0)) catch {
#| Failure::Failure(err) => Err(err)
#| err => Err(err.to_string())
#| },
#| 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 t in tests {
#| @test.assert_eq(
#| Result::Ok(parse_uint64(t.0, base=t.1)) catch {
#| Failure::Failure(err) => Err(err)
#| err => Err(err.to_string())
#| },
#| 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 t in tests {
#| @test.assert_eq(
#| Result::Ok(parse_uint(t.0)) catch {
#| Failure::Failure(err) => Err(err)
#| err => Err(err.to_string())
#| },
#| t.1,
#| )
#| }
#|}
#|test "parse_uint64 uppercase hex and invalid base" {
#| @test.assert_eq(parse_uint64("ABCD", base=16), 43981)
#| assert_true(
#| @test.expect_error(() => parse_uint64("1234", base=37))
#| is Failure("invalid base"),
#| )
#|}
),
},
)
///|
let moonbitlang_core_json_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/json",
deps={},
files={
"deprecated.mbt": "",
"extends.mbt": (
#|pub extend JsonDecodeError with Eq::{equal}
#|pub extend JsonDecodeError with Show::{to_string}
#|pub extend JsonPath with Eq::{equal}
#|pub extend JsonPath with Show::{to_string}
#|pub extend ParseError with Eq::{equal}
#|pub extend ParseError with Show::{to_string}
#|pub extend Position with Eq::{equal}
#|#deprecated("Use `@json.from_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Json with FromJson::{from_json}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend Json with Show::{to_string, output}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Json with ToJson::{to_json}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend JsonDecodeError with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend JsonDecodeError with Eq::{not_equal}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend JsonDecodeError with Show::{output}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend JsonDecodeError with ToJson::{to_json}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend JsonPath with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend JsonPath with Eq::{not_equal}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend JsonPath with Show::{output}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend JsonPath with ToJson::{to_json}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ParseError with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ParseError with Eq::{not_equal}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ParseError with Show::{output}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ParseError with ToJson::{to_json}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Position with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Position with Eq::{not_equal}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Position with ToJson::{to_json}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Replacer with @debug.Debug::{to_repr}
),
"from_json.mbt": (
#|#warnings("-deprecated_syntax")
#|pub(all) suberror JsonDecodeError {
#| JsonDecodeError((JsonPath, String))
#|} derive(Eq, Show, ToJson, @debug.Debug)
#|pub(open) trait FromJson {
#| fn 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 fn from_json(json, path) {
#| match json {
#| true => true
#| false => false
#| _ => decode_error(path, "Bool::from_json: expected boolean")
#| }
#|}
#|pub impl FromJson for Int with fn 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 fn from_json(json, path) {
#| guard json is String(str) else {
#| decode_error(
#| path, "Int64::from_json: expected number in string representation",
#| )
#| }
#| @internal/strconv.parse_int64(str) catch {
#| Failure::Failure(error) =>
#| decode_error(path, "Int64::from_json: parsing failure \{error}")
#| error => decode_error(path, "Int64::from_json: parsing failure \{error}")
#| }
#|}
#|pub impl FromJson for UInt with fn 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 fn from_json(json, path) {
#| guard json is String(str) else {
#| decode_error(
#| path, "UInt64::from_json: expected number in string representation",
#| )
#| }
#| @internal/strconv.parse_uint64(str) catch {
#| Failure::Failure(error) =>
#| decode_error(path, "UInt64::from_json: parsing failure \{error}")
#| error => decode_error(path, "UInt64::from_json: parsing failure \{error}")
#| }
#|}
#|pub impl FromJson for Double with fn 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 Float with fn from_json(json, path) {
#| match json {
#| String("NaN") => @float.not_a_number
#| String("Infinity") => @float.infinity
#| String("-Infinity") => @float.neg_infinity
#| Number(n, ..) if n != @double.infinity && n != @double.neg_infinity =>
#| Float::from_double(n)
#| _ => decode_error(path, "Float::from_json: expected number")
#| }
#|}
#|pub impl FromJson for String with fn from_json(json, path) {
#| guard json is String(a) else {
#| decode_error(path, "String::from_json: expected string")
#| }
#| a
#|}
#|pub impl FromJson for StringView with fn 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 fn 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_get(0).unsafe_to_char()
#| } else if len == 2 {
#| let c1 = a.unsafe_get(0).to_int()
#| let c2 = a.unsafe_get(1).to_int()
#| 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 fn from_json(json, path) {
#| guard json is Array(a) else {
#| decode_error(path, "Array::from_json: expected array")
#| }
#| guard! JsonPath::Index(path, index=0) is (Index(_) as new_path)
#| [
#| for i, x in a => {
#| new_path.index = i
#| FromJson::from_json(x, new_path)
#| }
#| ]
#|}
#|pub impl[X : FromJson] FromJson for ArrayView[X] with fn from_json(json, path) {
#| guard json is Array(a) else {
#| decode_error(path, "ArrayView::from_json: expected array")
#| }
#| guard! JsonPath::Index(path, index=0) is (Index(_) as new_path)
#| [
#| for i, x in a => {
#| new_path.index = i
#| FromJson::from_json(x, new_path)
#| }
#| ]
#|}
#|pub impl[X : FromJson] FromJson for FixedArray[X] with fn 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! JsonPath::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 fn from_json(
#| json,
#| path,
#|) {
#| guard json is Object(obj) else {
#| decode_error(path, "Result::from_json: expected object")
#| }
#| if obj.length() != 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 fn from_json(json, path) {
#| guard json is Null else {
#| decode_error(path, "Unit::from_json: expected null")
#| }
#|}
#|pub impl FromJson for Json with fn from_json(json, _path) {
#| json
#|}
#|pub impl FromJson for Bytes with fn from_json(json, path) {
#| guard json is String(a) else {
#| decode_error(path, "Bytes::from_json: expected string")
#| }
#| let buffer = @buffer.Buffer(size_hint=a.length())
#| for x = a[:] {
#| match x {
#| [] => break
#| [
#| .. "\\x",
#| '0'..='9'
#| | 'a'..='f' as x,
#| '0'..='9'
#| | 'a'..='f' as y,
#| .. rest,
#| ] => {
#| let upper = (x.to_int() & 0xF) + (x.to_int() >> 6) * 9
#| let lower = (y.to_int() & 0xF) + (y.to_int() >> 6) * 9
#| buffer.write_byte(((upper << 4) | lower).to_byte())
#| continue rest
#| }
#| [' '..='~' as ch, .. rest] => {
#| guard ch != '\\' && ch != '"' else {
#| decode_error(path, "Bytes::from_json: invalid escape sequence")
#| }
#| buffer.write_byte(ch.to_uint().to_byte())
#| continue rest
#| }
#| _ => decode_error(path, "Bytes::from_json: invalid byte sequence")
#| }
#| }
#| buffer.to_bytes()
#|}
),
"internal_types.mbt": (
#|priv struct ParseContext {
#| mut offset : Int
#| input : StringView
#| end_offset : Int
#|}
#|fn ParseContext::make(input : StringView) -> ParseContext {
#| { offset: 0, input, end_offset: input.length(), }
#|}
#|priv enum Token {
#| Null
#| True
#| False
#| Number(Double, String?)
#| String(String)
#| LBrace
#| RBrace
#| LBracket
#| RBracket
#| Comma
#|}
),
"json.mbt": (
#|#deprecated("Suggestion: `if json is Null { Some(()) } else { None }`")
#|pub fn Json::as_null(self : Json) -> Unit? {
#| guard self is Null else { return None }
#| Some(())
#|}
#|#deprecated("Suggestion: `if json is True { Some(true) } else if json is False { Some(false) } else { None }`")
#|pub fn Json::as_bool(self : Json) -> Bool? {
#| match self {
#| True => Some(true)
#| False => Some(false)
#| _ => None
#| }
#|}
#|#deprecated("Suggestion: `if json is Number(n) { Some(n) } else { None }`")
#|pub fn Json::as_number(self : Json) -> Double? {
#| guard self is Number(n, ..) else { return None }
#| Some(n)
#|}
#|#deprecated("Suggestion: `if json is String(s) { Some(s) } else { None }`")
#|pub fn Json::as_string(self : Json) -> String? {
#| guard self is String(s) else { return None }
#| Some(s)
#|}
#|#deprecated("Suggestion: `if json is Array(array) { Some(array) } else { None }`")
#|pub fn Json::as_array(self : Json) -> Array[Json]? {
#| guard self is Array(arr) else { return None }
#| Some(arr)
#|}
#|#deprecated("Suggestion: `if json is Array(array) { array.get(index) } else { None }`")
#|pub fn Json::item(self : Json, index : Int) -> Json? {
#| if self is Array(arr) {
#| arr.get(index)
#| } else {
#| None
#| }
#|}
#|#deprecated
#|pub fn Json::as_object(self : Json) -> Map[String, Json]? {
#| guard self is Object(obj) else { return None }
#| Some(obj)
#|}
#|#deprecated("Suggestion: `if json is Object(obj) { obj.get(key) } else { None }`")
#|pub fn Json::value(self : Json, key : String) -> Json? {
#| if self is Object(obj) {
#| obj.get(key)
#| } else {
#| None
#| }
#|}
#|#inline
#|fn write_indent(
#| buf : StringBuilder,
#| cache : Array[String],
#| level : Int,
#| indent : Int,
#|) -> Unit {
#| while cache.length() <= level {
#| match cache {
#| [.., last] => cache.push(last + " ".repeat(indent))
#| [] => cache.push("\n")
#| }
#| }
#| buf.write_string(cache[level])
#|}
#|priv enum WriteFrame {
#| Array(Array[Json], mut i~ : Int) // (arr, index)
#| Object(Iter[(String, Json)], mut first~ : Bool) // (kvs, first)
#|}
#|pub struct Replacer {
#| priv f : (String, Json) -> Json?
#|} derive(@debug.Debug)
#|#alias(new, deprecated="Use `Replacer()` instead")
#|pub fn Replacer::Replacer(f : (String, Json) -> Json?) -> Replacer {
#| { f, }
#|}
#|pub fn Replacer::keep(array : ArrayView[StringView]) -> Replacer {
#| { f: (idx, value) => if array.contains(idx) { Some(value) } else { None }, }
#|}
#|pub fn Replacer::exclude(array : ArrayView[StringView]) -> Replacer {
#| { f: (idx, value) => if array.contains(idx) { None } else { Some(value) }, }
#|}
#|pub fn Json::stringify(
#| self : Json,
#| escape_slash? : Bool = false,
#| indent? : Int = 0,
#| replacer? : Replacer,
#|) -> String {
#| let buf = StringBuilder(size_hint=0)
#| let indent_cache : Array[String] = []
#| let stack : Array[WriteFrame] = []
#| let mut depth = 0
#| for x = Some(self) {
#| match x {
#| Some(value) => {
#| match value {
#| Object(members) =>
#| if members.is_empty() {
#| buf.write_string("{}")
#| } else {
#| depth += 1
#| buf.write_char('{')
#| if indent > 0 {
#| write_indent(buf, indent_cache, depth, indent)
#| }
#| stack.push(Object(members.iter(), first=true))
#| }
#| Array(arr) =>
#| if arr.is_empty() {
#| buf.write_string("[]")
#| } else {
#| depth += 1
#| buf.write_char('[')
#| if indent > 0 {
#| write_indent(buf, indent_cache, depth, indent)
#| }
#| stack.push(Array(arr, i=0))
#| }
#| String(s) => {
#| buf.write_char('\"')
#| write_escaped(buf, s, escape_slash~)
#| buf.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")
#| }
#| continue None
#| }
#| None =>
#| match stack {
#| [] => break
#| [.., Array(arr, i~) as frame] =>
#| if i < arr.length() {
#| let element = arr[i]
#| frame.i = i + 1
#| if i > 0 {
#| buf.write_char(',')
#| if indent > 0 {
#| write_indent(buf, indent_cache, depth, indent)
#| }
#| }
#| continue Some(element)
#| } else {
#| depth -= 1
#| ignore(stack.pop())
#| if indent > 0 {
#| write_indent(buf, indent_cache, depth, indent)
#| }
#| buf.write_char(']')
#| continue None
#| }
#| [.., Object(iterator, first~) as frame] =>
#| match iterator.next() {
#| Some((k, v)) => {
#| let mut v2 = v
#| if replacer is Some(replacer) {
#| if (replacer.f)(k, v) is Some(v) {
#| v2 = v
#| } else {
#| continue None
#| }
#| }
#| if !first {
#| buf.write_char(',')
#| if indent > 0 {
#| write_indent(buf, indent_cache, depth, indent)
#| }
#| }
#| buf.write_char('\"')
#| write_escaped(buf, k, escape_slash~)
#| buf.write_char('\"')
#| buf.write_char(':')
#| if indent > 0 {
#| buf.write_char(' ')
#| }
#| frame.first = false
#| continue Some(v2)
#| }
#| None => {
#| depth -= 1
#| ignore(stack.pop())
#| if indent > 0 {
#| write_indent(buf, indent_cache, depth, indent)
#| }
#| buf.write_char('}')
#| continue None
#| }
#| }
#| }
#| }
#| }
#| buf.to_string()
#|}
#|#inline
#|fn need_escape_scalar(
#| str : String,
#| escape_slash : Bool,
#| start : Int,
#| end : Int,
#|) -> Bool {
#| for i in start.. Unit {
#| ignore(@v128.i16x8_splat(0))
#|}
#|#cfg(not(any(target="native", target="wasm")))
#|fn need_escape(str : String, escape_slash : Bool) -> Bool {
#| need_escape_scalar(str, escape_slash, 0, str.length())
#|}
#|#cfg(any(target="native", target="wasm"))
#|fn need_escape(str : String, escape_slash : Bool) -> Bool {
#| let len = str.length()
#| guard len >= 8 else { return need_escape_scalar(str, escape_slash, 0, len) }
#| let control_limit = @v128.i16x8_splat(' ')
#| let quote = @v128.i16x8_splat('"')
#| let backslash = @v128.i16x8_splat('\\')
#| let slash = @v128.i16x8_splat('/')
#| let tail_start = for pos = 0; pos + 8 <= len; {
#| let block = @v128.v128_load_i16x8(str, pos)
#| let escaped = @v128.v128_or_(
#| @v128.i16x8_lt_u(block, control_limit),
#| @v128.v128_or_(
#| @v128.i16x8_eq(block, quote),
#| @v128.i16x8_eq(block, backslash),
#| ),
#| )
#| let escaped = if escape_slash {
#| @v128.v128_or_(escaped, @v128.i16x8_eq(block, slash))
#| } else {
#| escaped
#| }
#| if @v128.v128_any_true(escaped) {
#| return true
#| }
#| continue pos + 8
#| } nobreak {
#| pos
#| }
#| need_escape_scalar(str, escape_slash, tail_start, len)
#|}
#|fn write_escaped(
#| buf : StringBuilder,
#| str : String,
#| escape_slash~ : Bool,
#|) -> Unit {
#| if !need_escape(str, escape_slash) {
#| buf.write_string(str)
#| return
#| }
#| for code in str.code_units() {
#| match code {
#| '"' => buf.write_string("\\\"")
#| '\\' => buf.write_string("\\\\")
#| '/' =>
#| if escape_slash {
#| buf.write_string("\\/")
#| } else {
#| buf.write_char('/')
#| }
#| '\n' => buf.write_string("\\n")
#| '\r' => buf.write_string("\\r")
#| '\b' => buf.write_string("\\b")
#| '\t' => buf.write_string("\\t")
#| 0x0C => buf.write_string("\\f")
#| _ =>
#| if code < ' ' {
#| buf.write_string("\\u00")
#| buf.write_string(code.to_byte().to_hex())
#| } else {
#| buf.write_char(code.unsafe_to_char())
#| }
#| }
#| }
#|}
#|pub fn Json::transform(self : Self, replacer : Replacer) -> Json {
#| match self {
#| Object(members) =>
#| members
#| .iter()
#| .filter_map(pair => {
#| let (k, v) = pair
#| if (replacer.f)(k, v) is Some(v2) {
#| Some((k, v2.transform(replacer)))
#| } else {
#| None
#| }
#| })
#| |> Map::from_iter()
#| |> Object
#| Array(members) => Array(members.map(m => m.transform(replacer)))
#| value => value
#| }
#|}
#|pub impl ToJson for Json with fn to_json(self) {
#| self
#|}
#|#callsite(autofill(args_loc, loc))
#|#alias(inspect, deprecated="Use `json_inspect` without package name instead.")
#|pub fn json_inspect(
#| obj : &ToJson,
#| content? : Json,
#| loc~ : SourceLoc,
#| args_loc~ : ArgsLoc,
#|) -> Unit raise InspectError {
#| let loc = loc.to_json_string()
#| let args_loc = args_loc.to_json()
#| let actual = obj.to_json().stringify(escape_slash=false)
#| let want = match content {
#| Some(x) | (None with x = "".to_json()) => 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, @debug.Debug)
#|pub fn JsonPath::add_index(self : JsonPath, index : Int) -> JsonPath {
#| Index(self, index~)
#|}
#|pub fn JsonPath::add_key(self : JsonPath, key : String) -> JsonPath {
#| Key(self, key~)
#|}
#|pub impl Show for JsonPath with fn output(self, logger) {
#| fn write_token(logger : &Logger, token : String) -> Unit {
#| if !token.contains_any(chars="~/") {
#| logger.write_string(token)
#| return
#| }
#| for ch in token.iter() {
#| match ch {
#| '~' => logger <+ "~0"
#| '/' => logger <+ "~1"
#| _ => logger.write_char(ch)
#| }
#| }
#| }
#| fn build_path(path : JsonPath, logger : &Logger) -> Unit {
#| match path {
#| Root => ()
#| Key(parent, key~) =>
#| logger <+
#| "\{cb => build_path(parent, cb)}/\{cb => write_token(cb, key)}"
#| Index(parent, index~) =>
#| logger <+
#| "\{cb => build_path(parent, cb)}/\{cb => cb.write_object(index)}"
#| }
#| }
#| build_path(self, logger)
#|}
#|pub impl ToJson for JsonPath with fn to_json(self) {
#| String(self.to_string())
#|}
#|test "show JsonPath - JSON Pointer format" {
#| @builtin.inspect(Root, content="")
#| @builtin.inspect(Root.add_key("foo"), content="/foo")
#| @builtin.inspect(Root.add_index(0), content="/0")
#| let path : JsonPath = 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",
#| )
#|}
#|test "show JsonPath - special characters escaping" {
#| @builtin.inspect(Root.add_key("foo~bar"), content="/foo~0bar")
#| @builtin.inspect(Root.add_key("foo~~bar~~"), content="/foo~0~0bar~0~0")
#| @builtin.inspect(Root.add_key("foo/bar"), content="/foo~1bar")
#| @builtin.inspect(Root.add_key("foo//bar//"), content="/foo~1~1bar~1~1")
#| @builtin.inspect(Root.add_key("foo~/bar"), content="/foo~0~1bar")
#| @builtin.inspect(Root.add_key("~foo/bar~"), content="/~0foo~1bar~0")
#| @builtin.inspect(
#| Root.add_key("a/b").add_key("c~d").add_index(0).add_key("e~/f"),
#| content="/a~1b/c~0d/0/e~0~1f",
#| )
#| @builtin.inspect(Root.add_key(""), content="/")
#| @builtin.inspect(Root.add_key("~/"), content="/~0~1")
#|}
#|test "show JsonPath - RFC 6901 compliance examples" {
#| @builtin.inspect(Root, content="")
#| @builtin.inspect(Root.add_key("foo"), content="/foo")
#| @builtin.inspect(Root.add_key("foo").add_index(0), content="/foo/0")
#| @builtin.inspect(Root.add_key(""), content="/")
#| @builtin.inspect(Root.add_key("a/b"), content="/a~1b")
#| @builtin.inspect(Root.add_key("c%d"), content="/c%d")
#| @builtin.inspect(Root.add_key("e^f"), content="/e^f")
#| @builtin.inspect(Root.add_key("g|h"), content="/g|h")
#| @builtin.inspect(Root.add_key("i\\j"), content="/i\\j")
#| @builtin.inspect(Root.add_key("k\"l"), content="/k\"l")
#| @builtin.inspect(Root.add_key(" "), content="/ ")
#| @builtin.inspect(Root.add_key("m~n"), content="/m~0n")
#|}
),
"lex_main.mbt": (
#|fn ParseContext::lex_value(
#| ctx : ParseContext,
#| allow_rbracket~ : Bool,
#|) -> Token raise ParseError {
#| ctx.lex_skip_whitespace()
#| match ctx.read_char() {
#| Some('{') => return LBrace
#| Some('[') => return LBracket
#| Some(']') =>
#| if allow_rbracket {
#| return RBracket
#| } else {
#| ctx.invalid_char(shift=-1)
#| }
#| Some('n') => {
#| ctx.expect_ascii_char(b'u')
#| ctx.expect_ascii_char(b'l')
#| ctx.expect_ascii_char(b'l')
#| return Null
#| }
#| Some('t') => {
#| ctx.expect_ascii_char(b'r')
#| ctx.expect_ascii_char(b'u')
#| ctx.expect_ascii_char(b'e')
#| return True
#| }
#| Some('f') => {
#| ctx.expect_ascii_char(b'a')
#| ctx.expect_ascii_char(b'l')
#| ctx.expect_ascii_char(b's')
#| ctx.expect_ascii_char(b'e')
#| return False
#| }
#| Some('-') =>
#| match ctx.read_char() {
#| Some('0') => {
#| let { value: n, repr, } = ctx.lex_zero(start=ctx.offset - 2)
#| return Number(n, repr.map(repr => repr.to_owned()))
#| }
#| Some('1'..='9') => {
#| let { value: n, repr, } = ctx.lex_decimal_integer(
#| start=ctx.offset - 2,
#| )
#| return Number(n, repr.map(repr => repr.to_owned()))
#| }
#| Some(_) => ctx.invalid_char(shift=-1)
#| None => raise InvalidEof
#| }
#| Some('0') => {
#| let { value: n, repr, } = ctx.lex_zero(start=ctx.offset - 1)
#| return Number(n, repr.map(repr => repr.to_owned()))
#| }
#| Some('1'..='9') => {
#| let { value: n, repr, } = ctx.lex_decimal_integer(start=ctx.offset - 1)
#| return Number(n, repr.map(repr => repr.to_owned()))
#| }
#| Some('"') => {
#| let s = ctx.lex_string()
#| return String(s)
#| }
#| Some(c) => {
#| 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_get(ctx.offset).to_int()
#| ctx.offset += 1
#| if c1 >= 0xD800 && c1 <= 0xDBFF {
#| if ctx.offset < ctx.end_offset {
#| let c2 = ctx.input.unsafe_get(ctx.offset).to_int()
#| 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_get(ctx.offset).to_int()
#| 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_get(ctx.offset).to_int()
#| 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_get(ctx.offset).to_int()
#| 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')
#| try ctx.expect_char('d') catch {
#| err => json_inspect(err, content="InvalidEof")
#| } noraise {
#| _ => fail("expected 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')
#| try ctx.expect_char('d') catch {
#| err => json_inspect(err, content="InvalidEof")
#| } noraise {
#| _ => fail("expected InvalidEof")
#| }
#|}
#|fn ParseContext::lex_skip_whitespace(ctx : ParseContext) -> Unit {
#| let end = ctx.end_offset
#| ctx.offset = for offset = ctx.offset {
#| if offset >= end {
#| break offset
#| }
#| match ctx.input.unsafe_get(offset) {
#| ' ' | '\t' | '\r' | '\n' => continue offset + 1
#| _ => break offset
#| }
#| }
#|}
#|test "lex_skip_whitespace" {
#| let ctx = ParseContext::make("")
#| ctx.lex_skip_whitespace()
#| json_inspect(ctx.offset, content=0)
#| let ctx = ParseContext::make(" \t\r\n")
#| ctx.lex_skip_whitespace()
#| json_inspect(ctx.offset, content=6)
#| let ctx = ParseContext::make(" \t\r\n{")
#| ctx.lex_skip_whitespace()
#| json_inspect(ctx.offset, content=4)
#| let ctx = ParseContext::make("{}")
#| ctx.lex_skip_whitespace()
#| json_inspect(ctx.offset, content=0)
#| let ctx = ParseContext::make("\u{00A0}x")
#| ctx.lex_skip_whitespace()
#| json_inspect(ctx.offset, content=0)
#|}
#|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": (
#|const SAFE_INTEGER_LIMIT : Int64 = 9007199254740991L
#|const MAX_MANTISSA_FAST_PATH : UInt64 = 9007199254740992UL
#|const MIN_EXPONENT_FAST_PATH : Int64 = -22L
#|const MAX_EXPONENT_FAST_PATH : Int64 = 22L
#|const MAX_EXPONENT_DISGUISED_FAST_PATH : Int64 = 37L
#|const EXPONENT_CAP : Int64 = 100000L
#|const MAX_UINT64 : UInt64 = 0xffffffffffffffffUL
#|let pow10_table : ReadOnlyArray[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,
#|]
#|let int_pow10_table : ReadOnlyArray[UInt64] = [
#| 1UL, 10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL, 100000000UL,
#| 1000000000UL, 10000000000UL, 100000000000UL, 1000000000000UL, 10000000000000UL,
#| 100000000000000UL, 1000000000000000UL,
#|]
#|#valtype
#|priv struct JsonNumberScan {
#| negative : Bool
#| is_integer : Bool
#| mantissa : UInt64
#| exponent : Int64
#| many_digits : Bool
#|}
#|fn json_pow10_fast_path(exponent : Int) -> Double {
#| pow10_table[exponent & 31]
#|}
#|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 = MAX_UINT64 / b
#| if a > quotient {
#| None
#| } else {
#| Some(a * b)
#| }
#|}
#|fn JsonNumberScan::try_fast_double(self : JsonNumberScan) -> Double {
#| if self.mantissa == 0UL {
#| let value = 0.0
#| return if self.negative { -value } else { value }
#| }
#| if self.many_digits ||
#| self.exponent < MIN_EXPONENT_FAST_PATH ||
#| self.exponent > MAX_EXPONENT_DISGUISED_FAST_PATH ||
#| self.mantissa > MAX_MANTISSA_FAST_PATH {
#| return @double.not_a_number
#| }
#| let value = if self.exponent <= MAX_EXPONENT_FAST_PATH {
#| let value = self.mantissa.to_double()
#| if self.exponent < 0L {
#| value / json_pow10_fast_path(-self.exponent.to_int())
#| } else {
#| value * json_pow10_fast_path(self.exponent.to_int())
#| }
#| } else {
#| let shift = self.exponent - MAX_EXPONENT_FAST_PATH
#| guard checked_mul(self.mantissa, int_pow10_table[shift.to_int()])
#| is Some(mantissa) else {
#| return @double.not_a_number
#| }
#| if mantissa > MAX_MANTISSA_FAST_PATH {
#| return @double.not_a_number
#| }
#| mantissa.to_double() * json_pow10_fast_path(MAX_EXPONENT_FAST_PATH.to_int())
#| }
#| if self.negative {
#| -value
#| } else {
#| value
#| }
#|}
#|fn ParseContext::scan_json_number(
#| ctx : ParseContext,
#| start : Int,
#| end : Int,
#|) -> JsonNumberScan {
#| let negative = ctx.input.unsafe_get(start) == '-'
#| let mut has_decimal = false
#| let mut has_exponent = false
#| let mut exponent_negative = false
#| let mut exponent_part = 0L
#| let mut fractional_digits = 0
#| let mut mantissa = 0UL
#| let mut significant_digits = 0
#| let mut seen_nonzero = false
#| for i in (if negative { start + 1 } else { start }).. {
#| let digit = c.to_int() - '0'
#| if has_exponent {
#| if exponent_part < EXPONENT_CAP {
#| let next_exponent = exponent_part * 10L + digit.to_int64()
#| exponent_part = if next_exponent > EXPONENT_CAP {
#| EXPONENT_CAP
#| } else {
#| next_exponent
#| }
#| }
#| } else {
#| if has_decimal {
#| fractional_digits += 1
#| }
#| if digit != 0 || seen_nonzero {
#| seen_nonzero = true
#| significant_digits += 1
#| if significant_digits <= 19 {
#| mantissa = mantissa * 10UL +
#| UInt64::extend_uint(digit.reinterpret_as_uint())
#| }
#| }
#| }
#| }
#| '.' => has_decimal = true
#| 'e' | 'E' => {
#| has_exponent = true
#| if i + 1 < end {
#| let next = ctx.input.unsafe_get(i + 1)
#| if next == '-' {
#| exponent_negative = true
#| }
#| }
#| }
#| _ => ()
#| }
#| }
#| let exponent_part = if exponent_negative {
#| -exponent_part
#| } else {
#| exponent_part
#| }
#| {
#| negative,
#| is_integer: !has_decimal && !has_exponent,
#| mantissa,
#| exponent: exponent_part - fractional_digits.to_int64(),
#| many_digits: significant_digits > 19,
#| }
#|}
#|#valtype
#|priv struct LexedNumber {
#| repr : StringView?
#| value : Double
#|}
#|fn ParseContext::lex_integer_end(
#| ctx : ParseContext,
#| start : Int,
#| end : Int,
#|) -> LexedNumber {
#| let negative = ctx.input.unsafe_get(start) == '-'
#| let number_start = if negative { start + 1 } else { start }
#| for i = number_start, acc = 0L {
#| if i >= end {
#| let value = if negative { -acc } else { acc }
#| break { value: value.to_double(), repr: None, }
#| }
#| let digit = (ctx.input.unsafe_get(i).to_int() - '0').to_int64()
#| if acc > (SAFE_INTEGER_LIMIT - digit) / 10L {
#| let s = ctx.input.view(start_offset=start, end_offset=end)
#| try {
#| let value = @internal/strconv.parse_double(s)
#| return { value, repr: Some(s), }
#| } catch {
#| _ =>
#| return if negative {
#| { value: @double.neg_infinity, repr: Some(s), }
#| } else {
#| { value: @double.infinity, repr: Some(s), }
#| }
#| }
#| }
#| continue i + 1, acc * 10L + digit
#| }
#|}
#|fn ParseContext::lex_decimal_integer(
#| ctx : ParseContext,
#| start~ : Int,
#|) -> LexedNumber raise ParseError {
#| for ;; {
#| match ctx.read_char() {
#| Some('.') => return ctx.lex_decimal_point(start~)
#| Some('e' | 'E') => return ctx.lex_decimal_exponent(start~)
#| Some('0'..='9') => continue
#| Some(_) => {
#| 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,
#|) -> LexedNumber raise ParseError {
#| match ctx.read_char() {
#| Some('0'..='9') => ctx.lex_decimal_fraction(start~)
#| Some(_) => ctx.invalid_char(shift=-1)
#| None => raise InvalidEof
#| }
#|}
#|fn ParseContext::lex_decimal_fraction(
#| ctx : ParseContext,
#| start~ : Int,
#|) -> LexedNumber raise ParseError {
#| for ;; {
#| match ctx.read_char() {
#| Some('e' | 'E') => return ctx.lex_decimal_exponent(start~)
#| Some('0'..='9') => continue
#| Some(_) => {
#| 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,
#|) -> LexedNumber raise ParseError {
#| match ctx.read_char() {
#| Some('+' | '-') => return ctx.lex_decimal_exponent_sign(start~)
#| Some('0'..='9') => return ctx.lex_decimal_exponent_integer(start~)
#| Some(_) => {
#| ctx.offset -= 1
#| ctx.invalid_char()
#| }
#| None => raise InvalidEof
#| }
#|}
#|fn ParseContext::lex_decimal_exponent_sign(
#| ctx : ParseContext,
#| start~ : Int,
#|) -> LexedNumber raise ParseError {
#| match ctx.read_char() {
#| Some('0'..='9') => return ctx.lex_decimal_exponent_integer(start~)
#| Some(_) => {
#| ctx.offset -= 1
#| ctx.invalid_char()
#| }
#| None => raise InvalidEof
#| }
#|}
#|fn ParseContext::lex_decimal_exponent_integer(
#| ctx : ParseContext,
#| start~ : Int,
#|) -> LexedNumber {
#| for ;; {
#| match ctx.read_char() {
#| Some('0'..='9') => continue
#| Some(_) => {
#| 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,
#|) -> LexedNumber raise ParseError {
#| match ctx.read_char() {
#| Some('.') => ctx.lex_decimal_point(start~)
#| Some('e' | 'E') => ctx.lex_decimal_exponent(start~)
#| Some('0'..='9') => {
#| ctx.offset -= 1
#| ctx.invalid_char()
#| }
#| Some(_) => {
#| 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,
#|) -> LexedNumber {
#| let scan = ctx.scan_json_number(start, end)
#| if scan.is_integer {
#| if !scan.many_digits &&
#| scan.exponent == 0L &&
#| scan.mantissa <= SAFE_INTEGER_LIMIT.reinterpret_as_uint64() {
#| let v = scan.mantissa.reinterpret_as_int64().to_double()
#| let value = if scan.negative { -v } else { v }
#| return { value, repr: None, }
#| }
#| return ctx.lex_integer_end(start, end)
#| }
#| let fast = scan.try_fast_double()
#| if !fast.is_nan() {
#| return { value: fast, repr: None, }
#| }
#| if !scan.many_digits {
#| let fast = @internal/strconv.try_eisel_lemire64(
#| scan.mantissa,
#| scan.exponent,
#| scan.negative,
#| )
#| if !fast.is_nan() {
#| return { value: fast, repr: None, }
#| }
#| }
#| let s = ctx.input.view(start_offset=start, end_offset=end)
#| try {
#| let d = @internal/strconv.parse_double(s)
#| { value: d, repr: None, }
#| } catch {
#| _ =>
#| if scan.negative {
#| { value: @double.neg_infinity, repr: Some(s), }
#| } else {
#| { value: @double.infinity, repr: Some(s), }
#| }
#| }
#|}
),
"lex_string.mbt": (
#|fn ParseContext::lex_string(ctx : ParseContext) -> String raise ParseError {
#| let string_start = ctx.offset
#| for i in string_start.. String raise ParseError {
#| let buf = StringBuilder()
#| let mut start = ctx.offset
#| fn flush(end : Int) {
#| if start > 0 && end > start {
#| buf.write_view(ctx.input[start:end])
#| }
#| }
#| for ;; {
#| match ctx.read_char() {
#| Some('"') => {
#| flush(ctx.offset - 1)
#| break
#| }
#| 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 escape_start = ctx.offset - 2
#| let c = ctx.lex_hex_digits(4)
#| if c is (0xD800..=0xDBFF) {
#| match ctx.read_char() {
#| Some('\\') => ()
#| Some(_) => ctx.unpaired_surrogate(escape_start)
#| None => raise InvalidEof
#| }
#| match ctx.read_char() {
#| Some('u') => ()
#| Some(_) => ctx.unpaired_surrogate(escape_start)
#| None => raise InvalidEof
#| }
#| let c2 = ctx.lex_hex_digits(4)
#| if c2 is (0xDC00..=0xDFFF) {
#| let combined = (c << 10) + c2 - 0x35fdc00
#| buf.write_char(combined.unsafe_to_char())
#| } else {
#| ctx.unpaired_surrogate(escape_start)
#| }
#| } else if c is (0xDC00..=0xDFFF) {
#| ctx.unpaired_surrogate(escape_start)
#| } else {
#| buf.write_char(c.unsafe_to_char())
#| }
#| }
#| Some(c) => ctx.invalid_char(shift=-c.utf16_len())
#| 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[T] ParseContext::unpaired_surrogate(
#| ctx : ParseContext,
#| escape_start : Int,
#|) -> T raise ParseError {
#| ctx.invalid_char(shift=escape_start - ctx.offset)
#|}
#|fn ParseContext::lex_hex_digits(
#| ctx : ParseContext,
#| n : Int,
#|) -> Int raise ParseError {
#| for _ in 0.. c.to_int() - '0'
#| Some('A'..='F' as c) => c.to_int() - 'A' + 10
#| Some('a'..='f' as c) => c.to_int() - 'a' + 10
#| Some(c) => ctx.invalid_char(shift=-c.utf16_len())
#| None => raise InvalidEof
#| }
#| continue (r << 4) | d
#| } nobreak {
#| r
#| }
#|}
),
"parse.mbt": (
#|pub fn valid(input : StringView) -> Bool {
#| try {
#| parse(input) |> ignore
#| true
#| } catch {
#| _ => return false
#| }
#|}
#|#label_migration(max_nesting_depth, fill=false)
#|pub fn parse(
#| input : StringView,
#| max_nesting_depth? : Int = 1024,
#|) -> Json raise ParseError {
#| let ctx = ParseContext::make(input)
#| let val = ctx.parse_value(remaining_available_depth=max_nesting_depth)
#| ctx.lex_skip_whitespace()
#| if ctx.offset >= ctx.end_offset {
#| val
#| } else {
#| ctx.invalid_char()
#| }
#|}
#|fn ParseContext::parse_value(
#| ctx : ParseContext,
#| remaining_available_depth~ : Int,
#|) -> Json raise ParseError {
#| let tok = ctx.lex_value(allow_rbracket=false)
#| ctx.parse_value2(tok, remaining_available_depth~)
#|}
#|fn ParseContext::parse_value2(
#| ctx : ParseContext,
#| tok : Token,
#| remaining_available_depth~ : Int,
#|) -> 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(remaining_available_depth~)
#| LBracket => ctx.parse_array(remaining_available_depth~)
#| RBracket | RBrace | Comma => abort("unreachable")
#| }
#|}
#|fn ParseContext::parse_object(
#| ctx : ParseContext,
#| remaining_available_depth~ : Int,
#|) -> Json raise ParseError {
#| if remaining_available_depth <= 0 {
#| raise DepthLimitExceeded
#| }
#| let child_remaining_available_depth = remaining_available_depth - 1
#| let map = Map([])
#| for x = ctx.lex_property_name() {
#| match x {
#| RBrace => break Json::object(map)
#| String(name) => {
#| ctx.lex_after_property_name()
#| map[name] = ctx.parse_value(
#| remaining_available_depth=child_remaining_available_depth,
#| )
#| match ctx.lex_after_object_value() {
#| Comma => continue ctx.lex_property_name2()
#| RBrace => break Json::object(map)
#| _ => abort("unreachable")
#| }
#| }
#| _ => abort("unreachable")
#| }
#| }
#|}
#|fn ParseContext::parse_array(
#| ctx : ParseContext,
#| remaining_available_depth~ : Int,
#|) -> Json raise ParseError {
#| if remaining_available_depth <= 0 {
#| raise DepthLimitExceeded
#| }
#| let child_remaining_available_depth = remaining_available_depth - 1
#| let vec = []
#| for x = ctx.lex_value(allow_rbracket=true) {
#| match x {
#| RBracket => break Json::array(vec)
#| tok => {
#| vec.push(
#| ctx.parse_value2(
#| tok,
#| remaining_available_depth=child_remaining_available_depth,
#| ),
#| )
#| let tok2 = ctx.lex_after_array_value()
#| match tok2 {
#| Comma => continue ctx.lex_value(allow_rbracket=false)
#| RBracket => break Json::array(vec)
#| _ => abort("unreachable")
#| }
#| }
#| }
#| }
#|}
),
"to_json.mbt": (
#|pub fn[T : ToJson] to_json(value : T) -> Json {
#| ToJson::to_json(value)
#|}
),
"tuple_fromjson.mbt": (
#|pub impl[A : FromJson, B : FromJson] FromJson for (A, B) with fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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, @debug.Debug)
#|pub(all) suberror ParseError {
#| InvalidChar(Position, Char)
#| InvalidEof
#| InvalidNumber(Position, String)
#| InvalidIdentEscape(Position)
#| DepthLimitExceeded
#|} derive(Eq, ToJson, @debug.Debug)
#|pub impl Show for ParseError with fn output(self, logger) {
#| match self {
#| InvalidChar({ line, column, }, c) =>
#| logger <+
#| $|Invalid character \{c.escape()} at line \{line}, column \{column}
#| InvalidEof => logger <+ "Unexpected end of file"
#| InvalidNumber({ line, column, }, s) =>
#| logger <+
#| $|Invalid number \{s} at line \{line}, column \{column}
#| InvalidIdentEscape({ line, column, }) =>
#| logger <+
#| $|Invalid escape sequence in identifier at line \{line}, column \{column}
#| DepthLimitExceeded =>
#| logger <+
#| $|Depth limit exceeded, please increase the max_nesting_depth parameter
#| }
#|}
#|#deprecated("Use Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl Show for Json
#|#warnings("-deprecated")
#|pub impl Show for Json with fn output(self, logger) {
#| match self {
#| Null => logger <+ "Null"
#| True => logger <+ "True"
#| False => logger <+ "False"
#| Number(n, repr~) => {
#| fn write_contents(cb : &Logger) -> Unit {
#| Show::output(n, cb)
#| if repr is Some(repr) {
#| cb.write_string(", repr=Some(")
#| Show::output(repr, cb)
#| cb.write_string(")")
#| }
#| }
#| logger <+ "Number(\{cb => write_contents(cb)})"
#| }
#| String(s) => logger <+ "String(\{cb => Show::output(s, cb)})"
#| Array(a) => logger <+ "Array(\{cb => Show::output(a, cb)})"
#| Object(o) => logger <+ "Object(\{cb => Show::output(o, cb)})"
#| }
#|}
),
"utils.mbt": (
#|fn offset_to_position(input : StringView, offset : Int) -> Position {
#| for code_unit in input.code_units()[:offset]; line = 1, column = 0 {
#| if code_unit == '\n' {
#| continue line + 1, 0
#| } else {
#| continue line, column + 1
#| }
#| } nobreak {
#| { line, column, }
#| }
#|}
#|fn[T] ParseContext::invalid_char(
#| ctx : ParseContext,
#| shift? : Int = 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_lazy_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/lazy",
deps={},
files={
"debug.mbt": (
#|pub impl[A : @debug.Debug] @debug.Debug for Lazy[A] with fn to_repr(self) {
#| match self.state {
#| Forced(v) => @debug.Repr::opaque_("Lazy", Repr(v))
#| Forcing => @debug.Repr::opaque_("Lazy", @debug.Repr::literal("forcing"))
#| Unforced(_) => @debug.Repr::opaque_("Lazy", @debug.Repr::omitted())
#| }
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Lazy with @debug.Debug::{to_repr}
),
"lazy.mbt": (
#|priv enum LazyState[A] {
#| Unforced(() -> A)
#| Forcing
#| Forced(A)
#|}
#|struct Lazy[A] {
#| mut state : LazyState[A]
#|}
#|#owned(thunk)
#|pub fn[A] Lazy::Lazy(thunk : () -> A) -> Lazy[A] {
#| { state: Unforced(thunk), }
#|}
#|#owned(value)
#|pub fn[A] Lazy::ready(value : A) -> Lazy[A] {
#| { state: Forced(value), }
#|}
#|pub fn[A] Lazy::peek(self : Lazy[A]) -> A? {
#| match self.state {
#| Forced(v) => Some(v)
#| _ => None
#| }
#|}
#|pub fn[A] Lazy::force(self : Lazy[A]) -> A {
#| match self.state {
#| Forced(v) => v
#| Forcing => abort("Lazy::force: reentrant force on the same cell")
#| Unforced(thunk) => {
#| self.state = Forcing
#| let v = thunk()
#| self.state = Forced(v)
#| v
#| }
#| }
#|}
),
},
)
///|
let moonbitlang_core_lazy_list_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/lazy_list",
deps={},
files={
"debug.mbt": (
#|pub impl[A : @debug.Debug] @debug.Debug for LazyList[A] with fn to_repr(self) {
#| let parts = []
#| for cur = self {
#| match cur.cell {
#| Empty => break
#| Cons(x, tail~) => {
#| parts.push(@debug.Repr(x))
#| match tail.peek() {
#| Some(next) => continue next
#| None => {
#| parts.push(@debug.Repr::omitted())
#| break
#| }
#| }
#| }
#| }
#| }
#| @debug.Repr::opaque_("LazyList", @debug.Repr::array(parts))
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend LazyList with @debug.Debug::{to_repr}
),
"lazy_list.mbt": (
#|#owned(head, tail)
#|fn[A] cons(head : A, tail : LazyList[A]) -> LazyList[A] {
#| { cell: Cons(head, tail=Tail::ready(tail)), }
#|}
#|#as_free_fn
#|pub fn[A] LazyList::empty() -> LazyList[A] {
#| { cell: Empty, }
#|}
#|#as_free_fn
#|#owned(head, tail)
#|pub fn[A] LazyList::lazy_cons(
#| head : A,
#| tail : () -> LazyList[A],
#|) -> LazyList[A] {
#| { cell: Cons(head, tail=Tail::delay(tail)), }
#|}
#|#as_free_fn
#|pub fn[A] LazyList::from_iter(iter : Iter[A]) -> LazyList[A] {
#| match iter.next() {
#| None => LazyList::empty()
#| Some(x) => LazyList::lazy_cons(x, () => LazyList::from_iter(iter))
#| }
#|}
#|pub fn[A] LazyList::is_empty(self : LazyList[A]) -> Bool {
#| self.cell is Empty
#|}
#|pub fn[A] LazyList::head(self : LazyList[A]) -> A? {
#| match self.cell {
#| Empty => None
#| Cons(x, ..) => Some(x)
#| }
#|}
#|pub fn[A] LazyList::tail(self : LazyList[A]) -> LazyList[A]? {
#| match self.cell {
#| Empty => None
#| Cons(_, tail~) => Some(tail.force())
#| }
#|}
#|pub fn[A, B] LazyList::map(self : LazyList[A], f : (A) -> B) -> LazyList[B] {
#| match self.cell {
#| Empty => LazyList::empty()
#| Cons(x, tail~) => LazyList::lazy_cons(f(x), () => tail.force().map(f))
#| }
#|}
#|pub fn[A] LazyList::filter(
#| self : LazyList[A],
#| pred : (A) -> Bool,
#|) -> LazyList[A] {
#| let mut cur = self
#| while cur.cell is Cons(x, tail~) {
#| if pred(x) {
#| let t = tail
#| return LazyList::lazy_cons(x, () => t.force().filter(pred))
#| }
#| cur = tail.force()
#| }
#| LazyList::empty()
#|}
#|pub fn[A] LazyList::take(self : LazyList[A], n : Int) -> LazyList[A] {
#| if n <= 0 {
#| return LazyList::empty()
#| }
#| match self.cell {
#| Empty => LazyList::empty()
#| Cons(x, tail~) =>
#| if n == 1 {
#| cons(x, LazyList::empty())
#| } else {
#| LazyList::lazy_cons(x, () => tail.force().take(n - 1))
#| }
#| }
#|}
#|pub fn[A] LazyList::drop(self : LazyList[A], n : Int) -> LazyList[A] {
#| let mut cur = self
#| let mut k = n
#| while k > 0 && cur.cell is Cons(_, tail~) {
#| cur = tail.force()
#| k -= 1
#| }
#| cur
#|}
#|pub fn[A] LazyList::take_while(
#| self : LazyList[A],
#| pred : (A) -> Bool,
#|) -> LazyList[A] {
#| match self.cell {
#| Empty => LazyList::empty()
#| Cons(x, tail~) =>
#| if pred(x) {
#| LazyList::lazy_cons(x, () => tail.force().take_while(pred))
#| } else {
#| LazyList::empty()
#| }
#| }
#|}
#|pub fn[A] LazyList::drop_while(
#| self : LazyList[A],
#| pred : (A) -> Bool raise?,
#|) -> LazyList[A] raise? {
#| let mut cur = self
#| while cur.cell is Cons(x, tail~) && pred(x) {
#| cur = tail.force()
#| }
#| cur
#|}
#|#owned(other)
#|pub fn[A] LazyList::concat(
#| self : LazyList[A],
#| other : LazyList[A],
#|) -> LazyList[A] {
#| match self.cell {
#| Empty => other
#| Cons(x, tail~) =>
#| if other.cell is Empty {
#| self
#| } else {
#| { cell: Cons(x, tail=tail.append(One(Tail::ready(other)))), }
#| }
#| }
#|}
#|fn[A] LazyList::concat_lazy(
#| self : LazyList[A],
#| other_thunk : () -> LazyList[A],
#|) -> LazyList[A] {
#| match self.cell {
#| Empty => other_thunk()
#| Cons(x, tail~) =>
#| { cell: Cons(x, tail=tail.append(One(Tail::delay(other_thunk)))), }
#| }
#|}
#|pub fn[A, B] LazyList::flat_map(
#| self : LazyList[A],
#| f : (A) -> LazyList[B],
#|) -> LazyList[B] {
#| let mut cur = self
#| while cur.cell is Cons(x, tail~) {
#| match f(x).cell {
#| Cons(y, tail=ys) => {
#| let outer_tail = tail
#| return LazyList::lazy_cons(y, () => {
#| ys.force().concat_lazy(() => outer_tail.force().flat_map(f))
#| })
#| }
#| Empty => cur = tail.force()
#| }
#| }
#| LazyList::empty()
#|}
#|pub fn[A, B] LazyList::zip(
#| self : LazyList[A],
#| other : LazyList[B],
#|) -> LazyList[(A, B)] {
#| match (self.cell, other.cell) {
#| (Cons(x, tail=tx), Cons(y, tail=ty)) =>
#| LazyList::lazy_cons((x, y), () => {
#| match tx.force().cell {
#| Empty => LazyList::empty()
#| Cons(_) => tx.force().zip(ty.force())
#| }
#| })
#| _ => LazyList::empty()
#| }
#|}
#|pub fn[A] LazyList::each(
#| self : LazyList[A],
#| f : (A) -> Unit raise?,
#|) -> Unit raise? {
#| let mut cur = self
#| while cur.cell is Cons(x, tail~) {
#| f(x)
#| cur = tail.force()
#| }
#|}
#|pub fn[A, B] LazyList::fold(
#| self : LazyList[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| let mut cur = self
#| let mut acc = init
#| while cur.cell is Cons(x, tail~) {
#| acc = f(acc, x)
#| cur = tail.force()
#| }
#| acc
#|}
#|pub fn[A] LazyList::to_array(self : LazyList[A]) -> Array[A] {
#| let arr = []
#| self.each(x => arr.push(x))
#| arr
#|}
#|pub fn[A] LazyList::iter(self : LazyList[A]) -> Iter[A] {
#| let mut advance : () -> LazyList[A] = () => self
#| Iter::new(() => {
#| match advance().cell {
#| Empty => None
#| Cons(head, tail~) => {
#| advance = () => tail.force()
#| Some(head)
#| }
#| }
#| })
#|}
),
"tail.mbt": (
#|#owned(value)
#|fn[A] Tail::ready(value : LazyList[A]) -> Tail[A] {
#| { state: Forced(value), }
#|}
#|#owned(thunk)
#|fn[A] Tail::delay(thunk : () -> LazyList[A]) -> Tail[A] {
#| { state: Unforced(thunk), }
#|}
#|#owned(pending)
#|fn[A] Tail::append(self : Tail[A], pending : Pending[A]) -> Tail[A] {
#| { state: Append(self, pending), }
#|}
#|fn[A] Tail::peek(self : Tail[A]) -> LazyList[A]? {
#| match self.state {
#| Forced(v) => Some(v)
#| _ => None
#| }
#|}
#|fn[A] Tail::force(self : Tail[A]) -> LazyList[A] {
#| match self.state {
#| Forced(v) => v
#| Forcing => abort("LazyList: reentrant force on the same tail")
#| Unforced(thunk) => {
#| self.state = Forcing
#| let v = thunk()
#| self.state = Forced(v)
#| v
#| }
#| Append(inner, pending) => {
#| self.state = Forcing
#| let (base, rest) = for cur = inner, rest = pending {
#| match cur.state {
#| Append(next, ps) => continue next, ps.concat(rest)
#| _ => break (cur.force(), rest)
#| }
#| }
#| let value = base.append_pending(rest)
#| self.state = Forced(value)
#| value
#| }
#| }
#|}
#|fn[A] LazyList::append_pending(
#| self : LazyList[A],
#| pending : Pending[A],
#|) -> LazyList[A] {
#| for cur = self, rest = pending {
#| match cur.cell {
#| Cons(x, tail~) =>
#| break if rest is Nil {
#| cur
#| } else {
#| { cell: Cons(x, tail=tail.append(rest)), }
#| }
#| Empty =>
#| match rest.uncons() {
#| None => break cur
#| Some((t, more)) => continue t.force(), more
#| }
#| }
#| }
#|}
#|#owned(other)
#|fn[A] Pending::concat(self : Pending[A], other : Pending[A]) -> Pending[A] {
#| match (self, other) {
#| (Nil, _) => other
#| (_, Nil) => self
#| _ => Cat(self, other)
#| }
#|}
#|fn[A] Pending::uncons(self : Pending[A]) -> (Tail[A], Pending[A])? {
#| for cur = self {
#| match cur {
#| Nil => break None
#| One(t) => break Some((t, Nil))
#| Cat(One(t), b) => break Some((t, b))
#| Cat(Cat(x, y), b) => continue Cat(x, Cat(y, b))
#| Cat(Nil, b) => continue b
#| }
#| }
#|}
),
"types.mbt": (
#|priv enum LazyListCell[A] {
#| Empty
#| Cons(A, tail~ : Tail[A])
#|}
#|priv struct Tail[A] {
#| mut state : TailState[A]
#|}
#|priv enum TailState[A] {
#| Unforced(() -> LazyList[A])
#| Forcing
#| Append(Tail[A], Pending[A])
#| Forced(LazyList[A])
#|}
#|priv enum Pending[A] {
#| Nil
#| One(Tail[A])
#| Cat(Pending[A], Pending[A])
#|}
#|struct LazyList[A] {
#| cell : LazyListCell[A]
#|}
),
},
)
///|
let moonbitlang_core_lexbuf_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/lexbuf",
deps={},
files={
"async_lexbuf.mbt": (
#|pub struct AsyncLexbuf {
#| priv source : async () -> String?
#| priv storage : LexbufStorage
#| priv mut cursor : Int
#| priv mut retained_from : Int
#| priv mut eof : Bool
#|}
#|pub fn AsyncLexbuf::from_fn(source : async () -> String?) -> AsyncLexbuf {
#| {
#| source,
#| storage: LexbufStorage(),
#| cursor: 0,
#| retained_from: -1,
#| eof: false,
#| }
#|}
#|#doc(hidden)
#|pub fn AsyncLexbuf::__get_cursor(self : AsyncLexbuf) -> Int {
#| self.cursor
#|}
#|#doc(hidden)
#|pub fn AsyncLexbuf::__buffer_end(self : AsyncLexbuf) -> Int {
#| self.storage.buffer_end
#|}
#|#doc(hidden)
#|pub fn AsyncLexbuf::__eof_reached(self : AsyncLexbuf) -> Bool {
#| self.eof
#|}
#|#doc(hidden)
#|pub fn AsyncLexbuf::__unsafe_code_unit_at(
#| self : AsyncLexbuf,
#| position : Int,
#|) -> Int {
#| debug_assert(() => {
#| position >= self.storage.buffer_start && position < self.__buffer_end()
#| })
#| self.storage.unsafe_code_unit_at(position)
#|}
#|#doc(hidden)
#|pub fn AsyncLexbuf::__advance(self : AsyncLexbuf, count : Int) -> Unit {
#| debug_assert(() => count >= 0 && self.cursor + count <= self.__buffer_end())
#| self.cursor += count
#|}
#|#doc(hidden)
#|pub fn AsyncLexbuf::__retain_from_cursor(self : AsyncLexbuf) -> Unit {
#| if self.retained_from < 0 || self.cursor < self.retained_from {
#| self.retained_from = self.cursor
#| }
#|}
#|#doc(hidden)
#|pub fn AsyncLexbuf::__get_stringview(
#| self : AsyncLexbuf,
#| start : Int,
#| end : Int,
#|) -> StringView {
#| guard self.retained_from >= 0 &&
#| self.retained_from <= start &&
#| start <= end &&
#| start >= self.storage.buffer_start &&
#| end <= self.__buffer_end() else {
#| abort("AsyncLexbuf::__get_stringview: range was not retained")
#| }
#| self.storage.get_stringview(start, end)
#|}
#|#doc(hidden)
#|pub fn AsyncLexbuf::__commit_to(self : AsyncLexbuf, position : Int) -> Unit {
#| guard self.retained_from >= 0 &&
#| self.storage.buffer_start <= position &&
#| position <= self.cursor else {
#| abort("AsyncLexbuf::__commit_to: position is not retained")
#| }
#| self.cursor = position
#| self.retained_from = -1
#|}
#|#doc(hidden)
#|pub async fn AsyncLexbuf::__refill(self : AsyncLexbuf) -> Unit {
#| guard self.cursor == self.__buffer_end() else {
#| abort("AsyncLexbuf::__refill: unread buffered input remains")
#| }
#| self.compact_buffer()
#| while !self.eof {
#| match (self.source)() {
#| None => {
#| self.eof = true
#| return
#| }
#| Some(chunk) =>
#| if !chunk.is_empty() {
#| self.storage.append(chunk)
#| return
#| }
#| }
#| }
#|}
#|fn AsyncLexbuf::compact_buffer(self : AsyncLexbuf) -> Unit {
#| let keep_from = if self.retained_from >= 0 {
#| self.retained_from
#| } else {
#| self.cursor
#| }
#| self.storage.discard_before(keep_from)
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `StringScanner` instead")
#|pub fn Lexbuf::from_string(content : String) -> Lexbuf {
#| {
#| source: () => None,
#| storage: LexbufStorage::from_string(content),
#| cursor: 0,
#| retained_from: -1,
#| eof: true,
#| }
#|}
),
"lexbuf.mbt": (
#|pub struct Lexbuf {
#| priv source : () -> String?
#| priv storage : LexbufStorage
#| priv mut cursor : Int
#| priv mut retained_from : Int
#| priv mut eof : Bool
#|}
#|pub fn Lexbuf::from_fn(source : () -> String?) -> Lexbuf {
#| {
#| source,
#| storage: LexbufStorage(),
#| cursor: 0,
#| retained_from: -1,
#| eof: false,
#| }
#|}
#|#doc(hidden)
#|pub fn Lexbuf::__get_cursor(self : Lexbuf) -> Int {
#| self.cursor
#|}
#|#doc(hidden)
#|pub fn Lexbuf::__buffer_end(self : Lexbuf) -> Int {
#| self.storage.buffer_end
#|}
#|#doc(hidden)
#|pub fn Lexbuf::__eof_reached(self : Lexbuf) -> Bool {
#| self.eof
#|}
#|#doc(hidden)
#|pub fn Lexbuf::__unsafe_code_unit_at(self : Lexbuf, position : Int) -> Int {
#| debug_assert(() => {
#| position >= self.storage.buffer_start && position < self.__buffer_end()
#| })
#| self.storage.unsafe_code_unit_at(position)
#|}
#|#doc(hidden)
#|pub fn Lexbuf::__advance(self : Lexbuf, count : Int) -> Unit {
#| debug_assert(() => count >= 0 && self.cursor + count <= self.__buffer_end())
#| self.cursor += count
#|}
#|#doc(hidden)
#|pub fn Lexbuf::__retain_from_cursor(self : Lexbuf) -> Unit {
#| if self.retained_from < 0 || self.cursor < self.retained_from {
#| self.retained_from = self.cursor
#| }
#|}
#|#doc(hidden)
#|pub fn Lexbuf::__get_stringview(
#| self : Lexbuf,
#| start : Int,
#| end : Int,
#|) -> StringView {
#| guard self.retained_from >= 0 &&
#| self.retained_from <= start &&
#| start <= end &&
#| start >= self.storage.buffer_start &&
#| end <= self.__buffer_end() else {
#| abort("Lexbuf::__get_stringview: range was not retained")
#| }
#| self.storage.get_stringview(start, end)
#|}
#|#doc(hidden)
#|pub fn Lexbuf::__commit_to(self : Lexbuf, position : Int) -> Unit {
#| guard self.retained_from >= 0 &&
#| self.storage.buffer_start <= position &&
#| position <= self.cursor else {
#| abort("Lexbuf::__commit_to: position is not retained")
#| }
#| self.cursor = position
#| self.retained_from = -1
#|}
#|#doc(hidden)
#|pub fn Lexbuf::__refill(self : Lexbuf) -> Unit {
#| guard self.cursor == self.__buffer_end() else {
#| abort("Lexbuf::__refill: unread buffered input remains")
#| }
#| self.compact_buffer()
#| while !self.eof {
#| match (self.source)() {
#| None => {
#| self.eof = true
#| break
#| }
#| Some(chunk) =>
#| if !chunk.is_empty() {
#| self.storage.append(chunk)
#| break
#| }
#| }
#| }
#|}
#|fn Lexbuf::compact_buffer(self : Lexbuf) -> Unit {
#| let keep_from = if self.retained_from >= 0 {
#| self.retained_from
#| } else {
#| self.cursor
#| }
#| self.storage.discard_before(keep_from)
#|}
),
"storage.mbt": (
#|priv struct LexbufStorage {
#| mut chunks : Array[String]
#| mut chunk_starts : Array[Int]
#| mut lookup_chunk : Int
#| mut buffer_start : Int
#| mut buffer_end : Int
#|}
#|const LEXBUF_MERGED_CHUNK_LIMIT : Int = 64
#|fn LexbufStorage::LexbufStorage() -> LexbufStorage {
#| {
#| chunks: [],
#| chunk_starts: [],
#| lookup_chunk: 0,
#| buffer_start: 0,
#| buffer_end: 0,
#| }
#|}
#|fn LexbufStorage::from_string(content : String) -> LexbufStorage {
#| let storage = LexbufStorage()
#| if !content.is_empty() {
#| storage.append(content)
#| }
#| storage
#|}
#|fn LexbufStorage::append(self : LexbufStorage, chunk : String) -> Unit {
#| guard !chunk.is_empty() else { abort("LexbufStorage: empty chunk") }
#| if self.chunks is [.., last] &&
#| last.length() + chunk.length() <= LEXBUF_MERGED_CHUNK_LIMIT {
#| self.chunks[self.chunks.length() - 1] = last + chunk
#| self.buffer_end += chunk.length()
#| return
#| }
#| self.chunk_starts.push(self.buffer_end)
#| self.chunks.push(chunk)
#| self.buffer_end += chunk.length()
#|}
#|fn LexbufStorage::chunk_contains(
#| self : LexbufStorage,
#| index : Int,
#| position : Int,
#|) -> Bool {
#| if index < 0 || index >= self.chunks.length() {
#| return false
#| }
#| let start = self.chunk_starts.unsafe_get(index)
#| start <= position && position < start + self.chunks.unsafe_get(index).length()
#|}
#|fn LexbufStorage::find_chunk(self : LexbufStorage, position : Int) -> Int {
#| let cached = self.lookup_chunk
#| if self.chunk_contains(cached, position) {
#| return cached
#| }
#| if self.chunk_contains(cached + 1, position) {
#| self.lookup_chunk = cached + 1
#| return cached + 1
#| }
#| if self.chunk_contains(cached - 1, position) {
#| self.lookup_chunk = cached - 1
#| return cached - 1
#| }
#| let low = for low = 0, high = self.chunks.length(); low < high; {
#| let middle = low + (high - low) / 2
#| if self.chunk_starts.unsafe_get(middle) <= position {
#| continue middle + 1, high
#| } else {
#| continue low, middle
#| }
#| } nobreak {
#| low
#| }
#| let index = low - 1
#| guard self.chunk_contains(index, position) else {
#| abort("LexbufStorage: position is not buffered")
#| }
#| self.lookup_chunk = index
#| index
#|}
#|fn LexbufStorage::unsafe_code_unit_at(
#| self : LexbufStorage,
#| position : Int,
#|) -> Int {
#| let index = self.find_chunk(position)
#| let chunk = self.chunks.unsafe_get(index)
#| chunk.unsafe_get(position - self.chunk_starts.unsafe_get(index)).to_int()
#|}
#|fn LexbufStorage::get_stringview(
#| self : LexbufStorage,
#| start : Int,
#| end : Int,
#|) -> StringView {
#| if start == end {
#| return ""
#| }
#| let first = self.find_chunk(start)
#| let first_chunk = self.chunks.unsafe_get(first)
#| let first_start = self.chunk_starts.unsafe_get(first)
#| let first_end = first_start + first_chunk.length()
#| if end <= first_end {
#| return first_chunk.view(
#| start_offset=start - first_start,
#| end_offset=end - first_start,
#| )
#| }
#| let builder = StringBuilder(size_hint=(end - start) * 2)
#| builder.write_view(first_chunk.view(start_offset=start - first_start))
#| for index in (first + 1).. Unit {
#| guard self.buffer_start <= position && position <= self.buffer_end else {
#| abort("LexbufStorage: invalid retention state")
#| }
#| let length = self.chunks.length()
#| let first = for index in 0.. position {
#| break index
#| }
#| } nobreak {
#| length
#| }
#| self.buffer_start = position
#| if first == length {
#| self.chunks.clear()
#| self.chunk_starts.clear()
#| } else if first > 0 {
#| let chunks : Array[String] = []
#| let chunk_starts : Array[Int] = []
#| for index in first.. Repr(x))),
#| )
#|}
#|test "Debug for List" {
#| let xs : List[Int] = List([1, 2, 3])
#| @debug.debug_inspect(xs, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("use `_.to_array().rev_fold(...)` instead")
#|pub fn[A, B] List::rev_fold(self : List[A], init~ : B, f : (B, A) -> B) -> B {
#| let xs = self.to_array()
#| for x in xs.rev_iter(); acc = (init : B) {
#| continue f(acc, x)
#| } nobreak {
#| acc
#| }
#|}
#|#deprecated("use `_.rev().foldi(...)` instead")
#|pub fn[A, B] List::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] List::tail(self : List[A]) -> List[A] {
#| match self {
#| Empty => Empty
#| More(_, tail~) => tail
#| }
#|}
),
"extends.mbt": (
#|pub extend List with Compare::{compare}
#|pub extend List with Eq::{equal}
#|pub extend List with Hash::{hash}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend List with @debug.Debug::{to_repr}
#|#deprecated("Use the comparison operators (`<`, `<=`, `>=`, `>`) instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend List with Compare::{op_ge, op_gt, op_le, op_lt}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend List with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend List with Eq::{not_equal}
#|#deprecated("Use `Hash::hash_combine` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend List with Hash::{hash_combine}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend List with Show::{output, to_string}
),
"list.mbt": (
#|#alias(empty)
#|#as_free_fn
#|#as_free_fn(empty)
#|#inline
#|pub fn[A] List::new() -> List[A] {
#| Empty
#|}
#|#as_free_fn
#|#as_free_fn(construct, deprecated="Use cons instead")
#|#owned(head, tail)
#|pub fn[A] List::cons(head : A, tail : List[A]) -> List[A] {
#| More(head, tail~)
#|}
#|#alias(add)
#|#owned(head)
#|pub fn[A] List::prepend(self : List[A], head : A) -> List[A] {
#| More(head, tail=self)
#|}
#|pub impl[A : Eq] Eq for List[A] with fn equal(self, other) -> Bool {
#| if physical_equal(self, other) {
#| return true
#| }
#| match (self, other) {
#| (Empty, Empty) => true
#| (More(x, tail=xs), More(y, tail=ys)) => x == y && xs == ys
#| _ => false
#| }
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for List[A]
#|pub impl[A : Show] Show for List[A] with fn output(xs, logger) {
#| logger.write_iter(xs.iter(), prefix="@list.from_array([", suffix="])")
#|}
#|pub impl[A : ToJson] ToJson for List[A] with fn to_json(self) {
#| let capacity = self.length()
#| guard capacity != 0 else { return [] }
#| let jsons = Array(capacity~)
#| for a in self {
#| jsons.push(a.to_json())
#| }
#| Json::array(jsons)
#|}
#|pub fn[A : ToJson] List::to_json(self : List[A]) -> Json {
#| ToJson::to_json(self)
#|}
#|pub impl[A : @json.FromJson] @json.FromJson for List[A] with fn from_json(
#| json,
#| path,
#|) {
#| guard json is Array(arr) else {
#| raise 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)))
#| } nobreak {
#| list
#| }
#|}
#|#as_free_fn
#|pub fn[A : @json.FromJson] List::from_json(
#| json : Json,
#|) -> List[A] raise @json.JsonDecodeError {
#| @json.from_json(json)
#|}
#|#as_free_fn(deprecated="Use @list.List([...]) instead")
#|#alias(of, deprecated="Use @list.List([...]) instead")
#|#as_free_fn(of, deprecated="Use @list.List([...]) instead")
#|#deprecated("Use @list.List([...]) instead")
#|pub fn[A] List::from_array(arr : ArrayView[A]) -> List[A] {
#| List(arr)
#|}
#|pub fn[A] List::List(arr : ArrayView[A]) -> List[A] {
#| for i in arr.length()>..0; list = Empty {
#| continue More(arr[i], tail=list)
#| } nobreak {
#| list
#| }
#|}
#|pub fn[A] List::length(self : List[A]) -> Int {
#| for x = self, acc = 0 {
#| match (x, acc) {
#| (Empty, len) => break len
#| (More(_, tail=rest), acc) => continue rest, acc + 1
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::each(self : List[A], f : (A) -> Unit raise?) -> Unit raise? {
#| for x = self {
#| match x {
#| Empty => break
#| More(head, tail~) => {
#| f(head)
#| continue tail
#| }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::eachi(
#| self : List[A],
#| f : (Int, A) -> Unit raise?,
#|) -> Unit raise? {
#| for x = self, i = 0 {
#| match (x, i) {
#| (Empty, _) => break
#| (More(x, tail=xs), i) => {
#| f(i, x)
#| continue xs, i + 1
#| }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A, B] List::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)
#| for d = dest, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (More(_) as dest, More(hd, tail~)) => {
#| dest.tail = More(f(hd), tail=Empty)
#| continue dest.tail, tail
#| }
#| (Empty, _) => panic()
#| }
#| }
#| dest
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A, B] List::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)
#| for i = 1, d = dest, t = tail {
#| match (i, d, t) {
#| (_, _, Empty) => break
#| (i, More(_) as dest, More(hd, tail~)) => {
#| dest.tail = More(f(i, hd), tail=Empty)
#| continue i + 1, dest.tail, tail
#| }
#| (_, Empty, _) => panic()
#| }
#| }
#| dest
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A, B] List::rev_map(
#| self : List[A],
#| f : (A) -> B raise?,
#|) -> List[B] raise? {
#| for a = Empty, b = self {
#| match (a, b) {
#| (acc, Empty) => break acc
#| (acc, More(x, tail=xs)) => continue More(f(x), tail=acc), xs
#| }
#| }
#|}
#|pub fn[A] List::to_array(self : List[A]) -> Array[A] {
#| [
#| for x in self => x
#| ]
#|}
#|#locals(f)
#|pub fn[A] List::filter(
#| self : List[A],
#| f : (A) -> Bool raise?,
#|) -> List[A] raise? {
#| for x = self {
#| match x {
#| Empty => break Empty
#| More(head, tail~) =>
#| if !f(head) {
#| continue tail
#| } else {
#| let dest = More(head, tail=Empty)
#| for d = dest, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (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()
#| }
#| }
#| break dest
#| }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::all(self : List[A], f : (A) -> Bool raise?) -> Bool raise? {
#| for x = self {
#| match x {
#| Empty => break true
#| More(head, tail~) => if f(head) { continue tail } else { break false }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::any(self : List[A], f : (A) -> Bool raise?) -> Bool raise? {
#| for x = self {
#| match x {
#| Empty => break false
#| More(head, tail~) => if f(head) { break true } else { continue tail }
#| }
#| }
#|}
#|#internal(unsafe, "Panic if the list is empty")
#|#doc(hidden)
#|pub fn[A] List::unsafe_head(self : List[A]) -> A {
#| match self {
#| Empty => abort("head of empty list")
#| More(head, tail=_) => head
#| }
#|}
#|pub fn[A] List::unsafe_tail(self : List[A]) -> List[A] {
#| match self {
#| Empty => abort("tail of empty list")
#| More(_, tail~) => tail
#| }
#|}
#|pub fn[A] List::head(self : List[A]) -> A? {
#| match self {
#| Empty => None
#| More(head, tail=_) => Some(head)
#| }
#|}
#|#internal(unsafe, "Panic if the list is empty")
#|#doc(hidden)
#|pub fn[A] List::unsafe_last(self : List[A]) -> A {
#| for x = self {
#| match x {
#| Empty => break abort("last of empty list")
#| More(head, tail=Empty) => break head
#| More(_, tail~) => continue tail
#| }
#| }
#|}
#|pub fn[A] List::last(self : List[A]) -> A? {
#| for x = self {
#| match x {
#| Empty => break None
#| More(head, tail=Empty) => break Some(head)
#| More(_, tail~) => continue tail
#| }
#| }
#|}
#|#owned(other)
#|pub fn[A] List::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)
#| for d = dest, t = tail {
#| match (d, t) {
#| (More(_) as dest, Empty) => {
#| dest.tail = other
#| break
#| }
#| (More(_) as dest, More(head, tail~)) => {
#| dest.tail = More(head, tail=Empty)
#| continue dest.tail, tail
#| }
#| (Empty, _) => panic()
#| }
#| }
#| dest
#| }
#| }
#|}
#|#owned(other)
#|pub fn[A] List::rev_concat(self : List[A], other : List[A]) -> List[A] {
#| for a = self, b = other {
#| match (a, b) {
#| (Empty, other) => break other
#| (More(head, tail~), other) => continue tail, More(head, tail=other)
#| }
#| }
#|}
#|pub fn[A] List::rev(self : List[A]) -> List[A] {
#| self.rev_concat(Empty)
#|}
#|#locals(f)
#|pub fn[A, B] List::fold(
#| self : List[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| for x = self, acc = init {
#| match (x, acc) {
#| (Empty, acc) => break acc
#| (More(head, tail~), acc) => continue tail, f(acc, head)
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A, B] List::foldi(
#| self : List[A],
#| init~ : B,
#| f : (Int, B, A) -> B raise?,
#|) -> B raise? {
#| for xs = self, i = 0, acc = init {
#| match xs {
#| Empty => break acc
#| More(x, tail=rest) => continue rest, i + 1, f(i, acc, x)
#| }
#| }
#|}
#|#as_free_fn
#|pub fn[A, B] List::zip(self : List[A], other : List[B]) -> List[(A, B)] {
#| let res = for a = self, b = other, acc = Empty {
#| match (a, b, acc) {
#| (Empty, _, acc) | (_, Empty, acc) => break acc
#| (More(x, tail=xs), More(y, tail=ys), acc) =>
#| continue xs, ys, More((x, y), tail=acc)
#| }
#| }
#| res.reverse_in_place()
#|}
#|#locals(f)
#|pub fn[A, B] List::flat_map(
#| self : List[A],
#| f : (A) -> List[B] raise?,
#|) -> List[B] raise? {
#| for x = self {
#| match x {
#| Empty => break Empty
#| More(head, tail~) =>
#| match f(head) {
#| Empty => continue tail
#| More(hd, tail=tl) => {
#| let dest = More(hd, tail=Empty)
#| let dest1 = for d = dest, t = tl {
#| match (d, t) {
#| (dest, Empty) => break dest
#| (More(_) as dest, More(hd, tail~)) => {
#| dest.tail = More(hd, tail=Empty)
#| continue dest.tail, tail
#| }
#| (Empty, _) => panic()
#| }
#| }
#| loop_over_tail~: for d = dest1, t = tail {
#| match (d, t) {
#| (_, Empty) => break loop_over_tail~
#| (More(_) as dest, More(t_hd, tail=Empty)) => {
#| dest.tail = f(t_hd)
#| break loop_over_tail~
#| }
#| (dest, More(t_hd, tail=t_tl)) =>
#| for d2 = dest, t2 = f(t_hd) {
#| match (d2, t2) {
#| (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()
#| }
#| }
#| }
#| }
#| break dest
#| }
#| }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A, B] List::filter_map(
#| self : List[A],
#| f : (A) -> B? raise?,
#|) -> List[B] raise? {
#| for x = self {
#| match x {
#| Empty => break Empty
#| More(hd, tail~) =>
#| match f(hd) {
#| None => continue tail
#| Some(head) => {
#| let dest = More(head, tail=Empty)
#| for d = dest, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (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()
#| }
#| }
#| break dest
#| }
#| }
#| }
#| }
#|}
#|#internal(unsafe, "Panic if the index is out of bounds")
#|#doc(hidden)
#|pub fn[A] List::unsafe_nth(self : List[A], n : Int) -> A {
#| for x = self, i = n {
#| match (x, i) {
#| (Empty, _) => break abort("nth: index out of bounds")
#| (More(head, tail=_), 0) => break head
#| (More(_, tail~), n) => continue tail, n - 1
#| }
#| }
#|}
#|pub fn[A] List::nth(self : List[A], n : Int) -> A? {
#| for x = self, i = n {
#| match (x, i) {
#| (Empty, _) => break None
#| (More(head, tail=_), 0) => break Some(head)
#| (More(_, tail~), n) => continue tail, n - 1
#| }
#| }
#|}
#|#as_free_fn
#|pub fn[A] List::repeat(n : Int, x : A) -> List[A] {
#| if n < 0 {
#| abort("negative repeat count")
#| }
#| for acc = Empty, i = n {
#| match (acc, i) {
#| (acc, n) =>
#| if n <= 0 {
#| break acc
#| } else {
#| continue More(x, tail=acc), n - 1
#| }
#| }
#| }
#|}
#|pub fn[A] List::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)
#| for d = dest, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (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] List::is_empty(self : List[A]) -> Bool {
#| self is Empty
#|}
#|pub fn[A, B] List::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)
#| for a = tail, b = xs, c = ys {
#| match (a, b, c) {
#| (Empty, _, _) => break
#| (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
#| }
#| (_, _, _) => break abort("unreachable")
#| }
#| }
#| (xs, ys)
#| }
#| }
#|}
#|pub fn[A] List::flatten(self : List[List[A]]) -> List[A] {
#| for x = self {
#| match x {
#| Empty => break Empty
#| More(head, tail~) =>
#| match head {
#| Empty => continue tail
#| More(hd, tail=tl) => {
#| let dest = More(hd, tail=Empty)
#| let dest1 = for d = dest, t = tl {
#| match (d, t) {
#| (dest, Empty) => break dest
#| (More(_) as dest, More(hd, tail~)) => {
#| dest.tail = More(hd, tail=Empty)
#| continue dest.tail, tail
#| }
#| (Empty, _) => panic()
#| }
#| }
#| loop_over_tail~: for d = dest1, t = tail {
#| match (d, t) {
#| (_, Empty) => break loop_over_tail~
#| (More(_) as dest, More(t_hd, tail=Empty)) => {
#| dest.tail = t_hd
#| break loop_over_tail~
#| }
#| (dest, More(t_hd, tail=t_tl)) =>
#| for d2 = dest, t2 = t_hd {
#| match (d2, t2) {
#| (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()
#| }
#| }
#| }
#| }
#| break dest
#| }
#| }
#| }
#| }
#|}
#|#internal(unsafe, "Panic if the list is empty")
#|#doc(hidden)
#|pub fn[A : Compare] List::unsafe_maximum(self : List[A]) -> A {
#| guard self.maximum() is Some(max) else { abort("maximum: empty list") }
#| max
#|}
#|pub fn[A : Compare] List::maximum(self : List[A]) -> A? {
#| guard self is More(head, tail~) else { return None }
#| for rest = tail, curr_max = head {
#| match rest {
#| Empty => break Some(curr_max)
#| More(item, tail~) =>
#| continue tail, if item > curr_max { item } else { curr_max }
#| }
#| }
#|}
#|#internal(unsafe, "Panic if the list is empty")
#|#doc(hidden)
#|pub fn[A : Compare] List::unsafe_minimum(self : List[A]) -> A {
#| guard self.minimum() is Some(min) else { abort("minimum: empty list") }
#| min
#|}
#|pub fn[A : Compare] List::minimum(self : List[A]) -> A? {
#| guard self is More(head, tail~) else { return None }
#| for rest = tail, curr_min = head {
#| match rest {
#| Empty => break Some(curr_min)
#| More(item, tail~) =>
#| continue tail, if item < curr_min { item } else { curr_min }
#| }
#| }
#|}
#|pub fn[A : Compare] List::sort(self : List[A]) -> List[A] {
#| let arr = self.to_array()
#| arr.sort()
#| List(arr)
#|}
#|pub impl[A] Add for List[A] with fn add(self, other) {
#| self.concat(other)
#|}
#|pub fn[A : Eq] List::contains(self : List[A], value : A) -> Bool {
#| for cur = self {
#| match cur {
#| Empty => break false
#| More(x, tail=xs) => if x == value { break true } else { continue xs }
#| }
#| }
#|}
#|#as_free_fn
#|#locals(f)
#|pub fn[A, S] List::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)
#| for d = dest, t = f(new_state) {
#| match (d, t) {
#| (_, None) => break
#| (More(_) as dest, Some((element, new_state))) => {
#| dest.tail = More(element, tail=Empty)
#| continue dest.tail, f(new_state)
#| }
#| (Empty, _) => panic()
#| }
#| }
#| dest
#| }
#| }
#|}
#|#as_free_fn
#|#locals(f)
#|pub fn[A, S] List::rev_unfold(
#| f : (S) -> (A, S)? raise?,
#| init~ : S,
#|) -> List[A] raise? {
#| for a = f(init), b = Empty {
#| match (a, b) {
#| (None, acc) => break acc
#| (Some((x, s)), acc) => continue f(s), More(x, tail=acc)
#| }
#| }
#|}
#|pub fn[A] List::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)
#| for d = dest, t = tail, i = n - 1 {
#| match (d, t, i) {
#| (_, Empty, _) | (_, _, 0) => break
#| (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] List::drop(self : List[A], n : Int) -> List[A] {
#| if n <= 0 {
#| self
#| } else {
#| for a = n, b = self {
#| match (a, b) {
#| (1, More(_, tail=xs)) | ((_, Empty) with xs = Empty) => break xs
#| (n, More(_, tail=xs)) => continue n - 1, xs
#| }
#| }
#| }
#|}
#|#locals(p)
#|pub fn[A] List::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)
#| for d = dest, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (More(_) as dest, More(x, tail=xs)) if p(x) => {
#| dest.tail = More(x, tail=Empty)
#| continue dest.tail, xs
#| }
#| (More(_), _) => break
#| (Empty, _) => panic()
#| }
#| }
#| dest
#| } else {
#| Empty
#| }
#| }
#|}
#|#locals(p)
#|pub fn[A] List::drop_while(
#| self : List[A],
#| p : (A) -> Bool raise?,
#|) -> List[A] raise? {
#| for cur = self {
#| match cur {
#| Empty => break Empty
#| More(x, tail=xs) =>
#| if p(x) {
#| continue xs
#| } else {
#| break More(x, tail=xs)
#| }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A, E] List::scan_left(
#| self : List[A],
#| f : (E, A) -> E raise?,
#| init~ : E,
#|) -> List[E] raise? {
#| let dest = More(init, tail=Empty)
#| for d = dest, s = self, a = init {
#| match (d, s, a) {
#| (_, Empty, _) => break
#| (Empty, _, _) => panic()
#| (More(_) as dest, More(x, tail=xs), acc) => {
#| let next = f(acc, x)
#| dest.tail = More(next, tail=Empty)
#| continue dest.tail, xs, next
#| }
#| }
#| }
#| dest
#|}
#|pub fn[A, B] List::scan_right(
#| self : List[A],
#| f : (B, A) -> B raise?,
#| init~ : B,
#|) -> List[B] raise? {
#| self.rev().scan_left(f, init~).reverse_in_place()
#|}
#|pub fn[A : Eq, B] List::lookup(self : List[(A, B)], v : A) -> B? {
#| for cur = self {
#| match cur {
#| Empty => break None
#| More((x, y), tail=xs) => if x == v { break Some(y) } else { continue xs }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::find(self : List[A], f : (A) -> Bool raise?) -> A? raise? {
#| for cur = self {
#| match cur {
#| Empty => break None
#| More(element, tail=list) =>
#| if f(element) {
#| break Some(element)
#| } else {
#| continue list
#| }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::find_index(
#| self : Self[A],
#| f : (A) -> Bool raise?,
#|) -> Int? raise? {
#| for cur = self, idx = 0 {
#| match (cur, idx) {
#| (Empty, _) => break None
#| (More(element, tail=list), idx) =>
#| if f(element) {
#| break Some(idx)
#| } else {
#| continue list, idx + 1
#| }
#| }
#| }
#|}
#|#locals(f)
#|pub fn[A] List::findi(self : List[A], f : (A, Int) -> Bool raise?) -> A? raise? {
#| for list = self, index = 0 {
#| match list {
#| Empty => break None
#| More(element, tail=list) =>
#| if f(element, index) {
#| break Some(element)
#| } else {
#| continue list, index + 1
#| }
#| }
#| }
#|}
#|pub fn[A] List::remove_at(self : List[A], index : Int) -> List[A] {
#| match (index, self) {
#| (0, More(_, tail~))
#| | ((_, Empty) with tail = Empty)
#| | ((_..<0, _) with tail = self) => tail
#| (n, More(head, tail~)) => {
#| let dest = More(head, tail=Empty)
#| for d = dest, t = tail, i = n - 1 {
#| match (d, t, i) {
#| (_, Empty, _) => break
#| (More(_) as dest, More(_, tail~), 0) => {
#| dest.tail = tail
#| break
#| }
#| (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] List::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~)
#| for d = dest, t = tail {
#| match (d, t) {
#| (_, Empty) => break
#| (More(_) as dest, More(x, tail=xs)) =>
#| if x == elem {
#| dest.tail = xs
#| break
#| } else {
#| dest.tail = More(x, tail=Empty)
#| continue dest.tail, xs
#| }
#| (Empty, _) => panic()
#| }
#| }
#| dest
#| }
#| }
#|}
#|#alias(is_prefix, deprecated)
#|pub fn[A : Eq] List::has_prefix(self : List[A], prefix : List[A]) -> Bool {
#| for a = self, b = prefix {
#| match (a, b) {
#| (_, Empty) => break true
#| (Empty, More(_)) => break false
#| (More(h1, tail=t1), More(h2, tail=t2)) =>
#| if h1 == h2 {
#| continue t1, t2
#| } else {
#| break false
#| }
#| }
#| }
#|}
#|#alias(is_suffix, deprecated)
#|pub fn[A : Eq] List::has_suffix(self : List[A], suffix : List[A]) -> Bool {
#| guard suffix is More(_) else { return true }
#| for lead = self, probe = suffix {
#| match (lead, probe) {
#| (_, Empty) =>
#| break for lag = self, ahead = lead {
#| match (lag, ahead) {
#| (_, Empty) => break lag.has_prefix(suffix)
#| (More(_, tail=lag_tail), More(_, tail=ahead_tail)) =>
#| continue lag_tail, ahead_tail
#| (Empty, More(_)) =>
#| break false
#| }
#| }
#| (Empty, More(_)) => break false
#| (More(_, tail=lead_tail), More(_, tail=probe_tail)) =>
#| continue lead_tail, probe_tail
#| }
#| }
#|}
#|pub fn[A] List::intercalate(self : List[List[A]], sep : List[A]) -> List[A] {
#| self.intersperse(sep).flatten()
#|}
#|pub impl[X] Default for List[X] with fn default() {
#| Empty
#|}
#|pub fn[X] default() -> List[X] {
#| Empty
#|}
#|#alias(iterator, deprecated)
#|pub fn[A] List::iter(self : List[A]) -> Iter[A] {
#| let mut next = self
#| Iter::new(fn() {
#| match next {
#| Empty => None
#| More(head, tail~) => {
#| next = tail
#| Some(head)
#| }
#| }
#| })
#|}
#|#alias(iterator2, deprecated)
#|pub fn[A] List::iter2(self : List[A]) -> Iter2[Int, A] {
#| let mut i = 0
#| let mut next = self
#| Iter2::new(fn() {
#| match next {
#| Empty => None
#| More(head, tail~) => {
#| let result = (i, head)
#| next = tail
#| i += 1
#| Some(result)
#| }
#| }
#| })
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[A] List::from_iter(iter : Iter[A]) -> List[A] {
#| let mut head = Empty
#| let mut tail = Empty
#| while iter.next() is Some(x) {
#| match tail {
#| Empty => {
#| tail = More(x, tail~)
#| head = tail
#| }
#| More(_) as prev_tail => {
#| tail = More(x, tail=Empty)
#| prev_tail.tail = tail
#| }
#| }
#| }
#| head
#|}
#|#as_free_fn
#|#alias(from_iterator_rev, deprecated)
#|#as_free_fn(from_iterator_rev, deprecated)
#|pub fn[A] List::from_iter_rev(iter : Iter[A]) -> List[A] {
#| iter.fold(init=Empty, (acc, e) => More(e, tail=acc))
#|}
#|#as_free_fn
#|#owned(x)
#|pub fn[A] List::singleton(x : A) -> List[A] {
#| More(x, tail=Empty)
#|}
#|pub impl[A : Hash] Hash for List[A] with fn hash_combine(self, hasher) {
#| for e in self {
#| hasher.combine(e)
#| }
#|}
#|fn[A] List::reverse_in_place(self : List[A]) -> List[A] {
#| match self {
#| Empty | More(_, tail=Empty) => self
#| More(head, tail~) =>
#| for a = More(head, tail=Empty), b = tail {
#| match (a, b) {
#| (result, Empty) => break result
#| (result, More(_, tail=xs) as new_result) => {
#| new_result.tail = result
#| continue new_result, xs
#| }
#| }
#| }
#| }
#|}
#|pub impl[A : Compare] Compare for List[A] with fn compare(self, other) {
#| for a = self, b = other {
#| match (a, b) {
#| (Empty, Empty) => break 0
#| (Empty, More(_, tail=_)) => break -1
#| (More(_, tail=_), Empty) => break 1
#| (More(x, tail=xs), More(y, tail=ys)) => {
#| let cmp = x.compare(y)
#| if cmp != 0 {
#| break cmp
#| } else {
#| continue xs, ys
#| }
#| }
#| }
#| }
#|}
),
"types.mbt": (
#|#unsafe_cycle_free
#|pub enum List[A] {
#| Empty
#| More(A, mut tail~ : List[A])
#|}
),
},
)
///|
let moonbitlang_core_math_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/math",
deps={},
files={
"algebraic.mbt": (
#|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 = Float::reinterpret_from_uint(ui).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)
#| Float::from_double(t)
#|}
#|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"
),
"deprecated.mbt": (
#|#deprecated("Use `PI` instead")
#|pub let pi = 0x3.243F6A8885A308CA8A54
#|#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
#| }
#|}
),
"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
#| Float::from_double(y)
#|}
#|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()
#| hi = x - Float::from_int(k) * float_ln2_hi // t*ln2_hi is exact here
#| lo = Float::from_int(k) * 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 = Float::reinterpret_from_int((0x7f + k) << 23) // 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 *= twopk
#| }
#| return y - 1.0
#| }
#| let uf = Float::reinterpret_from_int((0x7f - k) << 23) // 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"
),
"hyperbolic.mbt": (
#|fn k_expo2f(x : Float) -> Float {
#| let k = 235
#| let k_ln2 = Float::reinterpret_from_int(0x4322e3bc)
#| let scale = Float::reinterpret_from_int((0x7f + k / 2) << 23)
#| 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 = Float::reinterpret_from_uint(ix)
#| 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 = Float::reinterpret_from_uint(ix)
#| 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 = Float::reinterpret_from_uint(ix)
#| 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 = Float::reinterpret_from_uint(i)
#| 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 = Float::reinterpret_from_uint(u)
#| 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"
),
"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 = Float::reinterpret_from_uint(iz).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)
#| Float::from_double(y)
#|}
#|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 = Float::reinterpret_from_uint(ui)
#| c = if k >= 2 { one - (fui - x) } else { x - (fui - 1.0) }
#| c /= Float::reinterpret_from_uint(ui)
#| } else {
#| c = 0.0
#| }
#| iu = (iu & 0x007fffff) + 0x3f3504f3
#| ui = iu
#| f = Float::reinterpret_from_uint(ui) - 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 = Float::from_int(k)
#| 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"
),
"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.42860654e-06 // 0x35bfbe8c */
#| let ovt : Float = 4.2995665694e-08 // -(128-log2(ovfl+.5ulp)) */
#| 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 : ReadOnlyArray[Float] = [1.0, 1.5]
#| let dp_h : ReadOnlyArray[Float] = [0.0, 5.84960938e-01] // 0x3f15c000 */
#| let dp_l : ReadOnlyArray[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 < 0x3f7ffff6 {
#| 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 = Float::reinterpret_from_int(i_s & 0xfffff000)
#| 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 = Float::reinterpret_from_int(ix)
#| 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 = Float::reinterpret_from_int(i_s & 0xfffff000)
#| i_s = (((ix.reinterpret_as_uint() >> 1) & 0xfffff000) | 0x20000000).reinterpret_as_int()
#| t_h = Float::reinterpret_from_uint(
#| i_s.reinterpret_as_uint() + 0x00400000 + (k.reinterpret_as_uint() << 21),
#| )
#| 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 = Float::reinterpret_from_int(i_s & 0xfffff000)
#| 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 = Float::reinterpret_from_int(i_s & 0xfffff000)
#| 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 = Float::from_int(n)
#| t1 = z_h + z_l + dp_h[k] + t
#| i_s = t1.reinterpret_as_int()
#| t1 = Float::reinterpret_from_int(i_s & 0xfffff000)
#| t2 = z_l - (t1 - t - dp_h[k] - z_h)
#| }
#| i_s = y.reinterpret_as_int()
#| y1 = Float::reinterpret_from_int(i_s & 0xfffff000)
#| 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 = Float::reinterpret_from_int(n & (0x007fffff >> k).lnot())
#| 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 = Float::reinterpret_from_int(i_s & 0xffff8000)
#| 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 = Float::reinterpret_from_int(j)
#| }
#| sn * z
#|}
),
"pow_double_js.mbt": (
#|pub fn pow(base : Double, exponent : Double) -> Double {
#| if base == 1.0 {
#| return 1.0
#| }
#| if base == -1.0 &&
#| (exponent == @double.infinity || exponent == @double.neg_infinity) {
#| return 1.0
#| }
#| math_pow_js(base, exponent)
#|}
#|fn math_pow_js(base : Double, exponent : Double) -> Double = "Math" "pow"
),
"prime.mbt": (
#|const DEFAULT_PRIME_TEST_ITERS = 64
#|let small_primes : ReadOnlyArray[@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 _ 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 * Float::reinterpret_from_int(u)
#|}
#|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 * Float::reinterpret_from_int(0x3f22f983) +
#| Float::reinterpret_from_int(0x4b40_0000)
#| j = Float::from_int(j.reinterpret_as_int() - 0x4b40_0000)
#| r = x - j * Float::reinterpret_from_int(0x3fc90f80)
#| r -= j * Float::reinterpret_from_int(0x37354440)
#| r -= j * Float::reinterpret_from_int(0x2c34611a)
#| 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 : ReadOnlyArray[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 -= 0x4000_0000
#| 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 -= 1
#| }
#| phi = mulh(phi, 0xc90f_daa2)
#| if phi < 0x8000_0000 {
#| phi = phi << 1
#| 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 = Float::reinterpret_from_uint(r)
#| return (r, q)
#|}
#|fn sinf_poly(x : Float) -> Float {
#| let s = x * x
#| let mut r = Float::reinterpret_from_int(0x3640_5000)
#| r = r * s - Float::reinterpret_from_int(0x3950_3486)
#| r = r * s + Float::reinterpret_from_int(0x3c08_88c1)
#| r = r * s - Float::reinterpret_from_int(0x3e2a_aaab)
#| let t = x * s
#| r = r * t + x
#| r
#|}
#|fn cosf_poly(x : Float) -> Float {
#| let s = x * x
#| let mut r = Float::reinterpret_from_int(0x37cd_4000)
#| r = r * s - Float::reinterpret_from_int(0x3ab6_077d)
#| r = r * s + Float::reinterpret_from_int(0x3d2a_aaa8)
#| r = r * s - Float::reinterpret_from_int(0x3f00_0000)
#| r = r * s + Float::reinterpret_from_int(0x3f80_0000)
#| 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 : ReadOnlyArray[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)
#| Float::from_double(if odd { -1.0 / r } else { r })
#|}
#|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 Float::from_double(x.to_double() * pio2 + x1p120)
#| }
#| 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 = Float::from_double(pio2 - 2.0 * (s + s * r(z).to_double()))
#| 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 : ReadOnlyArray[Float] = [
#| 4.6364760399e-01, 7.8539812565e-01, 9.8279368877e-01, 1.5707962513e+00,
#| ]
#| let atanlo : ReadOnlyArray[Float] = [
#| 5.0121582440e-09, 3.7748947079e-08, 3.4473217170e-08, 7.5497894159e-08,
#| ]
#| let a_t : ReadOnlyArray[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 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.abs() / x.abs())
#| }
#| match m {
#| 0 => z
#| 1 => -z
#| 2 => pi - z
#| _ => z - 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"
),
},
)
///|
let moonbitlang_core_option_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/option",
deps={},
files={
"deprecated.mbt": (
#|#deprecated("Use `if condition { Some(value()) } else { None }` instead")
#|pub fn[T] when(condition : Bool, value : () -> T) -> T? {
#| if condition {
#| Some(value())
#| } else {
#| None
#| }
#|}
#|#deprecated("Use `if !condition { Some(value()) } else { None }` instead")
#|pub fn[T] unless(condition : Bool, value : () -> T) -> T? {
#| if !condition {
#| Some(value())
#| } else {
#| None
#| }
#|}
#|#deprecated("Use `None` instead")
#|pub fn[T] empty() -> T? {
#| None
#|}
#|#deprecated("Use `Some(value)` instead")
#|pub fn[T] some(value : T) -> T? {
#| Some(value)
#|}
),
"methods.mbt": "",
"option.mbt": "",
},
)
///|
let moonbitlang_core_prelude_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/prelude",
deps={},
files={
"prelude.mbt": (
#|pub using @buffer {type Buffer}
#|pub using @set {type Set}
#|pub using @bigint {type BigInt}
#|pub using @builtin {
#| abort,
#| assert_true,
#| assert_false,
#| compare,
#| debug_assert,
#| fail,
#| ignore,
#| hash,
#| inspect,
#| panic,
#| physical_equal,
#| println,
#| eprintln,
#| trait Eq,
#| trait Compare,
#| trait Hash,
#| trait Logger,
#| trait Show,
#| trait ToJson,
#| trait Default,
#| trait Add,
#| trait Sub,
#| trait Mul,
#| trait Div,
#| trait Mod,
#| trait Neg,
#| trait Shl,
#| trait Shr,
#| trait BitAnd,
#| trait BitOr,
#| trait BitXOr,
#| type ArgsLoc,
#| type Array,
#| type ArrayView,
#| type MutArrayView,
#| type UninitializedArray,
#| type Failure,
#| type Hasher,
#| type Iter,
#| type Iter2,
#| type Json,
#| type Map,
#| type InspectError,
#| type SnapshotError,
#| type SourceLoc,
#| type StringBuilder,
#|}
#|#deprecated("Use !expr instead")
#|#warnings("-deprecated")
#|pub using @builtin {not}
#|pub using @debug {debug, type Repr, trait Debug, debug_inspect, repr}
#|#deprecated("Use `Repr(x)` instead")
#|#warnings("-deprecated")
#|pub using @debug {to_repr}
#|#deprecated("for debugging only, not for production")
#|#warnings("-deprecated")
#|pub using @debug {dump}
#|pub using @string {type Regex}
#|#deprecated("use `value |> x => { ... ; x} instead")
#|pub fn[T] tap(value : T, f : (T) -> Unit raise) -> T raise {
#| f(value)
#| value
#|}
#|#deprecated("use `value |> (x) => {...}` operator instead")
#|pub fn[T, R] then(value : T, f : (T) -> R raise?) -> R raise? {
#| f(value)
#|}
#|pub let null : Json = @builtin.null
#|pub using @json {trait FromJson, json_inspect}
#|#deprecated("The name `Iterator` is deprecated, use `Iter` instead. Note that if you have defined `iterator()` method to support `for .. in` loop, you should also rename `iterator()` to `iter()`. See https://github.com/moonbitlang/core/pull/3127 for more details.")
#|pub type Iterator[X] = Iter[X]
#|#deprecated("The name `Iterator2` is deprecated, use `Iter2` instead. Note that if you have defined `iterator2()` method to support `for .. in` loop, you should also rename `iterator2()` to `iter2()`. See https://github.com/moonbitlang/core/pull/3127 for more details.")
#|pub type Iterator2[X, Y] = Iter2[X, Y]
#|pub using @ref {type Ref}
#|pub using @lazy {type Lazy}
#|pub using @test {assert_eq, assert_not_eq}
),
},
)
///|
let moonbitlang_core_priority_queue_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/priority_queue",
deps={},
files={
"debug.mbt": (
#|pub impl[A : @debug.Debug + Compare] @debug.Debug for PriorityQueue[A] with fn to_repr(
#| self,
#|) {
#| @debug.Repr::opaque_(
#| "PriorityQueue",
#| @debug.Repr::array([ for x in self => Repr(x) ]),
#| )
#|}
#|test "Debug for PriorityQueue" {
#| let pq : PriorityQueue[Int] = from_array([3, 1, 2])
#| @debug.debug_inspect(pq, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `PriorityQueue([])` instead")
#|#as_free_fn(deprecated="Use `PriorityQueue([])` instead")
#|pub fn[A] PriorityQueue::new() -> PriorityQueue[A] {
#| new_priority_queue()
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend PriorityQueue with @debug.Debug::{to_repr}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend PriorityQueue with Default::{default}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend PriorityQueue with Show::{output, to_string}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend PriorityQueue with ToJson::{to_json}
),
"priority_queue.mbt": (
#|fn[A] new_priority_queue() -> PriorityQueue[A] {
#| { len: 0, top: None, }
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[A : Compare] PriorityQueue::PriorityQueue(
#| arr : ArrayView[A],
#|) -> PriorityQueue[A] {
#| guard arr is [a0, ..] else { return new_priority_queue() }
#| let len = arr.length()
#| for i = 1, acc = { content: a0, sibling: None, child: None, } {
#| if i < len {
#| continue i + 1,
#| meld(acc, { content: arr[i], sibling: None, child: None, })
#| } else {
#| break { len, top: Some(acc), }
#| }
#| }
#|}
#|fn[A] copy_node(x : Node[A]?) -> Node[A]? {
#| match x {
#| None => None
#| Some(root) => {
#| let cloned_root : Node[A] = {
#| content: root.content,
#| sibling: None,
#| child: None,
#| }
#| let stack : Array[(Node[A], Node[A])] = [(root, cloned_root)]
#| while stack.pop() is Some((orig, clone)) {
#| if orig.child is Some(child) {
#| let cloned_child : Node[A] = {
#| content: child.content,
#| sibling: None,
#| child: None,
#| }
#| clone.child = Some(cloned_child)
#| stack.push((child, cloned_child))
#| }
#| if orig.sibling is Some(sib) {
#| let cloned_sib : Node[A] = {
#| content: sib.content,
#| sibling: None,
#| child: None,
#| }
#| clone.sibling = Some(cloned_sib)
#| stack.push((sib, cloned_sib))
#| }
#| }
#| Some(cloned_root)
#| }
#| }
#|}
#|#alias(clone, deprecated)
#|pub fn[A] PriorityQueue::copy(self : PriorityQueue[A]) -> PriorityQueue[A] {
#| { len: self.len, top: copy_node(self.top), }
#|}
#|pub fn[A : Compare] PriorityQueue::to_array(
#| self : PriorityQueue[A],
#|) -> Array[A] {
#| let arr = Array(capacity=self.len)
#| let stack : Array[Node[A]?] = [self.top]
#| while stack.pop() is Some(node) {
#| match node {
#| None => ()
#| Some({ content, sibling, child, }) => {
#| arr.push(content)
#| stack.push(sibling)
#| stack.push(child)
#| }
#| }
#| }
#| arr.sort()
#| arr.rev_in_place()
#| arr
#|}
#|#alias(iterator, deprecated)
#|pub fn[A : Compare] PriorityQueue::iter(self : PriorityQueue[A]) -> Iter[A] {
#| self.to_array().iter()
#|}
#|pub impl[A : ToJson + Compare] ToJson for PriorityQueue[A] with fn to_json(self) {
#| [
#| for x in self => x
#| ]
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[K : Compare] PriorityQueue::from_iter(
#| iter : Iter[K],
#|) -> PriorityQueue[K] {
#| let s = new_priority_queue()
#| while iter.next() is Some(e) {
#| s.push(e)
#| }
#| s
#|}
#|#owned(x, y)
#|fn[A : Compare] meld(x : Node[A], y : Node[A]) -> Node[A] {
#| if x.content > y.content {
#| y.sibling = x.child
#| x.child = Some(y)
#| x
#| } else {
#| x.sibling = y.child
#| y.child = Some(x)
#| y
#| }
#|}
#|#owned(x)
#|fn[A : Compare] merges(x : Node[A]?) -> Node[A]? {
#| let (x, acc) = match x {
#| None => return None
#| Some({ sibling: None, .. }) as x => return x
#| Some({ sibling: Some({ sibling: s2, .. } as s1), .. } as x) => {
#| x.sibling = None
#| s1.sibling = None
#| (s2, meld(x, s1))
#| }
#| }
#| for siblings = x, merged = acc {
#| match (siblings, merged) {
#| (None, acc) => break Some(acc)
#| (Some({ sibling: None, .. } as x), acc) => break Some(meld(acc, x))
#| (Some({ sibling: Some({ sibling: s2, .. } as s1), .. } as x), acc) => {
#| x.sibling = None
#| s1.sibling = None
#| continue s2, meld(acc, meld(x, s1))
#| }
#| }
#| }
#|}
#|pub fn[A] PriorityQueue::length(self : PriorityQueue[A]) -> Int {
#| self.len
#|}
#|#internal(unsafe, "Panic if the queue is empty.")
#|#doc(hidden)
#|pub fn[A : Compare] PriorityQueue::unsafe_pop(self : PriorityQueue[A]) -> Unit {
#| self.top = match self.top {
#| None => abort("The PriorityQueue is empty!")
#| Some({ child, .. }) => merges(child)
#| }
#| self.len -= 1
#|}
#|pub fn[A : Compare] PriorityQueue::pop(self : PriorityQueue[A]) -> A? {
#| match self.top {
#| None => None
#| Some({ content, child, .. }) => {
#| self.len -= 1
#| self.top = merges(child)
#| Some(content)
#| }
#| }
#|}
#|#owned(value)
#|pub fn[A : Compare] PriorityQueue::push(
#| self : PriorityQueue[A],
#| value : A,
#|) -> Unit {
#| let x = { content: value, sibling: None, child: None, }
#| self.top = match self.top {
#| None => Some(x)
#| Some(top) => Some(meld(top, x))
#| }
#| self.len += 1
#|}
#|pub fn[A] PriorityQueue::peek(self : PriorityQueue[A]) -> A? {
#| match self.top {
#| None => None
#| Some({ content, .. }) => Some(content)
#| }
#|}
#|pub fn[A] PriorityQueue::clear(self : PriorityQueue[A]) -> Unit {
#| self.top = None
#| self.len = 0
#|}
#|pub fn[A] PriorityQueue::is_empty(self : PriorityQueue[A]) -> Bool {
#| self.len == 0
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show + Compare] Show for PriorityQueue[A]
#|pub impl[A : Show + Compare] Show for PriorityQueue[A] with fn output(
#| self,
#| logger,
#|) {
#| logger.write_iter(
#| self.iter(),
#| prefix="@priority_queue.from_array([",
#| suffix="])",
#| )
#|}
#|pub impl[K] Default for PriorityQueue[K] with fn default() {
#| new_priority_queue()
#|}
),
"types.mbt": (
#|priv struct Node[A] {
#| content : A
#| mut sibling : Node[A]?
#| mut child : Node[A]?
#|}
#|struct PriorityQueue[A] {
#| mut len : Int
#| mut top : Node[A]?
#|}
),
},
)
///|
let moonbitlang_core_queue_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/queue",
deps={},
files={
"debug.mbt": (
#|pub impl[A : @debug.Debug] @debug.Debug for Queue[A] with fn to_repr(self) {
#| @debug.Repr::opaque_(
#| "Queue",
#| @debug.Repr::array([ for x in self => Repr(x) ]),
#| )
#|}
#|test "Debug for Queue" {
#| let q : Queue[Int] = from_array([1, 2, 3])
#| @debug.debug_inspect(q, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `Queue([])` instead")
#|#as_free_fn(deprecated="Use `Queue([])` instead")
#|pub fn[A] Queue::new() -> Queue[A] {
#| new_queue()
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Queue with @debug.Debug::{to_repr}
#|#deprecated("Use `@debug.Debug` instead of `Show` for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md", skip_current_package=true)
#|#doc(hidden)
#|pub extend Queue with Show::{output, to_string}
),
"queue.mbt": (
#|fn[A] new_queue() -> Queue[A] {
#| { inner: Deque([]), }
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[A] Queue::Queue(arr : ArrayView[A]) -> Queue[A] {
#| { inner: Deque(arr), }
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[A : Show] Show for Queue[A]
#|pub impl[A : Show] Show for Queue[A] with fn output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@queue.from_array([", suffix="])")
#|}
#|impl[A : Eq] Eq for Queue[A] with fn equal(self, other) {
#| self.inner == other.inner
#|}
#|pub fn[A] Queue::clear(self : Queue[A]) -> Unit {
#| self.inner.clear()
#|}
#|pub fn[A] Queue::length(self : Queue[A]) -> Int {
#| self.inner.length()
#|}
#|pub fn[A] Queue::is_empty(self : Queue[A]) -> Bool {
#| self.inner.is_empty()
#|}
#|#owned(x)
#|pub fn[A] Queue::push(self : Queue[A], x : A) -> Unit {
#| self.inner.push_back(x)
#|}
#|#internal(unsafe, "Panics if the queue is empty.")
#|#doc(hidden)
#|#alias(peek_exn, deprecated)
#|pub fn[A] Queue::unsafe_peek(self : Queue[A]) -> A {
#| match self.inner.front() {
#| None => abort("Queue is empty")
#| Some(x) => x
#| }
#|}
#|pub fn[A] Queue::peek(self : Queue[A]) -> A? {
#| self.inner.front()
#|}
#|#internal(unsafe, "Panics if the queue is empty.")
#|#doc(hidden)
#|#alias(pop_exn, deprecated)
#|pub fn[A] Queue::unsafe_pop(self : Queue[A]) -> A {
#| match self.inner.pop_front() {
#| None => abort("Queue is empty")
#| Some(x) => x
#| }
#|}
#|pub fn[A] Queue::pop(self : Queue[A]) -> A? {
#| self.inner.pop_front()
#|}
#|#locals(f)
#|pub fn[A] Queue::each(self : Queue[A], f : (A) -> Unit raise?) -> Unit raise? {
#| for x in self.inner {
#| f(x)
#| }
#|}
#|#locals(f)
#|pub fn[A] Queue::eachi(
#| self : Queue[A],
#| f : (Int, A) -> Unit raise?,
#|) -> Unit raise? {
#| for i, x in self.inner {
#| f(i, x)
#| }
#|}
#|#locals(f)
#|pub fn[A, B] Queue::fold(
#| self : Queue[A],
#| init~ : B,
#| f : (B, A) -> B raise?,
#|) -> B raise? {
#| let mut acc = init
#| for x in self.inner {
#| acc = f(acc, x)
#| }
#| acc
#|}
#|#alias(clone, deprecated)
#|pub fn[A] Queue::copy(self : Queue[A]) -> Queue[A] {
#| { inner: self.inner.copy(), }
#|}
#|pub fn[A] Queue::transfer(self : Queue[A], dst : Queue[A]) -> Unit {
#| if physical_equal(self.inner, dst.inner) {
#| return // no-op for self-transfer
#| }
#| dst.inner.append(self.inner)
#| self.inner.clear()
#|}
#|#alias(iterator, deprecated)
#|pub fn[A] Queue::iter(self : Queue[A]) -> Iter[A] {
#| self.inner.iter()
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[A] Queue::from_iter(iter : Iter[A]) -> Queue[A] {
#| { inner: @deque.from_iter(iter), }
#|}
#|test "from_fixed_array_2" {
#| let q = from_array([1, 2, 3, 4])
#| q.push(11)
#| @test.assert_eq(q, from_array([1, 2, 3, 4, 11]))
#| q.unsafe_pop() |> ignore
#| @test.assert_eq(q, from_array([2, 3, 4, 11]))
#|}
#|test "from_array_2" {
#| let q = from_array([1, 2, 3, 4])
#| q.push(11)
#| @test.assert_eq(q, from_array([1, 2, 3, 4, 11]))
#| q.unsafe_pop() |> ignore
#| @test.assert_eq(q, from_array([2, 3, 4, 11]))
#|}
#|test "equal" {
#| let queue = from_array([1, 2, 3, 4])
#| let queue2 = from_array([1, 2, 3, 4])
#| let queue3 = from_array([1, 2, 3, 5])
#| assert_true(queue == queue2)
#| assert_false(queue == queue3)
#| queue.unsafe_pop() |> ignore
#| assert_false(queue == queue2)
#| @test.assert_eq(queue, from_array([2, 3, 4]))
#| assert_false(from_array([]) == from_array([1]))
#|}
#|test "push" {
#| let queue : Queue[Int] = new_queue()
#| queue.push(1)
#| queue.push(2)
#| queue.push(3)
#| queue.push(1)
#| @test.assert_eq(queue.length(), 4)
#| @test.assert_eq(queue, from_array([1, 2, 3, 1]))
#|}
#|test "copy" {
#| let queue : Queue[Int] = from_array([1, 2, 3, 4])
#| let queue2 : Queue[Int] = queue.copy()
#| @test.assert_eq(queue2.length(), 4)
#| @test.assert_eq(queue2, from_array([1, 2, 3, 4]))
#| @test.assert_eq(queue.length(), 4)
#| @test.assert_eq(queue, from_array([1, 2, 3, 4]))
#|}
#|test "transfer" {
#| let queue : Queue[Int] = from_array([1, 2, 3, 4])
#| let queue2 : Queue[Int] = from_array([5, 6, 7, 8])
#| queue.transfer(queue2)
#| @test.assert_eq(queue.length(), 0)
#| @test.assert_eq(queue2.length(), 8)
#| @test.assert_eq(queue2, from_array([5, 6, 7, 8, 1, 2, 3, 4]))
#|}
),
"types.mbt": (
#|#valtype
#|struct Queue[A] {
#| inner : @deque.Deque[A]
#|}
),
},
)
///|
let moonbitlang_core_quickcheck_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/quickcheck",
deps={},
files={
"arbitrary.mbt": (
#|pub(open) trait Arbitrary {
#| fn arbitrary(Int, @splitmix.RandomState) -> Self
#|}
#|pub impl Arbitrary for Unit with fn arbitrary(_, _) {
#| ()
#|}
#|pub impl Arbitrary for Bool with fn arbitrary(_, rs) {
#| rs.next_double() < 0.5
#|}
#|pub impl Arbitrary for Byte with fn arbitrary(_, rs) {
#| rs.next_uint().to_byte()
#|}
#|pub impl Arbitrary for Bytes with fn 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 Float with fn arbitrary(_, rs) {
#| rs.next_float()
#|}
#|pub impl Arbitrary for Double with fn arbitrary(_, rs) {
#| rs.next_double()
#|}
#|pub impl Arbitrary for Char with fn arbitrary(_, rs) {
#| if rs.next_uint() % 4 < 3 {
#| (rs.next_uint() % 128).reinterpret_as_int().to_char().unwrap()
#| } else {
#| let index = (rs.next_uint() % (0x110000 - 0x800)).reinterpret_as_int()
#| let code = if index < 0xD800 { index } else { index + 0x800 }
#| code.to_char().unwrap()
#| }
#|}
#|pub impl Arbitrary for String with fn arbitrary(size, rs) {
#| let len = if size == 0 { 0 } else { rs.next_positive_int() % size }
#| let buf = StringBuilder(size_hint=len * 2)
#| for i in 0.. {
#| guard i < len else { None }
#| let elem = X::arbitrary(i, rs)
#| i += 1
#| Some(elem)
#| })
#|}
#|pub fn[T : Arbitrary] gen(size? : Int, state? : @splitmix.RandomState) -> T {
#| let size = size.unwrap_or(0)
#| let state = state.unwrap_or_else(() => {
#| (Default::default() : @splitmix.RandomState)
#| })
#| Arbitrary::arbitrary(size, state)
#|}
#|pub impl[X : Arbitrary] Arbitrary for X? with fn arbitrary(i, rs) {
#| if rs.next_double() < 0.3 {
#| None
#| } else {
#| Some(Arbitrary::arbitrary(i, rs))
#| }
#|}
#|pub impl[T : Arbitrary, E : Arbitrary] Arbitrary for Result[T, E] with fn arbitrary(
#| size,
#| rs,
#|) {
#| if Arbitrary::arbitrary(size, rs) {
#| Ok(T::arbitrary(size, rs))
#| } else {
#| Err(E::arbitrary(size, rs))
#| }
#|}
#|pub impl[X : Arbitrary] Arbitrary for FixedArray[X] with fn arbitrary(size, rs) {
#| let len = if size == 0 { 0 } else { rs.next_positive_int() % size }
#| FixedArray::makei(len, i => X::arbitrary(i, rs))
#|}
#|pub impl[X : Arbitrary] Arbitrary for ReadOnlyArray[X] with fn arbitrary(
#| size,
#| rs,
#|) {
#| let values : Array[X] = Arbitrary::arbitrary(size, rs)
#| ReadOnlyArray::from_array(values)
#|}
#|pub impl[A : Arbitrary] Arbitrary for ArrayView[A] with fn arbitrary(size, rs) {
#| let arr : Array[A] = Arbitrary::arbitrary(size, rs)
#| arr
#|}
#|pub impl[X : Arbitrary] Arbitrary for Array[X] with fn arbitrary(size, rs) {
#| let len = if size == 0 { 0 } else { rs.next_positive_int() % size }
#| Array::makei(len, x => X::arbitrary(x, rs))
#|}
#|pub impl[X : Arbitrary] Arbitrary for @ref.Ref[X] with fn arbitrary(size, rs) {
#| @ref.new(X::arbitrary(size, rs))
#|}
#|pub impl[A : Arbitrary, B : Arbitrary] Arbitrary for (A, B) with fn 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 fn 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 fn 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 fn 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 fn 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 fn 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)
#|}
#|pub impl[
#| A : Arbitrary,
#| B : Arbitrary,
#| C : Arbitrary,
#| D : Arbitrary,
#| E : Arbitrary,
#| F : Arbitrary,
#| G : Arbitrary,
#| H : Arbitrary,
#|] Arbitrary for (A, B, C, D, E, F, G, H) with fn arbitrary(size, r0) {
#| let r1 = r0.split()
#| let (v1, v2, v3, v4, v5, v6, v7) = Arbitrary::arbitrary(size, r1)
#| (Arbitrary::arbitrary(size, r0), v1, v2, v3, v4, v5, v6, v7)
#|}
#|pub impl[
#| A : Arbitrary,
#| B : Arbitrary,
#| C : Arbitrary,
#| D : Arbitrary,
#| E : Arbitrary,
#| F : Arbitrary,
#| G : Arbitrary,
#| H : Arbitrary,
#| I : Arbitrary,
#|] Arbitrary for (A, B, C, D, E, F, G, H, I) with fn arbitrary(size, r0) {
#| let r1 = r0.split()
#| let (v1, v2, v3, v4, v5, v6, v7, v8) = Arbitrary::arbitrary(size, r1)
#| (Arbitrary::arbitrary(size, r0), v1, v2, v3, v4, v5, v6, v7, v8)
#|}
),
"arbitrary_bigint.mbt": (
#|fn[T] @splitmix.RandomState::pick(
#| self : @splitmix.RandomState,
#| values : ReadOnlyArray[T],
#|) -> T {
#| let index = self.next_uint(limit=values.length().reinterpret_as_uint())
#| values[index.reinterpret_as_int()]
#|}
#|fn with_random_sign(
#| magnitude : @bigint.BigInt,
#| rs : @splitmix.RandomState,
#|) -> @bigint.BigInt {
#| if magnitude.is_zero() || rs.next_uint(limit=2U) == 0U {
#| magnitude
#| } else {
#| -magnitude
#| }
#|}
#|fn around(base : @bigint.BigInt, rs : @splitmix.RandomState) -> @bigint.BigInt {
#| with_random_sign(base + rs.pick([-1N, 0N, 1N]), rs)
#|}
#|fn random_bigint(size : Int, rs : @splitmix.RandomState) -> @bigint.BigInt {
#| let chunk_limit = size.clamp(min=0, max=31) + 1
#| let chunk_count = for count in 1.. {
#| rs.next_uint(limit=256U).to_byte()
#| })
#| with_random_sign(@bigint.BigInt::from_octets(bytes), rs)
#|}
#|pub impl Arbitrary for @bigint.BigInt with fn arbitrary(size, rs) {
#| match rs.next_uint(limit=100U) {
#| 0..<35 => random_bigint(size, rs)
#| 35..<60 => rs.pick([0N, 1N, -1N, 2N, -2N, 10N, -10N])
#| 60..<85 =>
#| around(
#| 1N <<
#| rs.pick([0, 1, 7, 8, 15, 16, 31, 32, 52, 53, 63, 64, 127, 128, 255, 256]),
#| rs,
#| )
#| _ => {
#| let exponent = rs.pick([1, 2, 3, 6, 9, 18, 19, 38, 76, 100])
#| around(
#| (0 : Int).until(exponent).fold(init=1N, (power, _) => power * 10N),
#| rs,
#| )
#| }
#| }
#|}
),
"arbitrary_collections.mbt": (
#|pub impl[X : Arbitrary] Arbitrary for @list.List[X] with fn arbitrary(size, rs) {
#| let values : Array[X] = Arbitrary::arbitrary(size, rs)
#| List(values)
#|}
#|pub impl[X : Arbitrary] Arbitrary for @queue.Queue[X] with fn arbitrary(
#| size,
#| rs,
#|) {
#| let values : Iter[X] = Arbitrary::arbitrary(size, rs)
#| @queue.Queue::from_iter(values)
#|}
#|pub impl[X : Arbitrary] Arbitrary for @deque.Deque[X] with fn arbitrary(
#| size,
#| rs,
#|) {
#| let values : Array[X] = Arbitrary::arbitrary(size, rs)
#| Deque(values)
#|}
#|pub impl[K : Arbitrary + Hash + Eq, V : Arbitrary] Arbitrary for Map[K, V] with fn arbitrary(
#| size,
#| rs,
#|) {
#| let values : Iter[(K, V)] = Arbitrary::arbitrary(size, rs)
#| Map::from_iter(values)
#|}
#|pub impl[X : Arbitrary + Eq + Hash] Arbitrary for @set.Set[X] with fn arbitrary(
#| size,
#| rs,
#|) {
#| let values : Iter[X] = Arbitrary::arbitrary(size, rs)
#| @set.Set::from_iter(values)
#|}
#|pub impl[K : Arbitrary + Hash + Eq, V : Arbitrary] Arbitrary for @hashmap.HashMap[
#| K,
#| V,
#|] with fn arbitrary(size, rs) {
#| let values : Iter[(K, V)] = Arbitrary::arbitrary(size, rs)
#| @hashmap.HashMap::from_iter(values)
#|}
#|pub impl[X : Arbitrary + Eq + Hash] Arbitrary for @hashset.HashSet[X] with fn arbitrary(
#| size,
#| rs,
#|) {
#| let values : Iter[X] = Arbitrary::arbitrary(size, rs)
#| @hashset.HashSet::from_iter(values)
#|}
#|pub impl[K : Arbitrary + Compare, V : Arbitrary] Arbitrary for @sorted_map.SortedMap[
#| K,
#| V,
#|] with fn arbitrary(size, rs) {
#| let values : Iter[(K, V)] = Arbitrary::arbitrary(size, rs)
#| @sorted_map.SortedMap::from_iter(values)
#|}
#|pub impl[X : Arbitrary + Compare] Arbitrary for @sorted_set.SortedSet[X] with fn arbitrary(
#| size,
#| rs,
#|) {
#| let values : Iter[X] = Arbitrary::arbitrary(size, rs)
#| @sorted_set.SortedSet::from_iter(values)
#|}
#|pub impl[X : Arbitrary + Compare] Arbitrary for @priority_queue.PriorityQueue[X] with fn arbitrary(
#| size,
#| rs,
#|) {
#| let len = if size == 0 { 0 } else { rs.next_positive_int() % size }
#| let queue : @priority_queue.PriorityQueue[X] = PriorityQueue([])
#| for i in 0.. UInt {
#| match (bits, signed) {
#| (16, _) => 5U
#| (32, _) => 10U
#| (64, true) => 19U
#| (64, false) => 20U
#| _ => abort("arbitrary integer: unsupported bit width")
#| }
#|}
#|fn canonical_integer_bits(
#| mask : UInt64,
#| signed : Bool,
#| rs : @splitmix.RandomState,
#|) -> UInt64 {
#| guard signed else { rs.next_uint(limit=4U).to_uint64() }
#| match rs.next_uint(limit=5U) {
#| 0U => 0UL
#| 1U => 1UL
#| 2U => mask
#| 3U => 2UL
#| _ => mask - 1UL
#| }
#|}
#|fn apply_random_sign(
#| magnitude : UInt64,
#| signed : Bool,
#| rs : @splitmix.RandomState,
#|) -> UInt64 {
#| if signed && rs.next_uint(limit=2U) == 1U {
#| 0UL - magnitude
#| } else {
#| magnitude
#| }
#|}
#|fn boundary_delta(base : UInt64, rs : @splitmix.RandomState) -> UInt64 {
#| match rs.next_uint(limit=3U) {
#| 0U => base - 1UL
#| 1U => base
#| _ => base + 1UL
#| }
#|}
#|fn binary_boundary_bits(
#| bits : Int,
#| signed : Bool,
#| rs : @splitmix.RandomState,
#|) -> UInt64 {
#| let exponent_count = if signed { bits - 1 } else { bits }
#| let exponent = rs
#| .next_uint(limit=exponent_count.reinterpret_as_uint())
#| .reinterpret_as_int()
#| let magnitude = boundary_delta(1UL << exponent, rs)
#| apply_random_sign(magnitude, signed, rs)
#|}
#|fn decimal_boundary_bits(
#| bits : Int,
#| signed : Bool,
#| rs : @splitmix.RandomState,
#|) -> UInt64 {
#| let exponent = rs
#| .next_uint(limit=decimal_power_count(bits, signed))
#| .reinterpret_as_int()
#| let magnitude = boundary_delta(
#| (0 : Int).until(exponent).fold(init=1UL, (power, _) => power * 10UL),
#| rs,
#| )
#| apply_random_sign(magnitude, signed, rs)
#|}
#|fn extreme_integer_bits(
#| bits : Int,
#| mask : UInt64,
#| signed : Bool,
#| rs : @splitmix.RandomState,
#|) -> UInt64 {
#| let choice = rs.next_uint(limit=4U)
#| if signed {
#| let sign_bit = 1UL << (bits - 1)
#| match choice {
#| 0U => sign_bit
#| 1U => sign_bit + 1UL
#| 2U => sign_bit - 2UL
#| _ => sign_bit - 1UL
#| }
#| } else {
#| match choice {
#| 0U => mask
#| 1U => mask - 1UL
#| 2U => mask - 2UL
#| _ => 1UL << (bits - 1)
#| }
#| }
#|}
#|fn gen_integer_bits(
#| bits : Int,
#| signed : Bool,
#| rs : @splitmix.RandomState,
#|) -> UInt64 {
#| let mask = if bits == 64 {
#| 0xffff_ffff_ffff_ffffUL
#| } else {
#| (1UL << bits) - 1UL
#| }
#| let value = match rs.next_uint(limit=100U) {
#| 0..<40 => rs.next_uint64()
#| 40..<60 => canonical_integer_bits(mask, signed, rs)
#| 60..<80 => binary_boundary_bits(bits, signed, rs)
#| 80..<90 => decimal_boundary_bits(bits, signed, rs)
#| _ => extreme_integer_bits(bits, mask, signed, rs)
#| }
#| value & mask
#|}
#|pub impl Arbitrary for Int16 with fn arbitrary(_, rs) {
#| Int16::reinterpret_from_uint16(gen_integer_bits(16, true, rs).to_uint16())
#|}
#|pub impl Arbitrary for UInt16 with fn arbitrary(_, rs) {
#| gen_integer_bits(16, false, rs).to_uint16()
#|}
#|pub impl Arbitrary for Int with fn arbitrary(_, rs) {
#| gen_integer_bits(32, true, rs).to_uint().reinterpret_as_int()
#|}
#|pub impl Arbitrary for UInt with fn arbitrary(_, rs) {
#| gen_integer_bits(32, false, rs).to_uint()
#|}
#|pub impl Arbitrary for Int64 with fn arbitrary(_, rs) {
#| gen_integer_bits(64, true, rs).reinterpret_as_int64()
#|}
#|pub impl Arbitrary for UInt64 with fn arbitrary(_, rs) {
#| gen_integer_bits(64, false, rs)
#|}
),
"driver.mbt": (
#|fn size_at(
#| index : UInt,
#| count : UInt,
#| max_size : UInt,
#| recent_discards : UInt,
#|) -> Int {
#| let base_size = if count <= 1 {
#| 0UL
#| } else {
#| index.to_uint64() * max_size.to_uint64() / (count - 1).to_uint64()
#| }
#| let size = base_size + recent_discards.to_uint64()
#| let limit = if max_size.to_uint64() > @int.MAX_VALUE.to_uint64() {
#| @int.MAX_VALUE.to_uint64()
#| } else {
#| max_size.to_uint64()
#| }
#| if size > limit {
#| limit.to_int()
#| } else {
#| size.to_int()
#| }
#|}
#|priv enum CaseOutcome {
#| Passed
#| Discarded
#| Falsified
#| Raised(Error)
#|}
#|enum QuickCheckReport[A] {
#| Passed(tests~ : UInt, observations~ : ObservationSummary)
#| GaveUp(tests~ : UInt, discarded~ : UInt, observations~ : ObservationSummary)
#| Falsified(
#| counterexample~ : A,
#| context~ : String?,
#| tests~ : UInt,
#| size~ : Int,
#| shrinks~ : UInt,
#| shrink_attempts~ : UInt,
#| observations~ : ObservationSummary
#| )
#| Raised(
#| counterexample~ : A,
#| error~ : Error,
#| context~ : String?,
#| tests~ : UInt,
#| size~ : Int,
#| shrinks~ : UInt,
#| shrink_attempts~ : UInt,
#| observations~ : ObservationSummary
#| )
#|}
#|pub impl[A : @debug.Debug] @debug.Debug for QuickCheckReport[A] with fn to_repr(
#| self,
#|) {
#| match self {
#| Passed(tests~, observations~) =>
#| @debug.Repr::ctor(
#| "Passed",
#| [
#| (Some("tests"), Repr(tests)),
#| ..if !observations.is_empty() {
#| [(Some("observations"), @debug.Repr(observations))]
#| },
#| ],
#| )
#| GaveUp(tests~, discarded~, observations~) =>
#| @debug.Repr::ctor(
#| "GaveUp",
#| [
#| (Some("tests"), Repr(tests)),
#| (Some("discarded"), Repr(discarded)),
#| ..if !observations.is_empty() {
#| [(Some("observations"), @debug.Repr(observations))]
#| },
#| ],
#| )
#| Falsified(
#| counterexample~,
#| context~,
#| tests~,
#| size~,
#| shrinks~,
#| shrink_attempts~,
#| observations~
#| ) =>
#| @debug.Repr::ctor(
#| "Falsified",
#| [
#| (Some("counterexample"), Repr(counterexample)),
#| ..if context is Some(text) {
#| [(Some("context"), @debug.Repr(text))]
#| },
#| (Some("tests"), Repr(tests)),
#| (Some("size"), Repr(size)),
#| (Some("shrinks"), Repr(shrinks)),
#| (Some("shrink_attempts"), Repr(shrink_attempts)),
#| ..if !observations.is_empty() {
#| [(Some("observations"), @debug.Repr(observations))]
#| },
#| ],
#| )
#| Raised(
#| counterexample~,
#| error~,
#| context~,
#| tests~,
#| size~,
#| shrinks~,
#| shrink_attempts~,
#| observations~
#| ) =>
#| @debug.Repr::ctor(
#| "Raised",
#| [
#| (Some("counterexample"), Repr(counterexample)),
#| ..if context is Some(text) {
#| [(Some("context"), @debug.Repr(text))]
#| },
#| (Some("error"), Repr(error)),
#| (Some("tests"), Repr(tests)),
#| (Some("size"), Repr(size)),
#| (Some("shrinks"), Repr(shrinks)),
#| (Some("shrink_attempts"), Repr(shrink_attempts)),
#| ..if !observations.is_empty() {
#| [(Some("observations"), @debug.Repr(observations))]
#| },
#| ],
#| )
#| }
#|}
#|#deprecated("Use `@debug.Debug::to_repr` instead")
#|#doc(hidden)
#|pub extend QuickCheckReport with @debug.Debug::{to_repr}
#|fn[A] evaluate_case(
#| property : (A) -> Bool raise?,
#| filter : (A) -> Bool,
#| input : A,
#|) -> CaseOutcome {
#| guard filter(input) else { Discarded }
#| let invoke : (A) -> Bool raise = a => property(a)
#| try invoke(input) catch {
#| err => Raised(err)
#| } noraise {
#| true => Passed
#| false => Falsified
#| }
#|}
#|impl Eq for CaseOutcome with fn equal(expected, actual) {
#| match (expected, actual) {
#| (Falsified, Falsified) | (Raised(_), Raised(_)) => true
#| _ => false
#| }
#|}
#|fn[A : @shrink.Shrink] shrink_failure(
#| property : (A) -> Bool raise?,
#| filter : (A) -> Bool,
#| input : A,
#| initial : CaseOutcome,
#| max_shrinks : UInt,
#|) -> (A, CaseOutcome, UInt, UInt) {
#| let mut current = input
#| let mut current_outcome = initial
#| let mut successful = 0U
#| let mut attempted = 0U
#| let mut found = true
#| while attempted < max_shrinks && found {
#| found = false
#| let candidates = @shrink.Shrink::shrink(current)
#| while attempted < max_shrinks && candidates.next() is Some(candidate) {
#| attempted = attempted + 1
#| let outcome = evaluate_case(property, filter, candidate)
#| if initial == outcome {
#| current = candidate
#| current_outcome = outcome
#| successful = successful + 1
#| found = true
#| break
#| }
#| }
#| }
#| (current, current_outcome, successful, attempted)
#|}
#|fn context_line(context : String?) -> String {
#| match context {
#| Some(text) => "\ncontext: \{text}"
#| None => ""
#| }
#|}
#|fn[A : @debug.Debug] failure_report(report : QuickCheckReport[A]) -> String {
#| match report {
#| Passed(..) => abort("quickcheck internal error: a passed property reported")
#| GaveUp(tests~, discarded~, observations~) =>
#| (
#| $|QuickCheck gave up after \{tests} test(s)
#| $|discarded: \{discarded}\{observations.report(tests, prefix="\n")}
#| )
#| Falsified(
#| counterexample~,
#| context~,
#| tests~,
#| size~,
#| shrinks~,
#| shrink_attempts~,
#| observations~
#| ) =>
#| (
#| $|QuickCheck falsified after \{tests} test(s)
#| $|counterexample: \{@debug.to_string(counterexample)}\{context_line(context)}
#| $|size: \{size}
#| $|shrinks: \{shrinks} successful, \{shrink_attempts} attempted\{observations.report(tests - 1U, prefix="\n")}
#| )
#| Raised(
#| counterexample~,
#| error~,
#| context~,
#| tests~,
#| size~,
#| shrinks~,
#| shrink_attempts~,
#| observations~
#| ) =>
#| (
#| $|QuickCheck property raised after \{tests} test(s)
#| $|counterexample: \{@debug.to_string(counterexample)}\{context_line(context)}
#| $|error: \{@debug.to_string(error)}
#| $|size: \{size}
#| $|shrinks: \{shrinks} successful, \{shrink_attempts} attempted\{observations.report(tests - 1U, prefix="\n")}
#| )
#| }
#|}
#|pub fn[A : Arbitrary + @shrink.Shrink] report(
#| property : (A) -> Bool raise?,
#| filter? : (A) -> Bool = _ => true,
#| observe? : (A) -> Observations = _ => [],
#| counterexample_context? : (A) -> String,
#| count? : UInt = 100,
#| max_size? : UInt = 100,
#| max_shrinks? : UInt = 100,
#| discard_ratio? : UInt = 10,
#| seed? : UInt64 = 37,
#|) -> QuickCheckReport[A] {
#| let state = @splitmix.new(seed~)
#| let observations = ObservationSummary::empty()
#| for tests = 0U, discarded = 0U, recent_discards = 0U; tests < count; {
#| let size = size_at(tests, count, max_size, recent_discards)
#| let input : A = Arbitrary::arbitrary(size, state.split())
#| let outcome = evaluate_case(property, filter, input)
#| match outcome {
#| Passed => {
#| observations.add(observe(input))
#| continue tests + 1, discarded, 0U
#| }
#| Discarded => {
#| let next_discarded = discarded + 1
#| if discard_ratio == 0 || next_discarded / discard_ratio >= count {
#| return GaveUp(tests~, discarded=next_discarded, observations~)
#| }
#| continue tests, next_discarded, recent_discards + 1
#| }
#| _ => {
#| let completed_tests = tests + 1
#| let (counterexample, outcome, shrinks, shrink_attempts) = shrink_failure(
#| property, filter, input, outcome, max_shrinks,
#| )
#| let context = counterexample_context.map(render => {
#| render(counterexample)
#| })
#| return match outcome {
#| Falsified =>
#| Falsified(
#| counterexample~,
#| context~,
#| tests=completed_tests,
#| size~,
#| shrinks~,
#| shrink_attempts~,
#| observations~,
#| )
#| Raised(error) =>
#| Raised(
#| counterexample~,
#| error~,
#| context~,
#| tests=completed_tests,
#| size~,
#| shrinks~,
#| shrink_attempts~,
#| observations~,
#| )
#| Passed | Discarded =>
#| abort(
#| "quickcheck internal error: unexpected non-failure after shrinking",
#| )
#| }
#| }
#| }
#| } nobreak {
#| Passed(tests=count, observations~)
#| }
#|}
#|#callsite(autofill(loc))
#|pub fn[A : Arbitrary + @shrink.Shrink + @debug.Debug] check(
#| property : (A) -> Bool raise?,
#| filter? : (A) -> Bool = _ => true,
#| observe? : (A) -> Observations = _ => [],
#| counterexample_context? : (A) -> String,
#| count? : UInt = 100,
#| max_size? : UInt = 100,
#| max_shrinks? : UInt = 100,
#| discard_ratio? : UInt = 10,
#| seed? : UInt64 = 37,
#| loc~ : SourceLoc,
#|) -> Unit raise {
#| let result = report(
#| property,
#| filter~,
#| observe~,
#| counterexample_context?,
#| count~,
#| max_size~,
#| max_shrinks~,
#| discard_ratio~,
#| seed~,
#| )
#| match result {
#| Passed(observations~, ..) if observations.is_empty() => ()
#| Passed(tests~, observations~) => println(observations.report(tests))
#| GaveUp(..) | Falsified(..) | Raised(..) =>
#| fail(failure_report(result), loc~)
#| }
#|}
),
"facade.mbt": (
#|pub using @shrink {trait Shrink}
),
"generator.mbt": (
#|pub using @splitmix {type RandomState}
#|struct Generator[T] {
#| generate : (Int, RandomState) -> T
#|}
#|pub fn[T] Generator::Generator(
#| generate : (Int, RandomState) -> T,
#|) -> Generator[T] {
#| { generate, }
#|}
#|pub fn[T : Arbitrary] spawn() -> Generator[T] {
#| Generator(Arbitrary::arbitrary)
#|}
#|pub fn[T] Generator::run(
#| self : Generator[T],
#| size : Int,
#| state : RandomState,
#|) -> T {
#| (self.generate)(size, state)
#|}
#|pub fn[T] Generator::sample(
#| self : Generator[T],
#| size? : Int = 100,
#| seed? : UInt64 = 37,
#|) -> T {
#| self.run(size, @splitmix.new(seed~))
#|}
#|pub fn[T] Generator::samples(
#| self : Generator[T],
#| count? : Int = 10,
#| size? : Int = 100,
#| seed? : UInt64 = 37,
#|) -> Array[T] {
#| let state = @splitmix.new(seed~)
#| Array::makei(count, _ => self.run(size, state))
#|}
#|pub fn[T] pure(value : T) -> Generator[T] {
#| Generator((_, _) => value)
#|}
#|pub fn[T, U] Generator::map(
#| self : Generator[T],
#| transform : (T) -> U,
#|) -> Generator[U] {
#| Generator((size, state) => transform(self.run(size, state)))
#|}
#|pub fn[T, U] Generator::flat_map(
#| self : Generator[T],
#| transform : (T) -> Generator[U],
#|) -> Generator[U] {
#| Generator((size, state) => {
#| let next_state = state.split()
#| transform(self.run(size, state)).run(size, next_state)
#| })
#|}
#|pub fn[T, U] Generator::zip(
#| self : Generator[T],
#| other : Generator[U],
#|) -> Generator[(T, U)] {
#| self.zip_with(other, (first, second) => (first, second))
#|}
#|pub fn[T, U, V] Generator::zip_with(
#| self : Generator[T],
#| other : Generator[U],
#| combine : (T, U) -> V,
#|) -> Generator[V] {
#| Generator((size, state) => {
#| let other_state = state.split()
#| combine(self.run(size, state), other.run(size, other_state))
#| })
#|}
#|pub fn[T, U, V, W] Generator::zip_with3(
#| self : Generator[T],
#| second : Generator[U],
#| third : Generator[V],
#| combine : (T, U, V) -> W,
#|) -> Generator[W] {
#| Generator((size, state) => {
#| let second_state = state.split()
#| let third_state = second_state.split()
#| combine(
#| self.run(size, state),
#| second.run(size, second_state),
#| third.run(size, third_state),
#| )
#| })
#|}
#|pub fn[T] sized(create : (Int) -> Generator[T]) -> Generator[T] {
#| Generator((size, state) => create(size).run(size, state))
#|}
#|pub fn[T] Generator::scale(
#| self : Generator[T],
#| transform : (Int) -> Int,
#|) -> Generator[T] {
#| Generator((size, state) => self.run(transform(size), state))
#|}
#|pub fn[T] Generator::resize(self : Generator[T], size : Int) -> Generator[T] {
#| self.scale(_ => size)
#|}
#|pub fn int_range(lower : Int, upper : Int) -> Generator[Int] {
#| guard lower < upper else {
#| if lower == upper {
#| return pure(lower)
#| }
#| abort("int_range: lower bound exceeds upper bound")
#| }
#| let width = (upper - lower).reinterpret_as_uint()
#| Generator((_, state) => {
#| (state.next_uint() % width).reinterpret_as_int() + lower
#| })
#|}
#|pub fn char_range(lower : Char, upper : Char) -> Generator[Char] {
#| let lo = lower.to_int()
#| let hi = upper.to_int()
#| fn is_surrogate(code : Int) -> Bool {
#| code >= 0xD800 && code <= 0xDFFF
#| }
#| guard lo <= hi else { abort("char_range: lower bound exceeds upper bound") }
#| guard lo >= 0 && hi <= 0x10FFFF && !is_surrogate(lo) && !is_surrogate(hi) else {
#| abort("char_range: bounds must be Unicode scalar values")
#| }
#| let gap = if lo < 0xD800 && hi > 0xDFFF { 0x800 } else { 0 }
#| int_range(lo, hi + 1 - gap).map(code => {
#| let code = if code >= 0xD800 { code + gap } else { code }
#| code.to_char().unwrap()
#| })
#|}
#|pub fn[T] one_of(generators : Array[Generator[T]]) -> Generator[T] {
#| guard !generators.is_empty() else { abort("one_of: empty array") }
#| int_range(0, generators.length()).flat_map(index => generators[index])
#|}
#|pub fn[T] elements(values : Array[T]) -> Generator[T] {
#| guard !values.is_empty() else { abort("elements: empty array") }
#| int_range(0, values.length()).map(index => values[index])
#|}
#|pub fn[T] frequency(generators : Array[(UInt, Generator[T])]) -> Generator[T] {
#| guard !generators.is_empty() else { abort("frequency: empty array") }
#| let total = for pair in generators; total = 0U {
#| let (weight, _) = pair
#| continue total + weight
#| } nobreak {
#| total
#| }
#| guard total > 0 else { abort("frequency: total weight is zero") }
#| Generator((size, state) => {
#| let choice = state.next_uint() % total
#| for pair in generators; remaining = choice {
#| let (weight, generator) = pair
#| if remaining < weight {
#| break generator.run(size, state)
#| }
#| continue remaining - weight
#| } nobreak {
#| abort("frequency: invalid weights")
#| }
#| })
#|}
#|pub fn[T] Generator::array_with_size(
#| self : Generator[T],
#| size : Int,
#|) -> Generator[Array[T]] {
#| guard size >= 0 else { abort("array_with_size: negative size") }
#| Generator((sample_size, state) => {
#| Array::makei(size, _ => self.run(sample_size, state))
#| })
#|}
),
"observation.mbt": (
#|enum Observation {
#| Label(String)
#| Class(label~ : String, hit~ : Bool)
#|} derive(@debug.Debug)
#|type Observations = Array[Observation]
#|priv struct ObservationSummary {
#| labels : Map[@list.List[String], UInt]
#| classes : Map[String, UInt]
#|}
#|impl @debug.Debug for ObservationSummary with fn to_repr(self) {
#| @debug.Repr::record(
#| Map(
#| [
#| ..if !self.labels.is_empty() {
#| [("labels", @debug.Repr(self.labels))]
#| },
#| ..if !self.classes.is_empty() {
#| [("classes", @debug.Repr(self.classes))]
#| },
#| ],
#| ),
#| )
#|}
#|pub impl Show for Observation with fn output(self, logger) {
#| match self {
#| Label(value) => logger.write_string(value)
#| Class(label~, ..) => logger.write_string(label)
#| }
#|}
#|#deprecated("Use `@debug.Debug::to_repr` instead")
#|#doc(hidden)
#|pub extend Observation with @debug.Debug::{to_repr}
#|pub fn label(value : String) -> Observation {
#| Label(value)
#|}
#|pub fn classify(condition : Bool, label : String) -> Observation {
#| Class(label~, hit=condition)
#|}
#|pub fn[T : @debug.Debug] collect(value : T) -> Observation {
#| label(@debug.to_string(value))
#|}
#|fn ObservationSummary::empty() -> ObservationSummary {
#| { labels: {}, classes: {}, }
#|}
#|fn ObservationSummary::is_empty(self : ObservationSummary) -> Bool {
#| self.labels.is_empty() && self.classes.is_empty()
#|}
#|fn ObservationSummary::add(
#| self : ObservationSummary,
#| observations : Observations,
#|) -> Unit {
#| let labels = []
#| let classes : Map[String, Bool] = Map([])
#| for observation in observations {
#| match observation {
#| Label(value) => labels.push(value)
#| Class(label~, hit~) =>
#| classes[label] = classes.get_or_default(label, false) || hit
#| }
#| }
#| labels.sort()
#| labels.dedup()
#| if !labels.is_empty() {
#| let key = @list.List(labels)
#| self.labels[key] = self.labels.get_or_default(key, 0U) + 1U
#| }
#| for label, hit in classes {
#| let increment = if hit { 1U } else { 0U }
#| self.classes[label] = self.classes.get_or_default(label, 0U) + increment
#| }
#|}
#|priv struct ObservationRow {
#| count : UInt
#| name : String
#|} derive(Eq)
#|impl Compare for ObservationRow with fn compare(
#| left : ObservationRow,
#| right : ObservationRow,
#|) {
#| match Compare::compare(right.count, left.count) {
#| 0 => Compare::compare(left.name, right.name)
#| order => order
#| }
#|}
#|fn percentage(count : UInt, total : UInt) -> UInt {
#| guard total > 0U else { return 0U }
#| let total = total.to_uint64()
#| ((count.to_uint64() * 100UL + total / 2UL) / total).to_uint()
#|}
#|fn write_observation_rows(
#| builder : StringBuilder,
#| heading : String,
#| rows : Array[ObservationRow],
#| total : UInt,
#| count_width : Int,
#|) -> Unit {
#| guard !rows.is_empty() else { return }
#| rows.sort_by(Compare::compare)
#| builder <+ "\n \{heading}:"
#| for row in rows {
#| let count = "\{row.count}".pad_start(count_width, ' ')
#| let percent = "\{percentage(row.count, total)}".pad_start(3, ' ')
#| builder <+ "\n \{count} \{percent}% \{row.name}"
#| }
#|}
#|fn ObservationSummary::report(
#| self : ObservationSummary,
#| total : UInt,
#| prefix? : String = "",
#|) -> String {
#| guard !self.is_empty() else { return "" }
#| let label_rows = [
#| for labels, count in self.labels => {
#| { count, name: labels.iter().join(", "), }
#| }
#| ]
#| let class_rows = [ for name, count in self.classes => { count, name, } ]
#| let builder = StringBuilder()
#| builder <+ "\{prefix}observations:"
#| let count_width = "\{total}".length()
#| write_observation_rows(builder, "labels", label_rows, total, count_width)
#| write_observation_rows(builder, "classes", class_rows, total, count_width)
#| builder.to_string()
#|}
#|pub extend Observation with Show::{to_string}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Observation with Show::{output}
),
"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.. [||]
#| More(x, tail=xs) =>
#| Shrink::shrink(x)
#| .map(x_ => xs.add(x_))
#| .concat(shr_sub_terms(xs).map(xs_ => xs_.add(x)))
#| }
#| }
#| [
#| for k = n / 2; k > 0; k = k / 2 => k
#| ]
#| .rev_iter()
#| .flat_map(k => removes_list(k, n, xs))
#| .concat(deferred(() => shr_sub_terms(xs)))
#|}
#|pub impl[T : Shrink] Shrink for @queue.Queue[T] with fn shrink(xs) {
#| Shrink::shrink(xs.iter().collect()).map(candidate => Queue(candidate))
#|}
#|pub impl[T : Shrink] Shrink for @deque.Deque[T] with fn shrink(xs) {
#| Shrink::shrink(xs.to_array()).map(candidate => Deque(candidate))
#|}
#|pub impl[T : Shrink] Shrink for @immut_vector.Vector[T] with fn shrink(xs) {
#| Shrink::shrink(xs.to_array()).map(candidate => Vector(candidate))
#|}
#|pub impl[T : Shrink + Eq + Hash] Shrink for @hashset.HashSet[T] with fn shrink(
#| xs,
#|) {
#| Shrink::shrink(xs.to_array()).map(candidate => HashSet(candidate))
#|}
#|pub impl[T : Shrink + Compare] Shrink for @sorted_set.SortedSet[T] with fn shrink(
#| xs,
#|) {
#| Shrink::shrink(xs.to_array()).map(candidate => SortedSet(candidate))
#|}
#|pub impl[T : Shrink + Eq + Hash] Shrink for @immut_hashset.HashSet[T] with fn shrink(
#| xs,
#|) {
#| Shrink::shrink(xs.iter().collect()).map(candidate => HashSet(candidate))
#|}
#|pub impl[T : Shrink + Compare] Shrink for @immut_sorted_set.SortedSet[T] with fn shrink(
#| xs,
#|) {
#| Shrink::shrink(xs.to_array()).map(candidate => SortedSet(candidate))
#|}
#|pub impl[T : Shrink + Eq + Hash] Shrink for @set.Set[T] with fn shrink(xs) {
#| Shrink::shrink(xs.to_array()).map(candidate => Set(candidate))
#|}
#|pub impl[K : Shrink + Hash + Eq, V : Shrink] Shrink for Map[K, V] with fn shrink(
#| xs,
#|) {
#| let entries = xs.to_array()
#| Shrink::shrink(entries).map(candidate => Map(candidate))
#|}
#|pub impl[T : Shrink + Compare] Shrink for @priority_queue.PriorityQueue[T] with fn shrink(
#| xs,
#|) {
#| Shrink::shrink(xs.to_array()).map(candidate => PriorityQueue(candidate))
#|}
#|pub impl[T : Shrink + Compare] Shrink for @immut_priority_queue.PriorityQueue[T] with fn shrink(
#| xs,
#|) {
#| Shrink::shrink(xs.to_array()).map(candidate => PriorityQueue(candidate))
#|}
#|pub impl[K : Shrink + Hash + Eq, V : Shrink] Shrink for @hashmap.HashMap[K, V] with fn shrink(
#| xs,
#|) {
#| Shrink::shrink(xs.to_array()).map(candidate => HashMap(candidate))
#|}
#|pub impl[K : Shrink + Compare, V : Shrink] Shrink for @sorted_map.SortedMap[
#| K,
#| V,
#|] with fn shrink(xs) {
#| Shrink::shrink(xs.to_array()).map(candidate => SortedMap(candidate))
#|}
#|pub impl[K : Shrink + Eq + Hash, V : Shrink] Shrink for @immut_hashmap.HashMap[
#| K,
#| V,
#|] with fn shrink(xs) {
#| Shrink::shrink(xs.to_array()).map(candidate => HashMap(candidate))
#|}
#|pub impl[K : Shrink + Compare, V : Shrink] Shrink for @immut_sorted_map.SortedMap[
#| K,
#| V,
#|] with fn shrink(xs) {
#| Shrink::shrink(xs.to_array()).map(candidate => SortedMap(candidate))
#|}
),
"composite.mbt": (
#|pub impl[T : Shrink] Shrink for T? with fn shrink(x) {
#| match x {
#| None => [||]
#| Some(v) => Shrink::shrink(v).map(v1 => Some(v1)).concat([|None|])
#| }
#|}
#|pub impl[T : Shrink, E : Shrink] Shrink for Result[T, E] with fn shrink(x) {
#| match x {
#| Ok(v) => Shrink::shrink(v).map(v1 => Ok(v1))
#| Err(e) => Shrink::shrink(e).map(e1 => Err(e1))
#| }
#|}
#|pub impl[X : Shrink] Shrink for Array[X] with fn shrink(xs) {
#| let view = xs[:]
#| let n = view.length()
#| fn shr_sub_terms(arr : ArrayView[X]) {
#| match arr {
#| [] => [||]
#| [x, .. xs] =>
#| X::shrink(x)
#| .map(x_ => [x_, ..xs])
#| .concat(shr_sub_terms(xs).map(xs_ => [x, ..xs_]))
#| }
#| }
#| [
#| for k = n; k > 0; k = k / 2 => k
#| ]
#| .iter()
#| .flat_map(k => removes_array(k, n, xs))
#| .concat(deferred(() => shr_sub_terms(view)))
#|}
#|pub impl[X : Shrink] Shrink for FixedArray[X] with fn shrink(xs) {
#| Shrink::shrink(xs[:].to_owned()).map(candidate => {
#| FixedArray::from_array(candidate)
#| })
#|}
#|pub impl[X : Shrink] Shrink for ReadOnlyArray[X] with fn shrink(xs) {
#| Shrink::shrink(xs[:].to_owned()).map(candidate => {
#| ReadOnlyArray::from_array(candidate)
#| })
#|}
#|pub impl[X : Shrink] Shrink for ArrayView[X] with fn shrink(xs) {
#| let candidates : Iter[Array[X]] = Shrink::shrink(xs.to_owned())
#| candidates.map(candidate => candidate)
#|}
#|pub impl[X : Shrink] Shrink for @ref.Ref[X] with fn shrink(x) {
#| Shrink::shrink(x.val).map(value => Ref(value))
#|}
#|pub impl[A : Shrink, B : Shrink] Shrink for (A, B) with fn shrink(x) {
#| let (a, b) = x
#| Shrink::shrink(a)
#| .map(a1 => (a1, b))
#| .concat(Shrink::shrink(b).map(b1 => (a, b1)))
#|}
#|pub impl[A : Shrink, B : Shrink, C : Shrink] Shrink for (A, B, C) with fn shrink(
#| x,
#|) {
#| let (a, b, c) = x
#| Shrink::shrink((a, (b, c))).map(y => {
#| let (a1, (b1, c1)) = y
#| (a1, b1, c1)
#| })
#|}
#|pub impl[A : Shrink, B : Shrink, C : Shrink, D : Shrink] Shrink for (A, B, C, D) with fn shrink(
#| x,
#|) {
#| let (a, b, c, d) = x
#| Shrink::shrink((a, (b, c, d))).map(y => {
#| let (a1, (b1, c1, d1)) = y
#| (a1, b1, c1, d1)
#| })
#|}
#|pub impl[A : Shrink, B : Shrink, C : Shrink, D : Shrink, E : Shrink] Shrink for (
#| A,
#| B,
#| C,
#| D,
#| E,
#|) with fn shrink(x) {
#| let (a, b, c, d, e) = x
#| Shrink::shrink((a, (b, c, d, e))).map(y => {
#| let (a1, (b1, c1, d1, e1)) = y
#| (a1, b1, c1, d1, e1)
#| })
#|}
#|pub impl[A : Shrink, B : Shrink, C : Shrink, D : Shrink, E : Shrink, F : Shrink] Shrink for (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#|) with fn shrink(x) {
#| let (a, b, c, d, e, f) = x
#| Shrink::shrink((a, (b, c, d, e, f))).map(y => {
#| let (a1, (b1, c1, d1, e1, f1)) = y
#| (a1, b1, c1, d1, e1, f1)
#| })
#|}
#|pub impl[
#| A : Shrink,
#| B : Shrink,
#| C : Shrink,
#| D : Shrink,
#| E : Shrink,
#| F : Shrink,
#| G : Shrink,
#|] Shrink for (A, B, C, D, E, F, G) with fn shrink(x) {
#| let (a, b, c, d, e, f, g) = x
#| Shrink::shrink((a, (b, c, d, e, f, g))).map(y => {
#| let (a1, (b1, c1, d1, e1, f1, g1)) = y
#| (a1, b1, c1, d1, e1, f1, g1)
#| })
#|}
#|pub impl[
#| A : Shrink,
#| B : Shrink,
#| C : Shrink,
#| D : Shrink,
#| E : Shrink,
#| F : Shrink,
#| G : Shrink,
#| H : Shrink,
#|] Shrink for (A, B, C, D, E, F, G, H) with fn shrink(x) {
#| let (a, b, c, d, e, f, g, h) = x
#| Shrink::shrink((a, (b, c, d, e, f, g, h))).map(y => {
#| let (a1, (b1, c1, d1, e1, f1, g1, h1)) = y
#| (a1, b1, c1, d1, e1, f1, g1, h1)
#| })
#|}
#|pub impl[
#| A : Shrink,
#| B : Shrink,
#| C : Shrink,
#| D : Shrink,
#| E : Shrink,
#| F : Shrink,
#| G : Shrink,
#| H : Shrink,
#| I : Shrink,
#|] Shrink for (A, B, C, D, E, F, G, H, I) with fn shrink(x) {
#| let (a, b, c, d, e, f, g, h, i) = x
#| Shrink::shrink((a, (b, c, d, e, f, g, h, i))).map(y => {
#| let (a1, (b1, c1, d1, e1, f1, g1, h1, i1)) = y
#| (a1, b1, c1, d1, e1, f1, g1, h1, i1)
#| })
#|}
),
"shrink.mbt": (
#|pub(open) trait Shrink {
#| fn shrink(Self) -> Iter[Self] = _
#|}
#|impl Shrink with fn shrink(_a) {
#| [||]
#|}
#|pub impl Shrink for Int with fn shrink(x) {
#| [|..[ for z = x / 2; z != 0; z = z / 2 => x - z ], ..if x != 0 { [0] }|]
#|}
#|pub impl Shrink for Int64 with fn shrink(x) {
#| [|..[ for z = x / 2; z != 0; z = z / 2 => x - z ], ..if x != 0 { [0L] }|]
#|}
#|pub impl Shrink for Int16 with fn shrink(x) {
#| Shrink::shrink(x.to_int()).map(Int16::from_int)
#|}
#|pub impl Shrink for UInt16 with fn shrink(x) {
#| Shrink::shrink(x.to_uint()).map(UInt::to_uint16)
#|}
#|pub impl Shrink for @bigint.BigInt with fn shrink(x) {
#| let zero = @bigint.BigInt::from_int(0)
#| guard x != zero else { return Iter::empty() }
#| let magnitude = if x < zero { -x } else { x }
#| let bit_length = magnitude.bit_length()
#| let negative = x < zero
#| let mut shift = bit_length - 1
#| let mut emit_zero = true
#| Iter::new(
#| () => {
#| if shift > 0 {
#| let delta = magnitude >> shift
#| shift -= 1
#| Some(if negative { x + delta } else { x - delta })
#| } else if emit_zero {
#| emit_zero = false
#| Some(zero)
#| } else {
#| None
#| }
#| },
#| size_hint=bit_length,
#| )
#|}
#|pub impl Shrink for UInt with fn shrink(x) {
#| [|..[ for z = x / 2; z > 0; z = z / 2 => x - z ], ..if x != 0 { [0U] }|]
#|}
#|pub impl Shrink for UInt64 with fn shrink(x) {
#| [|..[ for z = x / 2; z > 0; z = z / 2 => x - z ], ..if x != 0 { [0UL] }|]
#|}
#|pub impl Shrink for Bool with fn shrink(b) {
#| if !b {
#| [||]
#| } else {
#| [|false|]
#| }
#|}
#|pub impl Shrink for Byte with fn shrink(x) {
#| let xi = x.to_int()
#| [|
#| ..[
#| for z = xi / 2; z > 0; z = z / 2 => (xi - z).to_byte()
#| ],
#| ..if xi != 0 {
#| [Byte(0)]
#| },
#| |]
#|}
#|pub impl Shrink for Char with fn shrink(c) {
#| let candidates = [
#| 'a',
#| 'b',
#| 'c',
#| ..if c.is_ascii_uppercase() {
#| [c.to_ascii_lowercase()]
#| },
#| 'A',
#| 'B',
#| 'C',
#| '1',
#| '2',
#| '3',
#| ' ',
#| '\n',
#| ]
#| candidates.sort()
#| candidates.dedup()
#| let char_stamp = (c : Char) => {
#| (
#| (!c.is_ascii_lowercase(), !c.is_ascii_uppercase(), !c.is_ascii_digit()),
#| (c != ' ', !c.is_whitespace(), c),
#| )
#| }
#| let stamp = char_stamp(c)
#| candidates.iter().filter(candidate => char_stamp(candidate) < stamp)
#|}
#|pub impl Shrink for Double with fn shrink(x) {
#| shrink_decimal(x)
#|}
#|pub impl Shrink for Float with fn shrink(x) {
#| shrink_decimal(x.to_double()).map(Float::from_double).filter(y => y != x)
#|}
#|pub impl Shrink for String with fn shrink(s) {
#| Shrink::shrink(s.to_array()).map(chars => String::from_array(chars))
#|}
#|pub impl Shrink for Bytes with fn shrink(bytes) {
#| Shrink::shrink(bytes.to_array()).map(xs => Bytes::from_array(xs))
#|}
#|pub impl Shrink for Unit
),
"utils.mbt": (
#|fn[T] deferred(f : () -> Iter[T]) -> Iter[T] {
#| let cell = @lazy.Lazy(f)
#| Iter::new(fn() { cell.force().next() })
#|}
#|fn[T] removes_array(k : Int, n : Int, xs : Array[T]) -> Iter[Array[T]] {
#| guard k <= n else { [||] }
#| let mut start = 0
#| Iter::new(
#| fn() {
#| guard start + k <= n else { None }
#| let candidate = [..xs[:start], ..xs[start + k:]]
#| start += k
#| Some(candidate)
#| },
#| size_hint=(n - k) / k + 1,
#| )
#|}
#|fn[T] removes_list(k : Int, n : Int, xs : @list.List[T]) -> Iter[@list.List[T]] {
#| guard k <= n else { [||] }
#| let mut start = (n - k) / k * k
#| Iter::new(
#| fn() {
#| guard start >= 0 else { None }
#| let candidate = xs.take(start).concat(xs.drop(start + k))
#| start -= k
#| Some(candidate)
#| },
#| size_hint=(n - k) / k + 1,
#| )
#|}
#|fn shrink_decimal(x : Double) -> Iter[Double] {
#| guard !x.is_nan() else { [|0.0, 1.0, -1.0, 2.0|] }
#| guard !x.is_inf() else { [|0.0, 1.0, -1.0, 1000.0, -1000.0|] }
#| guard x >= 0.0 else { [|-x|].concat(shrink_decimal(-x).map(Double::neg)) }
#| guard x != 0.0 else { [||] }
#| [|1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0|].flat_map(p => {
#| let m = (x * p + 0.5).floor().to_int64()
#| if p != 1.0 && m % 10L == 0L {
#| return [||]
#| }
#| [|m|]
#| .concat(Shrink::shrink(m))
#| .map(n => n.to_double() / p)
#| .filter(y => y >= 0.0 && y < x)
#| })
#|}
),
},
)
///|
let moonbitlang_core_quickcheck_splitmix_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/quickcheck/splitmix",
deps={},
files={
"deprecated.mbt": (
#|#deprecated("use `@splitmix.new` instead")
#|pub fn RandomState::new(seed? : UInt64 = 37) -> RandomState {
#| new(seed~)
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend RandomState with @debug.Debug::{to_repr}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend RandomState with Default::{default}
),
"random.mbt": (
#|struct RandomState {
#| mut seed : UInt64
#| gamma : UInt64
#|} derive(@debug.Debug)
#|let golden_gamma : UInt64 = 0x9e3779b97f4a7c15
#|let double_ulp : Double = 1.0 / (1L << 53).to_double()
#|let float_ulp : Float = 1.0F / Float::from_int64(1L << 24)
#|pub fn new(seed? : UInt64 = 37) -> RandomState {
#| { seed: mix64(seed), gamma: mix_gamma(seed + golden_gamma), }
#|}
#|pub fn RandomState::clone(self : RandomState) -> RandomState {
#| { ..self, }
#|}
#|pub fn RandomState::next(self : RandomState) -> Unit {
#| self.next_uint64() |> ignore
#|}
#|fn RandomState::next_uint64_raw(self : RandomState) -> UInt64 {
#| let { seed, gamma, } = self
#| self.seed = seed + gamma
#| mix64(self.seed)
#|}
#|pub fn RandomState::next_uint64(self : RandomState, limit? : UInt64) -> UInt64 {
#| match limit {
#| None => self.next_uint64_raw()
#| Some(0UL) => abort("RandomState::next_uint64: limit must be positive")
#| Some(limit) => {
#| let mask = if limit == 1UL {
#| 0UL
#| } else {
#| 0xffff_ffff_ffff_ffffUL >> (limit - 1UL).clz()
#| }
#| for candidate = self.next_uint64_raw() & mask; candidate >= limit; {
#| continue self.next_uint64_raw() & mask
#| } nobreak {
#| candidate
#| }
#| }
#| }
#|}
#|pub fn RandomState::next_uint(self : RandomState, limit? : UInt) -> UInt {
#| match limit {
#| None => self.next_uint64_raw().to_uint()
#| Some(0U) => abort("RandomState::next_uint: limit must be positive")
#| Some(limit) => self.next_uint64(limit=limit.to_uint64()).to_uint()
#| }
#|}
#|pub fn RandomState::next_int64(self : RandomState) -> Int64 {
#| self.next_uint64().reinterpret_as_int64()
#|}
#|pub fn RandomState::next_two_uint(self : RandomState) -> (UInt, UInt) {
#| let g = self.next_uint64()
#| ((g >> 32).to_uint(), g.to_uint())
#|}
#|pub fn RandomState::next_int(self : RandomState) -> Int {
#| self.next_uint().reinterpret_as_int()
#|}
#|pub fn RandomState::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 RandomState::next_float(self : RandomState) -> Float {
#| let u = self.next_uint64()
#| Float::from_uint64(u >> 40) * float_ulp
#|}
#|pub fn RandomState::next_double(self : RandomState) -> Double {
#| let u = self.next_uint64()
#| (u >> 11).to_double() * double_ulp
#|}
#|pub fn RandomState::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
#| }
#|}
#|pub impl Default for RandomState with fn default() {
#| new()
#|}
#|test "non-zero default" {
#| let rs = (Default::default() : RandomState)
#| @test.assert_not_eq(rs.seed, 0)
#| @test.assert_not_eq(rs.gamma, 0)
#|}
),
},
)
///|
let moonbitlang_core_random_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/random",
deps={},
files={
"debug.mbt": (
#|pub impl @debug.Debug for Rand with fn to_repr(_) {
#| @debug.Repr::opaque_("Rand", @debug.Repr::omitted())
#|}
),
"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(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(seed)
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Rand with @debug.Debug::{to_repr}
),
"random.mbt": (
#|struct Rand(&Source)
#|pub(open) trait Source {
#| fn next(Self) -> UInt64
#|}
#|impl Source for @random_source.ChaCha8 with fn next(
#| self : @random_source.ChaCha8,
#|) -> UInt64 {
#| self.next_uint64()
#|}
#|pub fn Rand::chacha8(
#| seed? : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456",
#|) -> Rand {
#| if seed.length() != 32 {
#| abort("seed must be 32 bytes long")
#| }
#| Rand(@random_source.ChaCha8(seed) as &Source)
#|}
#|let fixed_test_seed : Bytes = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456"
#|pub fn Rand::new(generator? : &Source) -> Rand {
#| match generator {
#| None =>
#| match @env.rand(32) {
#| Some(seed) => Rand::chacha8(seed~)
#| None => Rand::chacha8()
#| }
#| Some(gen) => Rand(gen)
#| }
#|}
#|fn Rand::next(self : Rand) -> UInt64 {
#| let Rand(s) = self
#| s.next()
#|}
#|test "next" {
#| let r = Rand::chacha8(seed=fixed_test_seed)
#| let n = r.next()
#| let exp = 13219109469176600229UL
#| @test.assert_eq(n, exp)
#|}
#|pub fn Rand::int(self : Rand, limit? : Int = 0) -> Int {
#| if limit < 0 {
#| abort("Rand::int: invalid argument limit")
#| }
#| if limit == 0 {
#| (self.next() >> 33).to_int()
#| } else {
#| self.uint(limit=limit.reinterpret_as_uint()).reinterpret_as_int()
#| }
#|}
#|pub fn Rand::int64(self : Rand, limit? : Int64 = 0) -> Int64 {
#| if limit < 0 {
#| abort("Rand::int64: invalid argument limit")
#| }
#| 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 Rand::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 = Rand::chacha8(seed=fixed_test_seed)
#| 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 Rand::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 r = umul128(self.next(), limit)
#| if r.lo >= limit {
#| return r.hi
#| }
#| let thresh = (limit.lnot() + 1) % limit
#| for r = r; r.lo < thresh; {
#| continue umul128(self.next(), limit)
#| } nobreak {
#| r.hi
#| }
#|}
#|test "UInt64" {
#| let r = Rand::chacha8(seed=fixed_test_seed)
#| let n = r.uint64()
#| let exp = 13219109469176600229UL
#| @test.assert_eq(n, exp)
#| let r = Rand::chacha8(seed=fixed_test_seed)
#| 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 Rand::double(
#| self : Rand,
#| min? : Double = 0.0,
#| max? : Double = 1.0,
#|) -> Double {
#| if min == 0.0 && max == 1.0 {
#| Double::convert_uint64(self.next() << 11 >> 11) /
#| Double::convert_uint64(1UL << 53)
#| } else {
#| self.double_in_range(min~, max~)
#| }
#|}
#|test "double" {
#| let r = Rand::chacha8(seed=fixed_test_seed)
#| let n = r.double()
#| inspect(n, content="0.615969772029264")
#|}
#|pub fn Rand::float(
#| self : Rand,
#| min? : Float = 0.0F,
#| max? : Float = 1.0F,
#|) -> Float {
#| if min == 0.0F && max == 1.0F {
#| Float::from_uint(self.uint() << 8 >> 8) / Float::from_uint(1U << 24)
#| } else {
#| self.float_in_range(min~, max~)
#| }
#|}
#|fn double_gamma(anchor : Double) -> Double {
#| if anchor == 0.0 {
#| 1UL.reinterpret_as_double()
#| } else {
#| let toward_zero = (anchor.reinterpret_as_uint64() - 1).reinterpret_as_double()
#| (anchor - toward_zero).abs()
#| }
#|}
#|fn ceil_sections(
#| scaled_min : Double,
#| scaled_max : Double,
#| anchor_is_max~ : Bool,
#|) -> UInt64 {
#| let distance = scaled_max - scaled_min
#| let error = if anchor_is_max {
#| -scaled_min - (distance - scaled_max)
#| } else {
#| scaled_max - (distance + scaled_min)
#| }
#| let ceiling = distance.ceil()
#| let sections = ceiling.to_uint64()
#| if distance != ceiling {
#| sections
#| } else if error > 0.0 {
#| sections + error.ceil().to_uint64()
#| } else {
#| sections - (-error).floor().to_uint64()
#| }
#|}
#|fn split_uint64_for_double(value : UInt64) -> (Double, Double) {
#| (Double::convert_uint64(value >> 2), Double::convert_uint64(value & 0x3))
#|}
#|fn float_gamma(anchor : Float) -> Float {
#| if anchor == 0.0F {
#| Float::reinterpret_from_uint(1U)
#| } else {
#| let toward_zero = Float::reinterpret_from_uint(
#| anchor.reinterpret_as_uint() - 1,
#| )
#| (anchor - toward_zero).abs()
#| }
#|}
#|fn split_uint64_for_float(value : UInt64) -> (Float, Float) {
#| (Float::from_uint64(value >> 2), Float::from_uint64(value & 0x3))
#|}
#|fn Rand::double_in_range(self : Rand, min~ : Double, max~ : Double) -> Double {
#| guard !(min.is_nan() || min.is_inf() || max.is_nan() || max.is_inf()) else {
#| abort("Rand::double: bounds must be finite")
#| }
#| let underflow_threshold = 4.0 * @double.min_positive
#| guard (min == 0.0 || min.abs() >= underflow_threshold) &&
#| (max == 0.0 || max.abs() >= underflow_threshold) else {
#| abort("Rand::double: bounds must be outside the underflow region")
#| }
#| guard min < max else { abort("Rand::double: min must be less than max") }
#| let anchor_is_max = min.abs() <= max.abs()
#| let gamma = double_gamma(if anchor_is_max { max } else { min })
#| let scaled_min = min / gamma
#| let scaled_max = max / gamma
#| guard (min == 0.0 || scaled_min.abs() >= @double.min_positive) &&
#| (max == 0.0 || scaled_max.abs() >= @double.min_positive) else {
#| abort("Rand::double: scaling a bound would underflow")
#| }
#| let sections = ceil_sections(scaled_min, scaled_max, anchor_is_max~)
#| let k = self.uint64(limit=sections) + 1
#| if anchor_is_max {
#| if k == sections {
#| min
#| } else {
#| let (k_high, k_low) = split_uint64_for_double(k)
#| 4.0 * (max * 0.25 - k_high * gamma) - k_low * gamma
#| }
#| } else {
#| let (k_high, k_low) = split_uint64_for_double(k - 1)
#| 4.0 * (min * 0.25 + k_high * gamma) + k_low * gamma
#| }
#|}
#|fn Rand::float_in_range(self : Rand, min~ : Float, max~ : Float) -> Float {
#| guard !(min.is_nan() || min.is_inf() || max.is_nan() || max.is_inf()) else {
#| abort("Rand::float: bounds must be finite")
#| }
#| let underflow_threshold = 4.0F * @float.min_positive
#| guard (min == 0.0F || min.abs() >= underflow_threshold) &&
#| (max == 0.0F || max.abs() >= underflow_threshold) else {
#| abort("Rand::float: bounds must be outside the underflow region")
#| }
#| guard min < max else { abort("Rand::float: min must be less than max") }
#| let anchor_is_max = min.abs() <= max.abs()
#| let gamma = float_gamma(if anchor_is_max { max } else { min })
#| let sections = ceil_sections(
#| min.to_double() / gamma.to_double(),
#| max.to_double() / gamma.to_double(),
#| anchor_is_max~,
#| )
#| let k = self.uint64(limit=sections) + 1
#| if anchor_is_max {
#| if k == sections {
#| min
#| } else {
#| let (k_high, k_low) = split_uint64_for_float(k)
#| 4.0F * (max * 0.25F - k_high * gamma) - k_low * gamma
#| }
#| } else {
#| let (k_high, k_low) = split_uint64_for_float(k - 1)
#| 4.0F * (min * 0.25F + k_high * gamma) + k_low * gamma
#| }
#|}
#|test "ceil_sections corrects a negative Dekker residual" {
#| let min = 0xffefffffffffffffUL.reinterpret_as_double()
#| let max = 0x7fe0000000000000UL.reinterpret_as_double()
#| let gamma = double_gamma(min)
#| let sections = ceil_sections(min / gamma, max / gamma, anchor_is_max=false)
#| @test.assert_eq(sections, 0x2fffffffffffffUL)
#|}
#|pub fn Rand::boolean(self : Rand) -> Bool {
#| (self.next() & 1) == 1
#|}
#|pub fn Rand::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 = Rand::chacha8(seed=fixed_test_seed)
#| 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)
#| @test.assert_eq(r.hi, 1305938385386173474UL)
#| @test.assert_eq(r.lo, 2552847189736476416UL)
#|}
#|test "umul128: handles small numbers correctly" {
#| let r = umul128(1UL, 1UL)
#| @test.assert_eq(r.hi, 0UL)
#| @test.assert_eq(r.lo, 1UL)
#|}
#|test "umul128: handles large numbers correctly" {
#| let r = umul128(1UL, 0xFFFFFFFFFFFFFFFFUL)
#| @test.assert_eq(r.hi, 0UL)
#| @test.assert_eq(r.lo, 0xFFFFFFFFFFFFFFFFUL)
#|}
#|test "umul128: handles zero correctly" {
#| let r = umul128(0UL, 0UL)
#| @test.assert_eq(r.hi, 0UL)
#| @test.assert_eq(r.lo, 0UL)
#|}
#|pub fn Rand::shuffle(
#| self : Rand,
#| limit : Int,
#| swap : (Int, Int) -> Unit,
#|) -> Unit {
#| if limit < 0 {
#| abort("Rand::shuffle: invalid argument limit")
#| }
#| for i in limit>..1 {
#| let j = self.int(limit=i + 1)
#| swap(i, j)
#| }
#|}
#|test "shuffle" {
#| let r = Rand::chacha8(seed=fixed_test_seed)
#| 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
#| })
#| @debug.debug_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={},
files={
"random_source_chacha.mbt": (
#|struct ChaCha8 {
#| buffer : FixedArray[UInt]
#| seed : FixedArray[UInt]
#| mut i : UInt
#| mut n : UInt
#| mut counter : UInt
#|}
#|pub fn ChaCha8::ChaCha8(seed : BytesView) -> ChaCha8 {
#| if seed.length() != 32 {
#| abort("seed must be 32 bytes long")
#| }
#| let seed = FixedArray::makei(SEED_CHUNK_NUM * 2, i => {
#| match seed[i * 4:] {
#| [u32le(x), ..] => x
#| _ => abort("seed must be 32 bytes long")
#| }
#| })
#| 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_uint64(self : ChaCha8) -> UInt64 {
#| let mut i = self.i
#| if i >= self.n {
#| self.refill()
#| i = 0
#| }
#| 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()
#| (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(UInt, UInt, UInt, UInt)
#|fn chacha_block(
#| seed : FixedArray[UInt],
#| buf : FixedArray[UInt],
#| counter : UInt,
#|) -> Unit {
#| fn qr(t : Quadruple) -> Quadruple {
#| let Quadruple(a, b, c, d) = t
#| 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)
#| Quadruple(a, b, c, 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 _ in 0..<4 {
#| let Quadruple(tb1_0, tb1_1, tb1_2, tb1_3) = qr(Quadruple(b0, b4, b8, b12))
#| b0 = tb1_0
#| b4 = tb1_1
#| b8 = tb1_2
#| b12 = tb1_3
#| let Quadruple(tb2_0, tb2_1, tb2_2, tb2_3) = qr(Quadruple(b1, b5, b9, b13))
#| b1 = tb2_0
#| b5 = tb2_1
#| b9 = tb2_2
#| b13 = tb2_3
#| let Quadruple(tb3_0, tb3_1, tb3_2, tb3_3) = qr(
#| Quadruple(b2, b6, b10, b14),
#| )
#| b2 = tb3_0
#| b6 = tb3_1
#| b10 = tb3_2
#| b14 = tb3_3
#| let Quadruple(tb4_0, tb4_1, tb4_2, tb4_3) = qr(
#| Quadruple(b3, b7, b11, b15),
#| )
#| b3 = tb4_0
#| b7 = tb4_1
#| b11 = tb4_2
#| b15 = tb4_3
#| let Quadruple(tb5_0, tb5_1, tb5_2, tb5_3) = qr(
#| Quadruple(b0, b5, b10, b15),
#| )
#| b0 = tb5_0
#| b5 = tb5_1
#| b10 = tb5_2
#| b15 = tb5_3
#| let Quadruple(tb6_0, tb6_1, tb6_2, tb6_3) = qr(
#| Quadruple(b1, b6, b11, b12),
#| )
#| b1 = tb6_0
#| b6 = tb6_1
#| b11 = tb6_2
#| b12 = tb6_3
#| let Quadruple(tb7_0, tb7_1, tb7_2, tb7_3) = qr(Quadruple(b2, b7, b8, b13))
#| b2 = tb7_0
#| b7 = tb7_1
#| b8 = tb7_2
#| b13 = tb7_3
#| let Quadruple(tb8_0, tb8_1, tb8_2, tb8_3) = qr(Quadruple(b3, b4, b9, 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" {
#| @test.assert_eq(BUFFER_CHUNK_NUM.clz() + BUFFER_CHUNK_NUM.ctz(), 31)
#|}
#|fn chacha8_values_at(seed : BytesView, positions : Array[Int]) -> Array[UInt64] {
#| let s = ChaCha8(seed)
#| let values = [
#| for _ in 0..<=positions[positions.length() - 1] => s.next_uint64()
#| ]
#| [
#| for position in positions => values[position]
#| ]
#|}
#|test "boundary conformance samples" {
#| let positions = [
#| 0, 1, 31, 32, 33, 95, 96, 123, 124, 125, 247, 248, 249, 371, 372,
#| ]
#| @test.assert_eq(chacha8_values_at(Bytes::make(32, b'\x00'), positions), [
#| 12432809566553409497UL, 7766219816435805978UL, 125952780581614778UL, 11456203247299035011UL,
#| 11766211380141310478UL, 6247410371955873534UL, 3688096476295560216UL, 8184198519316962464UL,
#| 10179668788428909817UL, 5258471208527403019UL, 7420841827674394489UL, 10937539205284161074UL,
#| 7354588099337910803UL, 1988377183516050978UL, 14819101479397601098UL,
#| ])
#| @test.assert_eq(
#| chacha8_values_at(Bytes::makei(32, i => i.to_byte()), positions),
#| [
#| 12537355132343524571UL, 11147319424196738781UL, 10643391562797985389UL, 3312211745067898083UL,
#| 9018521450285820678UL, 4858190046463179352UL, 990490856749627748UL, 7053860951501379351UL,
#| 7333627332515303615UL, 13837653776835850180UL, 2865794351678725456UL, 5128231522832781158UL,
#| 5308840319225627323UL, 16534914931032675201UL, 9337503077864249277UL,
#| ],
#| )
#| @test.assert_eq(
#| chacha8_values_at(Bytes::makei(32, i => (31 - i).to_byte()), positions),
#| [
#| 13207452830590730783UL, 5009552866163029026UL, 10502404787336730197UL, 9712881148437595521UL,
#| 16401154181191732095UL, 16593913030854572746UL, 14562847379601139255UL, 7882510831935376133UL,
#| 7240113522724531080UL, 1369140773094178244UL, 12544778259996841346UL, 17662407199021422433UL,
#| 8595294092888404219UL, 3588698780051976674UL, 13209002768099367735UL,
#| ],
#| )
#|}
#|test "output" {
#| let s = ChaCha8(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ123456")
#| let res = [ for _ in 0..<372 => s.next_uint64() ]
#| 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,
#| ]
#| @test.assert_eq(res, expected)
#|}
),
},
)
///|
let moonbitlang_core_range_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/range",
deps={},
files={
"range.mbt": (
#|priv enum Direction {
#| Backward
#| Still
#| Forward
#|}
#|trait Step: Add + Compare {
#| fn direction(Self) -> Int
#| fn step_one() -> Self
#|}
#|pub impl Step for Int with fn direction(self) {
#| if self > 0 {
#| 1
#| } else if self < 0 {
#| -1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for Int with fn step_one() {
#| 1
#|}
#|pub impl Step for Int64 with fn direction(self) {
#| if self > 0L {
#| 1
#| } else if self < 0L {
#| -1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for Int64 with fn step_one() {
#| 1L
#|}
#|pub impl Step for UInt with fn direction(self) {
#| if self > 0U {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for UInt with fn step_one() {
#| 1U
#|}
#|pub impl Step for UInt64 with fn direction(self) {
#| if self > 0UL {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for UInt64 with fn step_one() {
#| 1UL
#|}
#|pub impl Step for Float with fn direction(self) {
#| if self > (0.0 : Float) {
#| 1
#| } else if self < (0.0 : Float) {
#| -1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for Float with fn step_one() {
#| (1.0 : Float)
#|}
#|pub impl Step for Double with fn direction(self) {
#| if self > 0.0 {
#| 1
#| } else if self < 0.0 {
#| -1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for Double with fn step_one() {
#| 1.0
#|}
#|pub impl Step for Int16 with fn direction(self) {
#| if self > (0 : Int16) {
#| 1
#| } else if self < (0 : Int16) {
#| -1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for Int16 with fn step_one() {
#| (1 : Int16)
#|}
#|pub impl Step for UInt16 with fn direction(self) {
#| if self > (0 : UInt16) {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for UInt16 with fn step_one() {
#| (1 : UInt16)
#|}
#|pub impl Step for Byte with fn direction(self) {
#| if self > (0 : Byte) {
#| 1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for Byte with fn step_one() {
#| (1 : Byte)
#|}
#|pub impl Step for @bigint.BigInt with fn direction(self) {
#| if self > 0N {
#| 1
#| } else if self < 0N {
#| -1
#| } else {
#| 0
#| }
#|}
#|pub impl Step for @bigint.BigInt with fn step_one() {
#| 1N
#|}
#|pub fn[T : Step] iter(
#| from~ : T,
#| to~ : T,
#| step? : T = T::step_one(),
#| inclusive? : Bool = false,
#|) -> Iter[T] {
#| let n = T::direction(step)
#| let dir : Direction = if n > 0 {
#| Forward
#| } else if n < 0 {
#| Backward
#| } else {
#| Still
#| }
#| let mut i = from
#| let mut done = false
#| Iter::new(() => {
#| guard !done else { None }
#| let in_range = match dir {
#| Forward => Compare::compare(i, to) < 0
#| Backward => Compare::compare(i, to) > 0
#| Still => false
#| }
#| guard in_range || (inclusive && i == to) else { None }
#| let value = i
#| let next = i + step
#| let progress = match dir {
#| Forward => Compare::compare(next, i) > 0
#| Backward => Compare::compare(next, i) < 0
#| Still => false
#| }
#| if progress {
#| i = next
#| } else {
#| done = true
#| }
#| Some(value)
#| })
#|}
),
},
)
///|
let moonbitlang_core_ref_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/ref",
deps={},
files={
"debug.mbt": (
#|pub impl[T : @debug.Debug] @debug.Debug for Ref[T] with fn to_repr(self) {
#| @debug.Repr::opaque_("Ref", Repr(self.val))
#|}
#|test "Debug for Ref" {
#| let r : Ref[Int] = new(1)
#| @debug.debug_inspect(r, content="")
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Ref with @debug.Debug::{to_repr}
#|#deprecated("Use `@debug.Debug` instead of `Show`", skip_current_package=true)
#|#doc(hidden)
#|pub extend Ref with Show::{output, to_string}
),
"ref.mbt": (
#|pub(all) struct Ref[T] {
#| mut val : T
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[X : Show] Show for Ref[X]
#|pub impl[X : Show] Show for Ref[X] with fn output(self, logger) {
#| logger <+
#| $|{val: \{self.val}}
#|}
#|#alias(new, deprecated)
#|#owned(x)
#|pub fn[T] Ref::Ref(x : T) -> Ref[T] {
#| { val: x, }
#|}
#|test "to_string" {
#| @debug.debug_inspect(
#| new(3),
#| content=(
#| #|
#| ),
#| )
#|}
#|#owned(x)
#|pub fn[T] new(x : T) -> Ref[T] {
#| { val: x, }
#|}
#|pub fn[T, R] Ref::map(self : Ref[T], f : (T) -> R raise?) -> Ref[R] raise? {
#| { val: f(self.val), }
#|}
#|pub fn[T, R] Ref::protect(self : Ref[T], a : T, f : () -> R raise?) -> R raise? {
#| let old = self.val
#| self.val = a
#| defer {
#| self.val = old
#| }
#| f()
#|}
#|#as_free_fn
#|pub fn[T] Ref::swap(self : Ref[T], that : Ref[T]) -> Unit {
#| let tmp = self.val
#| self.val = that.val
#| that.val = tmp
#|}
#|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] Ref::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")
#|}
),
},
)
///|
let moonbitlang_core_result_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/result",
deps={},
files={
"deprecated.mbt": (
#|#deprecated("Use `Ok(value)` instead")
#|pub fn[T, E] ok(value : T) -> Result[T, E] {
#| Ok(value)
#|}
#|#deprecated("Use `Err(value)` instead")
#|pub fn[T, E] err(value : E) -> Result[T, E] {
#| Err(value)
#|}
#|#deprecated("use `x is Ok(_)` instead")
#|pub fn[T, E] Result::is_ok(self : Result[T, E]) -> Bool {
#| self is Ok(_)
#|}
#|#deprecated("use `x is Err(_)` instead")
#|pub fn[T, E] Result::is_err(self : Result[T, E]) -> Bool {
#| self is Err(_)
#|}
#|#deprecated("use `match result { Ok(value) => ok(value); Err(error) => err(error) }` instead")
#|pub fn[T, E, V] Result::fold(
#| self : Result[T, E],
#| ok : (T) -> V,
#| err : (E) -> V,
#|) -> V {
#| match self {
#| Ok(value) => ok(value)
#| Err(error) => err(error)
#| }
#|}
),
},
)
///|
let moonbitlang_core_set_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/set",
deps={},
files={
"debug.mbt": (
#|pub impl[K : @debug.Debug] @debug.Debug for Set[K] with fn to_repr(self) {
#| @debug.Repr::opaque_(
#| "Set",
#| @debug.Repr::array(self.to_array().map(x => Repr(x))),
#| )
#|}
#|test "Debug for Set" {
#| let s : Set[Int] = from_array([1, 2, 3])
#| @debug.debug_inspect(s, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `Set([], capacity=...)` instead")
#|#as_free_fn(deprecated="Use `Set([], capacity=...)` instead")
#|pub fn[K] Set::new(capacity? : Int = default_init_capacity) -> Set[K] {
#| new_set(capacity)
#|}
),
"extends.mbt": (
#|pub extend Set with BitAnd::{land}
#|pub extend Set with BitOr::{lor}
#|pub extend Set with BitXOr::{lxor}
#|pub extend Set with Eq::{equal}
#|pub extend Set with Sub::{sub}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Set with @debug.Debug::{to_repr}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Set with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Set with Eq::{not_equal}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Set with ToJson::{to_json}
),
"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
#|}
#|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
#|}
#|let default_init_capacity = 8
#|fn[K] new_set(capacity : Int) -> 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,
#| }
#|}
#|fn capacity_for_length(length : Int) -> Int {
#| let mut capacity = length.next_power_of_two()
#| if length > calc_grow_threshold(capacity) {
#| capacity *= 2
#| }
#| capacity
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[K : Hash + Eq] Set::Set(arr : ArrayView[K], capacity? : Int) -> Set[K] {
#| let length = arr.length()
#| let capacity = match capacity {
#| Some(capacity) => capacity.max(capacity_for_length(length))
#| None =>
#| if length == 0 {
#| default_init_capacity
#| } else {
#| capacity_for_length(length)
#| }
#| }
#| let m = new_set(capacity)
#| for e in arr {
#| m.add(e)
#| }
#| m
#|}
#|#alias(insert, deprecated)
#|pub fn[K : Hash + Eq] Set::add(self : Set[K], key : K) -> Unit {
#| self.add_with_hash(key, Hash::hash(key))
#|}
#|fn[K : Eq] Set::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.unsafe_get(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)
#|}
#|#owned(entry)
#|fn[K] Set::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.unsafe_get(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
#| }
#| }
#| }
#|}
#|#owned(entry)
#|fn[K] Set::set_entry(self : Set[K], entry : Entry[K], new_idx : Int) -> Unit {
#| match entry.next {
#| None => self.tail = new_idx
#| Some(next) => next.prev = new_idx
#| }
#| self.entries.unsafe_set(new_idx, Some(entry))
#|}
#|pub fn[K : Hash + Eq] Set::add_and_check(self : Set[K], key : K) -> Bool {
#| if self.size >= self.grow_at {
#| self.grow()
#| }
#| let hash = Hash::hash(key)
#| let (idx, psl, added) = for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries.unsafe_get(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 = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(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] Set::remove(self : Set[K], key : K) -> Unit {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(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] Set::remove_and_check(self : Set[K], key : K) -> Bool {
#| let hash = Hash::hash(key)
#| for i = 0, idx = hash & self.capacity_mask {
#| guard self.entries.unsafe_get(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
#| }
#|}
#|#owned(entry)
#|fn[K] Set::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.unsafe_set(idx, Some(entry))
#| self.size += 1
#|}
#|fn[K] Set::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] Set::shift_back(self : Set[K], idx : Int) -> Unit {
#| for cur = idx {
#| let next = (cur + 1) & self.capacity_mask
#| match self.entries.unsafe_get(next) {
#| None | Some({ psl: 0, .. }) => {
#| self.entries.unsafe_set(cur, None)
#| break
#| }
#| Some(entry) => {
#| entry.psl -= 1
#| self.set_entry(entry, cur)
#| continue next
#| }
#| }
#| }
#|}
#|fn[K] Set::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
#| for x = old_head {
#| match x {
#| None => break
#| Some(e) => {
#| let next_in_chain = e.next
#| e.next = None
#| self.rehash_place_entry(e)
#| continue next_in_chain
#| }
#| }
#| }
#|}
#|#owned(outer)
#|fn[K] Set::rehash_place_entry(self : Set[K], outer : Entry[K]) -> Unit {
#| let hash = outer.hash
#| for psl = 0, idx = hash & self.capacity_mask {
#| match self.entries.unsafe_get(idx) {
#| None => {
#| outer.psl = psl
#| outer.prev = self.tail
#| self.add_entry_to_tail(idx, outer)
#| return
#| }
#| Some(curr) =>
#| if psl > curr.psl {
#| self.push_away(idx, curr)
#| outer.psl = psl
#| outer.prev = self.tail
#| self.add_entry_to_tail(idx, outer)
#| return
#| } else {
#| continue psl + 1, (idx + 1) & self.capacity_mask
#| }
#| }
#| }
#|}
#|#alias(size, deprecated)
#|pub fn[K] Set::length(self : Set[K]) -> Int {
#| self.size
#|}
#|pub fn[K] Set::capacity(self : Set[K]) -> Int {
#| self.capacity
#|}
#|pub fn[K] Set::is_empty(self : Set[K]) -> Bool {
#| self.size == 0
#|}
#|#locals(f)
#|pub fn[K] Set::each(self : Set[K], f : (K) -> Unit raise?) -> Unit raise? {
#| for x = self.head {
#| match x {
#| Some({ key, next, .. }) => {
#| f(key)
#| continue next
#| }
#| None => break
#| }
#| }
#|}
#|#locals(f)
#|pub fn[K] Set::eachi(self : Set[K], f : (Int, K) -> Unit raise?) -> Unit raise? {
#| for i = 0, curr = self.head {
#| match (i, curr) {
#| (i, Some({ key, next, .. })) => {
#| f(i, key)
#| continue i + 1, next
#| }
#| (_, None) => break
#| }
#| }
#|}
#|pub fn[K] Set::clear(self : Set[K]) -> Unit {
#| self.entries.fill(None)
#| self.size = 0
#| self.head = None
#| self.tail = -1
#|}
#|#alias(iterator, deprecated)
#|pub fn[K] Set::iter(self : Set[K]) -> Iter[K] {
#| let mut curr_entry = self.head
#| let len = self.size
#| let mut remaining = len
#| Iter::new(
#| fn() {
#| guard remaining > 0 && curr_entry is Some({ key, next, .. }) else { None }
#| curr_entry = next
#| remaining -= 1
#| Some(key)
#| },
#| size_hint=len,
#| )
#|}
#|pub fn[K] Set::to_array(self : Set[K]) -> Array[K] {
#| let arr = Array(capacity=self.size)
#| for x = self.head {
#| match x {
#| Some({ key, next, .. }) => {
#| arr.push(key)
#| continue next
#| }
#| None => break
#| }
#| }
#| arr
#|}
#|pub impl[K : Hash + Eq] Eq for Set[K] with fn equal(self, other) {
#| guard self.size == other.size else { return false }
#| for k in self {
#| guard other.contains(k) else { return false }
#| } nobreak {
#| true
#| }
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[K : Hash + Eq] Set::from_iter(iter : Iter[K]) -> Set[K] {
#| let m = new_set(default_init_capacity)
#| while iter.next() is Some(e) {
#| m.add(e)
#| }
#| m
#|}
#|pub impl[K] Default for Set[K] with fn default() {
#| new_set(default_init_capacity)
#|}
#|#alias(clone, deprecated)
#|pub fn[K] Set::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)
#| for entry = last, idx = self.tail, next = (None : Entry[K]?) {
#| match (entry, idx, next) {
#| ({ 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)
#| break
#| }
#| }
#| }
#| }
#| other
#|}
#|pub fn[K : Hash + Eq] Set::difference(self : Set[K], other : Set[K]) -> Set[K] {
#| let m = new_set(default_init_capacity)
#| self.each(k => if !other.contains(k) { m.add(k) })
#| m
#|}
#|pub fn[K : Hash + Eq] Set::symmetric_difference(
#| self : Set[K],
#| other : Set[K],
#|) -> Set[K] {
#| let m = new_set(default_init_capacity)
#| 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] Set::union(self : Set[K], other : Set[K]) -> Set[K] {
#| let m = new_set(default_init_capacity)
#| self.each(k => m.add(k))
#| other.each(k => m.add(k))
#| m
#|}
#|pub fn[K : Hash + Eq] Set::intersection(
#| self : Set[K],
#| other : Set[K],
#|) -> Set[K] {
#| let m = new_set(default_init_capacity)
#| self.each(k => if other.contains(k) { m.add(k) })
#| m
#|}
#|pub impl[X : ToJson] ToJson for Set[X] with fn to_json(self) {
#| let res = Array(capacity=self.size)
#| for v in self {
#| res.push(v.to_json())
#| }
#| Json::array(res)
#|}
#|pub fn[K : Hash + Eq] Set::is_disjoint(self : Set[K], other : Set[K]) -> Bool {
#| if self.length() <= other.length() {
#| 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] Set::is_subset(self : Set[K], other : Set[K]) -> Bool {
#| if self.length() <= other.length() {
#| for k in self {
#| if !other.contains(k) {
#| return false
#| }
#| }
#| true
#| } else {
#| false
#| }
#|}
#|pub fn[K : Hash + Eq] Set::is_superset(self : Set[K], other : Set[K]) -> Bool {
#| other.is_subset(self)
#|}
#|pub impl[K : Hash + Eq] BitAnd for Set[K] with fn land(self, other) {
#| self.intersection(other)
#|}
#|pub impl[K : Hash + Eq] BitOr for Set[K] with fn lor(self, other) {
#| self.union(other)
#|}
#|pub impl[K : Hash + Eq] BitXOr for Set[K] with fn lxor(self, other) {
#| self.symmetric_difference(other)
#|}
#|pub impl[K : Hash + Eq] Sub for Set[K] with fn sub(self, other) {
#| self.difference(other)
#|}
),
},
)
///|
let moonbitlang_core_sorted_map_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/sorted_map",
deps={},
files={
"debug.mbt": (
#|pub impl[K : @debug.Debug, V : @debug.Debug] @debug.Debug for SortedMap[K, V] with fn to_repr(
#| self,
#|) {
#| @debug.Repr::opaque_(
#| "SortedMap",
#| @debug.Repr::map([ for k, v in self => (Repr(k), Repr(v)) ]),
#| )
#|}
#|test "Debug for SortedMap" {
#| let sm : SortedMap[Int, String] = from_array([(1, "a"), (2, "b")])
#| @debug.debug_inspect(
#| sm,
#| content=(
#| #|
#| ),
#| )
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `SortedMap([])` instead")
#|#as_free_fn(deprecated="Use `SortedMap([])` instead")
#|pub fn[K, V] SortedMap::new() -> SortedMap[K, V] {
#| new_sorted_map()
#|}
),
"extends.mbt": (
#|pub extend SortedMap with Eq::{equal}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedMap with @debug.Debug::{to_repr}
#|#deprecated("Use `@json.from_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedMap with @json.FromJson::{from_json}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedMap with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedMap with Eq::{not_equal}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedMap with Show::{output, to_string}
#|#deprecated("Use `@json.to_json` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedMap with ToJson::{to_json}
),
"map.mbt": (
#|pub impl[K : Eq, V : Eq] Eq for SortedMap[K, V] with fn equal(self, other) {
#| guard self.size == other.size else { return false }
#| let iter = self.iter()
#| let iter1 = other.iter()
#| while iter.next() is Some(a) && iter1.next() is Some(b) {
#| guard a == b else { break false }
#| } nobreak {
#| true
#| }
#|}
#|fn[K, V] new_sorted_map() -> SortedMap[K, V] {
#| { root: None, size: 0, }
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[K : Compare, V] SortedMap::SortedMap(
#| entries : ArrayView[(K, V)],
#|) -> SortedMap[K, V] {
#| let map = new_sorted_map()
#| for e in entries {
#| map.set(e.0, e.1)
#| }
#| map
#|}
#|#alias("_[_]=_")
#|#alias(add, deprecated="Use set instead")
#|#owned(value)
#|pub fn[K : Compare, V] SortedMap::set(
#| 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] SortedMap::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] SortedMap::get(self : SortedMap[K, V], key : K) -> V? {
#| for x = self.root {
#| match x {
#| 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
#| }
#| }
#|}
#|#alias("_[_]")
#|pub fn[K : Compare, V] SortedMap::at(self : SortedMap[K, V], key : K) -> V {
#| for x = self.root {
#| match x {
#| 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] SortedMap::get_or_init(
#| self : SortedMap[K, V],
#| key : K,
#| init : () -> V,
#|) -> V {
#| match self.get(key) {
#| Some(v) => v
#| None => {
#| let v = init()
#| self.set(key, v)
#| v
#| }
#| }
#|}
#|pub fn[K : Compare, V] SortedMap::update_or_default(
#| self : SortedMap[K, V],
#| key : K,
#| default : V,
#| f : (V) -> V,
#|) -> Unit {
#| let (new_root, inserted) = update_or_default_node(self.root, key, default, f)
#| if self.root != new_root {
#| self.root = new_root
#| }
#| if inserted {
#| self.size += 1
#| }
#|}
#|pub fn[K : Compare, V] SortedMap::get_or_default(
#| self : SortedMap[K, V],
#| key : K,
#| default : V,
#|) -> V {
#| match self.get(key) {
#| Some(v) | (None with v = default) => v
#| }
#|}
#|pub fn[K : Compare, V] SortedMap::contains(
#| self : SortedMap[K, V],
#| key : K,
#|) -> Bool {
#| self.get(key) is Some(_)
#|}
#|pub fn[K, V] SortedMap::is_empty(self : SortedMap[K, V]) -> Bool {
#| self.size == 0
#|}
#|#alias(size, deprecated)
#|pub fn[K, V] SortedMap::length(self : SortedMap[K, V]) -> Int {
#| self.size
#|}
#|pub fn[K, V] SortedMap::clear(self : SortedMap[K, V]) -> Unit {
#| self.root = None
#| self.size = 0
#|}
#|pub fn[K, V] SortedMap::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] SortedMap::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 += 1
#| })
#|}
#|#alias(keys_as_iter, deprecated)
#|pub fn[K, V] SortedMap::keys(self : SortedMap[K, V]) -> Iter[K] {
#| let todo_list = []
#| let mut next_node = self.root
#| Iter::new(
#| fn() {
#| for x = next_node {
#| match x {
#| Some({ left, key, value: _, right, height: _, }) => {
#| todo_list.push((key, right))
#| continue left
#| }
#| None if todo_list.pop() is Some((key, right)) => {
#| next_node = right
#| break Some(key)
#| }
#| None => break None
#| }
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|#alias(values_as_iter, deprecated)
#|pub fn[K, V] SortedMap::values(self : SortedMap[K, V]) -> Iter[V] {
#| let todo_list = []
#| let mut next_node = self.root
#| Iter::new(
#| fn() {
#| for x = next_node {
#| match x {
#| Some({ left, key: _, value, right, height: _, }) => {
#| todo_list.push((value, right))
#| continue left
#| }
#| None if todo_list.pop() is Some((value, right)) => {
#| next_node = right
#| break Some(value)
#| }
#| None => break None
#| }
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|pub fn[K, V] SortedMap::to_array(self : SortedMap[K, V]) -> Array[(K, V)] {
#| [
#| for k, v in self => (k, v)
#| ]
#|}
#|#alias(iterator, deprecated)
#|pub fn[K, V] SortedMap::iter(self : SortedMap[K, V]) -> Iter[(K, V)] {
#| let todo_list = []
#| let mut next_node = self.root
#| Iter::new(
#| fn() {
#| for x = next_node {
#| match x {
#| Some({ left, key, value, right, height: _, }) => {
#| todo_list.push((key, value, right))
#| continue left
#| }
#| None if todo_list.pop() is Some((key, value, right)) => {
#| next_node = right
#| break Some((key, value))
#| }
#| None => break None
#| }
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|#alias(iterator2, deprecated)
#|pub fn[K, V] SortedMap::iter2(self : SortedMap[K, V]) -> Iter2[K, V] {
#| self.iter()
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[K : Compare, V] SortedMap::from_iter(
#| iter : Iter[(K, V)],
#|) -> SortedMap[K, V] {
#| let m = new_sorted_map()
#| while iter.next() is Some((k, v)) {
#| m[k] = v
#| }
#| m
#|}
#|pub fn[K : Compare, V] SortedMap::range(
#| self : SortedMap[K, V],
#| low : K,
#| high : K,
#|) -> Iter2[K, V] {
#| let todo_list = []
#| let mut next_node = self.root
#| Iter2::new(fn() {
#| for x = next_node {
#| match x {
#| Some({ left, key, value, right, height: _, }) => {
#| let cmp_key_low = key.compare(low)
#| let cmp_key_high = key.compare(high)
#| if cmp_key_low < 0 {
#| continue right
#| } else if cmp_key_high > 0 {
#| continue left
#| } else if left is None {
#| next_node = right
#| break Some((key, value))
#| } else {
#| todo_list.push((key, value, right))
#| continue left
#| }
#| }
#| None if todo_list.pop() is Some((key, value, right)) => {
#| next_node = right
#| break Some((key, value))
#| }
#| None => break None
#| }
#| }
#| }).iter2()
#|}
#|#alias(clone, deprecated)
#|pub fn[K, V] SortedMap::copy(self : SortedMap[K, V]) -> SortedMap[K, V] {
#| fn copy_node(node : Node[K, V]?) -> Node[K, V]? {
#| match node {
#| None => None
#| Some({ key, value, left, right, height, }) =>
#| Some({
#| key,
#| value,
#| left: copy_node(left),
#| right: copy_node(right),
#| height,
#| })
#| }
#| }
#| { root: copy_node(self.root), size: self.size, }
#|}
#|pub fn[K : Compare, V] SortedMap::merge(
#| self : SortedMap[K, V],
#| other : SortedMap[K, V],
#|) -> SortedMap[K, V] {
#| let result = self.copy()
#| other.each((k, v) => result.set(k, v))
#| result
#|}
#|pub fn[K : Compare, V] SortedMap::merge_in_place(
#| self : SortedMap[K, V],
#| other : SortedMap[K, V],
#|) -> Unit {
#| other.each((k, v) => self.set(k, v))
#|}
#|fn[K, 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] Node::update_height(self : Node[K, V]) -> Unit {
#| self.height = 1 + height(self.left).max(height(self.right))
#|}
#|fn[K, V] height_ge(x1 : Node[K, V]?, x2 : Node[K, V]?) -> Bool {
#| match (x1, x2) {
#| (
#| Some({ height: h1, .. })
#| | (None with h1 = 0),
#| Some({ height: h2, .. })
#| | (None with h2 = 0),
#| ) => h1 >= h2
#| }
#|}
#|#owned(root)
#|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
#|}
#|#owned(n)
#|fn[K, V] rotate_l(n : Node[K, V]) -> Node[K, V] {
#| let r = n.right.unwrap()
#| n.right = r.left
#| n.update_height()
#| r.left = Some(n)
#| r.update_height()
#| r
#|}
#|#owned(n)
#|fn[K, V] rotate_r(n : Node[K, V]) -> Node[K, V] {
#| let l = n.left.unwrap()
#| n.left = l.right
#| n.update_height()
#| l.right = Some(n)
#| l.update_height()
#| l
#|}
#|#owned(n)
#|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)
#|}
#|#owned(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)
#|}
#|#owned(value)
#|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] update_or_default_node(
#| root : Node[K, V]?,
#| key : K,
#| default : V,
#| f : (V) -> V,
#|) -> (Node[K, V]?, Bool) {
#| match root {
#| None => (Some(new_node(key, default)), true)
#| Some(n) =>
#| if key == n.key {
#| n.value = f(n.value)
#| (Some(n), false)
#| } else {
#| let (l, r) = (n.left, n.right)
#| if key < n.key {
#| let (nl, inserted) = update_or_default_node(l, key, default, f)
#| n.left = nl
#| (Some(balance(n)), inserted)
#| } else {
#| let (nr, inserted) = update_or_default_node(r, key, default, f)
#| 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_sorted_map()
#| inspect(map.debug_tree(), content="_")
#| inspect(map.length(), 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.length(), content="3")
#|}
#|test "add1" {
#| let map = new_sorted_map()
#| map.set(6, "a")
#| map.set(5, "b")
#| map.set(4, "c")
#| map.set(3, "d")
#| map.set(2, "e")
#| map.set(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.length(), content="6")
#|}
#|test "add2" {
#| let map = new_sorted_map()
#| map.set(1, "a")
#| map.set(2, "b")
#| map.set(3, "c")
#| map.set(4, "d")
#| map.set(5, "e")
#| map.set(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.length(), content="6")
#|}
#|test "add3" {
#| let map = new_sorted_map()
#| map.set(4, "a")
#| map.set(1, "b")
#| map.set(3, "c")
#| map.set(2, "d")
#| inspect(
#| map.debug_tree(),
#| content="([3]3,c,([2]1,b,_,([1]2,d,_,_)),([1]4,a,_,_))",
#| )
#|}
#|test "add4" {
#| let map = new_sorted_map()
#| map.set(1, "a")
#| map.set(4, "b")
#| map.set(2, "c")
#| map.set(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.set(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.length(), 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.length(), 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.length(), 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.length(), content="5")
#| map.remove(3)
#| inspect(
#| map.debug_tree(),
#| content="([3]5,e,([1]1,a,_,_),([2]7,g,_,([1]8,h,_,_)))",
#| )
#| inspect(map.length(), content="4")
#| map.remove(5)
#| inspect(map.debug_tree(), content="([2]7,g,([1]1,a,_,_),([1]8,h,_,_))")
#| inspect(map.length(), content="3")
#| map.remove(7)
#| inspect(map.debug_tree(), content="([2]8,h,([1]1,a,_,_),_)")
#| inspect(map.length(), content="2")
#| map.remove(8)
#| inspect(map.debug_tree(), content="([1]1,a,_,_)")
#| inspect(map.length(), content="1")
#| map.remove(1)
#| inspect(map.debug_tree(), content="_")
#| inspect(map.size, content="0")
#|}
#|test "_[_]=_" {
#| let map = new_sorted_map()
#| 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.length(), content="0")
#|}
#|test "copy" {
#| let map1 = from_array([
#| (1, "a"),
#| (2, "b"),
#| (3, "c"),
#| (4, "d"),
#| (5, "e"),
#| (6, "f"),
#| ])
#| let map2 = map1.copy()
#| inspect(map1.debug_tree(), content=map2.debug_tree())
#| inspect(map1.length(), content="6")
#| inspect(map2.length(), content="6")
#| map2.set(7, "g")
#| inspect(map1.length(), content="6")
#| inspect(map2.length(), content="7")
#| @debug.debug_inspect(map1.get(7), content="None")
#| @debug.debug_inspect(map2.get(7), content="Some(\"g\")")
#| map1.remove(1)
#| inspect(map1.length(), content="5")
#| inspect(map2.length(), content="7")
#| @debug.debug_inspect(map1.get(1), content="None")
#| @debug.debug_inspect(map2.get(1), content="Some(\"a\")")
#|}
#|pub impl[K, V] Default for SortedMap[K, V] with fn default() {
#| new_sorted_map()
#|}
),
"types.mbt": (
#|#unsafe_cycle_free
#|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
#|}
),
"utils.mbt": (
#|#owned(key, value)
#|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 fn equal(self, other) {
#| self.key == other.key
#|}
#|fn[K, V] height(node : Node[K, V]?) -> Int {
#| match node {
#| Some({ height, .. }) | (None with height = 0) => height
#| }
#|}
#|fn[K : Show, V : Show] Node::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] SortedMap::debug_tree(self : SortedMap[K, V]) -> String {
#| match self.root {
#| Some(root) => root.debug_node()
#| None => "_"
#| }
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[K : Show, V : Show] Show for SortedMap[K, V]
#|#warnings("-deprecated")
#|pub impl[K : Show, V : Show] Show for SortedMap[K, V] with fn output(
#| self,
#| logger,
#|) {
#| logger.write_iter(self.iter(), prefix="@sorted_map.from_array([", suffix="])")
#|}
#|pub impl[K : Show, V : ToJson] ToJson for SortedMap[K, V] with fn to_json(self) {
#| Json::object(
#| Map(
#| capacity=self.length(),
#| [
#| for k, v in self => (k.to_string(), v.to_json())
#| ],
#| ),
#| )
#|}
#|pub impl[V : @json.FromJson] @json.FromJson for SortedMap[String, V] with fn from_json(
#| json,
#| path,
#|) {
#| guard json is Object(obj) else {
#| raise JsonDecodeError((path, "@sorted_map.from_json: expected object"))
#| }
#| let map = new_sorted_map()
#| for k, v in obj {
#| map.set(k, V::from_json(v, path.add_key(k)))
#| }
#| map
#|}
),
},
)
///|
let moonbitlang_core_sorted_set_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/sorted_set",
deps={},
files={
"debug.mbt": (
#|pub impl[V : @debug.Debug] @debug.Debug for SortedSet[V] with fn to_repr(self) {
#| @debug.Repr::opaque_(
#| "SortedSet",
#| @debug.Repr::array([ for x in self => Repr(x) ]),
#| )
#|}
#|test "Debug for SortedSet" {
#| let ss : SortedSet[Int] = from_array([3, 1, 2])
#| @debug.debug_inspect(ss, content="")
#|}
),
"deprecated.mbt": (
#|#deprecated("Use `SortedSet([])` instead")
#|#as_free_fn(deprecated="Use `SortedSet([])` instead")
#|pub fn[V] SortedSet::new() -> SortedSet[V] {
#| new_sorted_set()
#|}
),
"extends.mbt": (
#|pub extend SortedSet with Eq::{equal}
#|#deprecated("Use the `@debug.Debug` trait instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedSet with @debug.Debug::{to_repr}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedSet with Default::{default}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedSet with Eq::{not_equal}
#|#deprecated("Use `@debug.Debug` instead of `Show` for collections", skip_current_package=true)
#|#doc(hidden)
#|pub extend SortedSet with Show::{output, to_string}
),
"set.mbt": (
#|fn[V] new_sorted_set() -> SortedSet[V] {
#| { root: None, size: 0, }
#|}
#|#as_free_fn
#|#owned(value)
#|pub fn[V] SortedSet::singleton(value : V) -> SortedSet[V] {
#| { root: Some({ value, left: None, right: None, height: 1, }), size: 1, }
#|}
#|#alias(from_array)
#|#as_free_fn(from_array)
#|#alias(of, deprecated="Use from_array instead")
#|#as_free_fn(of, deprecated="Use from_array instead")
#|pub fn[V : Compare] SortedSet::SortedSet(array : ArrayView[V]) -> SortedSet[V] {
#| let set = new_sorted_set()
#| for x in array {
#| set.add(x)
#| }
#| set
#|}
#|#alias(deep_clone, deprecated)
#|#alias(clone, deprecated)
#|pub fn[V] SortedSet::copy(self : SortedSet[V]) -> SortedSet[V] {
#| match self.root {
#| None => new_sorted_set()
#| 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)
#| }
#| }
#|}
#|#owned(value, left, right)
#|fn[V] new_node(
#| value : V,
#| left? : Node[V]? = None,
#| right? : Node[V]? = None,
#| height? : Int = 1,
#|) -> Node[V] {
#| { value, left, right, height, }
#|}
#|#owned(value, left, right)
#|fn[V] new_node_update_height(
#| value : V,
#| left~ : Node[V]?,
#| right~ : Node[V]?,
#|) -> Node[V] {
#| { value, left, right, height: height(left).max(height(right)) + 1, }
#|}
#|#owned(value)
#|pub fn[V : Compare] SortedSet::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] SortedSet::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] SortedSet::contains(self : SortedSet[V], value : V) -> Bool {
#| for root = self.root, value = value {
#| match (root, value) {
#| (None, _) => break false
#| (Some(node), value) => {
#| let compare_result = value.compare(node.value)
#| if compare_result == 0 {
#| break true
#| } else if compare_result < 0 {
#| continue node.left, value
#| } else {
#| continue node.right, value
#| }
#| }
#| }
#| }
#|}
#|fn[V : Compare] lookup(root : Node[V]?, value : V) -> V? {
#| for node = root {
#| match node {
#| None => break None
#| Some(n) => {
#| let compare_result = value.compare(n.value)
#| if compare_result == 0 {
#| break Some(n.value)
#| } else if compare_result < 0 {
#| continue n.left
#| } else {
#| continue n.right
#| }
#| }
#| }
#| }
#|}
#|pub fn[V : Compare] SortedSet::union(
#| self : SortedSet[V],
#| src : SortedSet[V],
#|) -> SortedSet[V] {
#| let mut dups = 0
#| 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 { left: l, found, right: r, } = split_member(b, va)
#| if found {
#| dups += 1
#| }
#| Some(join(aux(la, l), va, aux(ra, r)))
#| }
#| (None, None) => None
#| }
#| }
#| match (self.root, src.root) {
#| (Some(_), Some(_)) => {
#| let t = aux(copy_tree(self.root), copy_tree(src.root))
#| { root: t, size: self.size + src.size - dups, }
#| }
#| (Some(_), None) => { root: copy_tree(self.root), size: self.size, }
#| (None, Some(_)) => { root: copy_tree(src.root), size: src.size, }
#| (None, None) => new_sorted_set()
#| }
#|}
#|#valtype
#|priv struct SplitResult[V] {
#| left : Node[V]?
#| found : Bool
#| right : Node[V]?
#|}
#|fn[V : Compare] split_member(root : Node[V]?, value : V) -> SplitResult[V] {
#| match root {
#| None => { left: None, found: false, right: None, }
#| Some(node) => {
#| let comp = value.compare(node.value)
#| if comp == 0 {
#| { left: node.left, found: true, right: node.right, }
#| } else if comp < 0 {
#| let { left, found, right, } = split_member(node.left, value)
#| { left, found, right: Some(join(right, node.value, node.right)), }
#| } else {
#| let { left, found, right, } = split_member(node.right, value)
#| { left: Some(join(node.left, node.value, left)), found, right, }
#| }
#| }
#| }
#|}
#|fn[V] concat(left : Node[V]?, right : Node[V]?) -> Node[V]? {
#| match (left, right) {
#| (None, _) => right
#| (_, None) => left
#| (Some(_), Some(r)) => {
#| let (min_val, rest) = remove_min(r)
#| Some(join(left, min_val, rest))
#| }
#| }
#|}
#|fn[V] remove_min(node : Node[V]) -> (V, Node[V]?) {
#| match node.left {
#| None => (node.value, node.right)
#| Some(left) => {
#| let (min_val, new_left) = remove_min(left)
#| (min_val, Some(join(new_left, node.value, node.right)))
#| }
#| }
#|}
#|#owned(left, value, right)
#|fn[V] 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~)
#| }
#|}
#|#owned(l, v)
#|fn[V] 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
#|}
#|#owned(v, r)
#|fn[V] 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
#|}
#|#alias(diff, deprecated)
#|pub fn[V : Compare] SortedSet::difference(
#| self : SortedSet[V],
#| src : SortedSet[V],
#|) -> SortedSet[V] {
#| match (self.root, src.root) {
#| (None, _) => new_sorted_set()
#| (_, None) => { root: copy_tree(self.root), size: self.size, }
#| (Some(_), Some(_)) => {
#| if self.size < src.size / 16 {
#| let ret = new_sorted_set()
#| self.each(x => if !src.contains(x) { ret.add(x) })
#| return ret
#| }
#| let mut found_count = 0
#| fn aux(a : Node[V]?, b : Node[V]?) -> Node[V]? {
#| match (a, b) {
#| (None, _) => None
#| (_, None) => a
#| (Some({ value: va, left: la, right: ra, .. }), _) => {
#| let { left: lb, found, right: rb, } = split_member(b, va)
#| if found {
#| found_count += 1
#| concat(aux(la, lb), aux(ra, rb))
#| } else {
#| Some(join(aux(la, lb), va, aux(ra, rb)))
#| }
#| }
#| }
#| }
#| let t = aux(copy_tree(self.root), copy_tree(src.root))
#| { root: t, size: self.size - found_count, }
#| }
#| }
#|}
#|pub fn[V : Compare] SortedSet::symmetric_difference(
#| self : SortedSet[V],
#| other : SortedSet[V],
#|) -> SortedSet[V] {
#| let mut found_count = 0
#| fn aux(a : Node[V]?, b : Node[V]?) -> Node[V]? {
#| match (a, b) {
#| (None, _) => b
#| (_, None) => a
#| (Some({ value: va, left: la, right: ra, .. }), _) => {
#| let { left: lb, found, right: rb, } = split_member(b, va)
#| if found {
#| found_count += 1
#| concat(aux(la, lb), aux(ra, rb))
#| } else {
#| Some(join(aux(la, lb), va, aux(ra, rb)))
#| }
#| }
#| }
#| }
#| let t = aux(copy_tree(self.root), copy_tree(other.root))
#| { root: t, size: self.size + other.size - 2 * found_count, }
#|}
#|#alias(intersect, deprecated)
#|pub fn[V : Compare] SortedSet::intersection(
#| self : SortedSet[V],
#| src : SortedSet[V],
#|) -> SortedSet[V] {
#| match (self.root, src.root) {
#| (None, _) | (_, None) => new_sorted_set()
#| (Some(_), Some(_)) => {
#| if self.size < src.size / 16 {
#| let ret = new_sorted_set()
#| self.each(x => if src.contains(x) { ret.add(x) })
#| return ret
#| }
#| if src.size < self.size / 16 {
#| let ret = new_sorted_set()
#| src.each(x => if lookup(self.root, x) is Some(v) { ret.add(v) })
#| return ret
#| }
#| let mut found_count = 0
#| fn aux(a : Node[V]?, b : Node[V]?) -> Node[V]? {
#| match (a, b) {
#| (None, _) | (_, None) => None
#| (Some({ value: va, left: la, right: ra, .. }), _) => {
#| let { left: lb, found, right: rb, } = split_member(b, va)
#| if found {
#| found_count += 1
#| Some(join(aux(la, lb), va, aux(ra, rb)))
#| } else {
#| concat(aux(la, lb), aux(ra, rb))
#| }
#| }
#| }
#| }
#| let t = aux(copy_tree(self.root), copy_tree(src.root))
#| { root: t, size: found_count, }
#| }
#| }
#|}
#|pub fn[V : Compare] SortedSet::subset(
#| self : SortedSet[V],
#| src : SortedSet[V],
#|) -> Bool {
#| self.iter().all(x => src.contains(x))
#|}
#|pub fn[V : Compare] SortedSet::disjoint(
#| self : SortedSet[V],
#| src : SortedSet[V],
#|) -> Bool {
#| self.iter().all(x => !src.contains(x))
#|}
#|pub impl[V : Eq] Eq for SortedSet[V] with fn equal(self, other) {
#| guard self.size == other.size else { return false }
#| let iter = self.iter()
#| let iter1 = other.iter()
#| while iter.next() is Some(a) && iter1.next() is Some(b) {
#| guard a == b else { break false }
#| } nobreak {
#| true
#| }
#|}
#|pub fn[V] SortedSet::is_empty(self : SortedSet[V]) -> Bool {
#| self.root is None
#|}
#|#alias(size, deprecated)
#|pub fn[V] SortedSet::length(self : SortedSet[V]) -> Int {
#| self.size
#|}
#|pub fn[V] SortedSet::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] SortedSet::eachi(
#| self : SortedSet[V],
#| f : (Int, V) -> Unit raise?,
#|) -> Unit raise? {
#| let mut i = 0
#| self.each(v => {
#| f(i, v)
#| i += 1
#| })
#|}
#|pub fn[V] SortedSet::to_array(self : SortedSet[V]) -> Array[V] {
#| if self.size == 0 {
#| return []
#| }
#| let arr = Array::unsafe_make_uninit(self.size)
#| let mut n = 0
#| fn dfs(root : Node[V]?) -> Unit {
#| if root is Some(root) {
#| dfs(root.left)
#| let v = root.value
#| arr.unsafe_set(n, v)
#| n += 1
#| dfs(root.right)
#| }
#| }
#| dfs(self.root)
#| arr
#|}
#|#alias(iterator, deprecated)
#|pub fn[V] SortedSet::iter(self : SortedSet[V]) -> Iter[V] {
#| let mut curr_node = self.root
#| let parents = []
#| Iter::new(
#| fn() {
#| for x = curr_node {
#| match x {
#| Some({ left: None, value, right, height: _, }) => {
#| curr_node = right
#| break Some(value)
#| }
#| Some({ left, value, right, height: _, }) => {
#| parents.push((value, right))
#| continue left
#| }
#| None if parents.pop() is Some((value, right)) => {
#| curr_node = right
#| break Some(value)
#| }
#| None => break None
#| }
#| }
#| },
#| size_hint=self.size,
#| )
#|}
#|#as_free_fn
#|#alias(from_iterator, deprecated)
#|#as_free_fn(from_iterator, deprecated)
#|pub fn[V : Compare] SortedSet::from_iter(iter : Iter[V]) -> SortedSet[V] {
#| let s = new_sorted_set()
#| while iter.next() is Some(e) {
#| s.add(e)
#| }
#| s
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|pub impl[V : Show] Show for SortedSet[V]
#|pub impl[V : Show] Show for SortedSet[V] with fn output(self, logger) {
#| logger.write_iter(self.iter(), prefix="@sorted_set.from_array([", suffix="])")
#|}
#|#deprecated("Use @debug.Debug instead of Show for debugging purposes. See https://github.com/moonbitlang/core/blob/main/debug/README.mbt.md")
#|impl[T : Show] Show for Node[T]
#|impl[T : Show] Show for Node[T] with fn output(self, logger) {
#| fn count(root : Node[T]?) -> Int {
#| match root {
#| None => 0
#| Some(root) => count(root.left) + count(root.right) + 1
#| }
#| }
#| let x = { root: Some(self), size: count(Some(self)), }
#| logger.write_iter(x.iter())
#|}
#|pub fn[V : Compare] SortedSet::range(
#| self : SortedSet[V],
#| low : V,
#| high : V,
#|) -> Iter[V] {
#| let mut curr_node = self.root
#| let parents = []
#| let iter = Iter::new(() => {
#| for x = curr_node {
#| match x {
#| Some({ value, left, right, height: _, }) => {
#| let cmp_key_low = value.compare(low)
#| let cmp_key_high = value.compare(high)
#| if cmp_key_low < 0 {
#| continue right
#| } else if cmp_key_high > 0 {
#| continue left
#| } else if left is None {
#| curr_node = right
#| break Some(value)
#| } else {
#| parents.push((value, right))
#| continue left
#| }
#| }
#| None if parents.pop() is Some((value, right)) => {
#| curr_node = right
#| break Some(value)
#| }
#| None => break None
#| }
#| }
#| })
#| iter.iter()
#|}
#|fn[V] 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] Node::update_height(self : Node[V]) -> Unit {
#| self.height = 1 + height(self.left).max(height(self.right))
#|}
#|fn[V] height_ge(x1 : Node[V]?, x2 : Node[V]?) -> Bool {
#| match (x1, x2) {
#| (
#| Some({ height: h1, .. })
#| | (None with h1 = 0),
#| Some({ height: h2, .. })
#| | (None with h2 = 0),
#| ) => h1 >= h2
#| }
#|}
#|#owned(root)
#|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
#|}
#|#owned(n)
#|fn[V] rotate_l(n : Node[V]) -> Node[V] {
#| let r = n.right.unwrap()
#| n.right = r.left
#| n.update_height()
#| r.left = Some(n)
#| r.update_height()
#| r
#|}
#|#owned(n)
#|fn[V] rotate_r(n : Node[V]) -> Node[V] {
#| let l = n.left.unwrap()
#| n.left = l.right
#| n.update_height()
#| l.right = Some(n)
#| l.update_height()
#| l
#|}
#|#owned(n)
#|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)
#|}
#|#owned(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)
#|}
#|#owned(value)
#|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()
#| @debug.debug_inspect(
#| copied_set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree() == copied_set.debug_tree(), content="true")
#| let set : SortedSet[Int] = from_array([])
#| let copied_set = set.copy()
#| @debug.debug_inspect(
#| copied_set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| inspect(set3.debug_tree(), content="([2]2,([1]1,_,_),([1]3,_,_))")
#| let set1 : SortedSet[Int] = new_sorted_set()
#| let set2 = new_sorted_set()
#| let set3 = set1.union(set2)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| inspect(set3.debug_tree(), content="_")
#| let set1 = from_array([1, 2, 3])
#| let set2 = from_array([])
#| let set3 = set1.union(set2)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set3,
#| content=(
#| #|
#| ),
#| )
#| 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,_,_))))",
#| )
#|}
#|#warnings("-deprecated")
#|test "split_member" {
#| let { left: l, found, right: r, } = split_member(
#| from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root,
#| 5,
#| )
#| inspect(found, content="true")
#| inspect(l, content="Some([1, 2, 3, 4])")
#| inspect(r, content="Some([6, 7, 8, 9])")
#| let { left: l, found, right: r, } = split_member(
#| from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root,
#| 0,
#| )
#| inspect(found, content="false")
#| inspect(l, content="None")
#| inspect(r, content="Some([1, 2, 3, 4, 5, 6, 7, 8, 9])")
#| let { left: l, found, right: r, } = split_member(
#| from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root,
#| 10,
#| )
#| inspect(found, content="false")
#| inspect(l, content="Some([1, 2, 3, 4, 5, 6, 7, 8, 9])")
#| inspect(r, content="None")
#| let { left: l, found, right: r, } = split_member(
#| from_array([7, 2, 9, 4, 5, 6, 3, 8, 1]).root,
#| 4,
#| )
#| inspect(found, content="true")
#| inspect(l, content="Some([1, 2, 3])")
#| inspect(r, content="Some([5, 6, 7, 8, 9])")
#| let { left: l, found, right: r, } = split_member(from_array([]).root, 7)
#| inspect(found, content="false")
#| inspect(l, content="None")
#| inspect(r, content="None")
#|}
#|test "join" {
#| fn join_to_array(
#| l : SortedSet[Int],
#| value : Int,
#| r : SortedSet[Int],
#| ) -> Array[Int] {
#| let root = join(l.root, value, r.root)
#| ({ root: Some(root), size: l.size + r.size + 1, } : SortedSet[Int]).to_array()
#| }
#| let l = from_array([13, 8, 17, 1, 11, 15, 25, 6])
#| let r = from_array([27, 28, 40, 35, 33])
#| @debug.debug_inspect(
#| join_to_array(l, 26, r),
#| 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])
#| @debug.debug_inspect(
#| join_to_array(l, 6, r),
#| content=(
#| #|[1, 2, 3, 4, 5, 6, 7]
#| ),
#| )
#| let l = from_array([3, 2, 5, 1, 4])
#| let r = from_array([])
#| @debug.debug_inspect(
#| join_to_array(l, 6, r),
#| content=(
#| #|[1, 2, 3, 4, 5, 6]
#| ),
#| )
#| let l = from_array([])
#| let r = from_array([])
#| @debug.debug_inspect(
#| join_to_array(l, 6, r),
#| content=(
#| #|[6]
#| ),
#| )
#| let l = from_array([])
#| let r = from_array([7, 8, 9, 10, 11, 12])
#| @debug.debug_inspect(
#| join_to_array(l, 6, r),
#| content=(
#| #|[6, 7, 8, 9, 10, 11, 12]
#| ),
#| )
#|}
#|test "add to empty set" {
#| let set = new_sorted_set()
#| set.add(1)
#| @test.assert_eq(set.contains(1), true)
#| inspect(set.debug_tree(), content="([1]1,_,_)")
#|}
#|test "add to non-empty set" {
#| let set = new_sorted_set()
#| set.add(1)
#| set.add(2)
#| @test.assert_eq(set.contains(1), true)
#| @test.assert_eq(set.contains(2), true)
#| inspect(set.debug_tree(), content="([2]1,_,([1]2,_,_))")
#|}
#|test "add duplicate value" {
#| let set = new_sorted_set()
#| set.add(1)
#| set.add(1)
#| @test.assert_eq(set.contains(1), true)
#| @test.assert_eq(set.length(), 1)
#| inspect(set.debug_tree(), content="([1]1,_,_)")
#|}
#|test "add multiple values" {
#| let set = new_sorted_set()
#| set.add(1)
#| set.add(2)
#| set.add(3)
#| @test.assert_eq(set.contains(1), true)
#| @test.assert_eq(set.contains(2), true)
#| @test.assert_eq(set.contains(3), true)
#| @test.assert_eq(set.length(), 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,_,([1]7,_,_)),([2]9,_,([1]10,_,_))))",
#| )
#| set.remove(10)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]4,([2]2,_,([1]3,_,_)),([3]8,([2]6,_,([1]7,_,_)),([1]9,_,_)))",
#| )
#| set.remove(4)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]6,([2]2,_,([1]3,_,_)),([2]8,([1]7,_,_),([1]9,_,_)))",
#| )
#| set.add(1)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]6,([2]2,([1]1,_,_),([1]3,_,_)),([2]8,([1]7,_,_),([1]9,_,_)))",
#| )
#| set.add(5)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([3]2,([1]1,_,_),([2]3,_,([1]5,_,_))),([2]8,([1]7,_,_),([1]9,_,_)))",
#| )
#| set.add(10)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| set.add(10)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| set.remove(1)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| 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)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([2]4,([1]3,_,_),([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))",
#| )
#| set.remove(3)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([4]6,([2]4,_,([1]5,_,_)),([3]8,([1]7,_,_),([2]10,([1]9,_,_),_)))",
#| )
#| set.remove(4)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]8,([2]6,([1]5,_,_),([1]7,_,_)),([2]10,([1]9,_,_),_))",
#| )
#| set.remove(5)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]8,([2]6,_,([1]7,_,_)),([2]10,([1]9,_,_),_))",
#| )
#| set.remove(6)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([3]8,([1]7,_,_),([2]10,([1]9,_,_),_))")
#| set.remove(7)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([2]9,([1]8,_,_),([1]10,_,_))")
#| set.remove(8)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([2]9,_,([1]10,_,_))")
#| set.remove(9)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([1]10,_,_)")
#| set.remove(10)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="_")
#| let set = from_array([7, 2, 9, 4, 5, 6, 3, 1])
#| set.remove(3)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]5,([2]2,([1]1,_,_),([1]4,_,_)),([2]7,([1]6,_,_),([1]9,_,_)))",
#| )
#| set.remove(2)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]5,([2]4,([1]1,_,_),_),([2]7,([1]6,_,_),([1]9,_,_)))",
#| )
#| set.remove(5)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(
#| set.debug_tree(),
#| content="([3]6,([2]4,([1]1,_,_),_),([2]7,_,([1]9,_,_)))",
#| )
#| set.remove(9)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([3]6,([2]4,([1]1,_,_),_),([1]7,_,_))")
#| set.remove(1)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([2]6,([1]4,_,_),([1]7,_,_))")
#| set.remove(7)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([2]6,([1]4,_,_),_)")
#| set.remove(4)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="([1]6,_,_)")
#| set.remove(6)
#| @debug.debug_inspect(
#| set,
#| content=(
#| #|
#| ),
#| )
#| inspect(set.debug_tree(), content="_")
#|}
#|pub impl[K] Default for SortedSet[K] with fn default() {
#| new_sorted_set()
#|}
),
"types.mbt": (
#|struct SortedSet[V] {
#| mut root : Node[V]?
#| mut size : Int
#|}
#|#unsafe_cycle_free
#|priv struct Node[V] {
#| mut value : V
#| mut left : Node[V]?
#| mut right : Node[V]?
#| mut height : Int
#|} derive(@debug.Debug)
),
"utils.mbt": (
#|impl[V : Eq] Eq for Node[V] with fn equal(self, other) {
#| self.value == other.value
#|}
#|fn[V] height(node : Node[V]?) -> Int {
#| match node {
#| Some({ height, .. }) | (None with height = 0) => height
#| }
#|}
#|fn[V : Show] Node::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] SortedSet::debug_tree(self : SortedSet[V]) -> String {
#| match self.root {
#| Some(root) => root.debug_node()
#| None => "_"
#| }
#|}
),
},
)
///|
let moonbitlang_core_string_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/string",
deps={},
files={
"extends.mbt": (
#|pub extend Regex with Add::{add}
#|pub extend Regex with BitOr::{lor}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend MatchResult with @debug.Debug::{to_repr}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Regex with @debug.Debug::{to_repr}
),
"parse_bigint.mbt": (
#|pub fn parse_bigint(str : StringView, base? : Int = 10) -> @bigint.BigInt raise {
#| @bigint.parse_bigint(str, base~)
#|}
),
"regex.mbt": (
#|pub struct Regex {
#| priv pat : @re.Pattern
#| priv mut re : @re.Regex?
#|}
#|#alias(new, deprecated="Use `Regex()` instead")
#|pub fn Regex::Regex(pattern : StringView) -> Regex raise {
#| let pat = @regex_parser.parse(
#| profile=re_profile_unicode,
#| pattern,
#| mode=String,
#| )
#| { pat, re: None, }
#|}
#|const MAX_REPEAT_QUANTIFIER = 256
#|pub impl @debug.Debug for Regex with fn to_repr(self) {
#| @debug.Repr::opaque_("Regex", Repr(self.pat))
#|}
#|struct MatchResult {
#| input : StringView
#| group_names : ReadOnlyArray[String?]
#| result : @re.MatchResult
#|} derive(@debug.Debug)
#|pub fn MatchResult::before(self : MatchResult) -> StringView {
#| guard self.result.group(0) is Some((start, _end)) else { panic() }
#| self.input[0:start]
#|}
#|pub fn MatchResult::after(self : MatchResult) -> StringView {
#| guard self.result.group(0) is Some((_start, end)) else { panic() }
#| self.input[end:self.input.length()]
#|}
#|pub fn MatchResult::content(self : MatchResult) -> StringView {
#| guard self.result.group(0) is Some((start, end)) else { panic() }
#| self.input[start:end]
#|}
#|pub fn MatchResult::group(self : MatchResult, group_index : Int) -> StringView? {
#| match self.result.group(group_index) {
#| None => None
#| Some((start, end)) => Some(self.input[start:end])
#| }
#|}
#|pub fn MatchResult::named_group(
#| self : MatchResult,
#| name : String,
#|) -> StringView? {
#| match self.group_names.search(Some(name)) {
#| None => None
#| Some(index) => self.group(index)
#| }
#|}
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|pub fn Regex::internal_compile_pattern(pat : Pattern) -> Regex {
#| let lowered_pat = re_lower_to_utf16(pat.0)
#| { pat: pat.0, re: Some(@re.compile(profile=re_profile_utf16, lowered_pat)), }
#|}
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|pub fn Regex::internal_from_string(pat : String) -> Regex {
#| try! Regex(pat)
#|}
#|fn Regex::re(self : Regex) -> @re.Regex {
#| match self.re {
#| Some(re) => re
#| None => {
#| let lowered_pat = re_lower_to_utf16(self.pat)
#| let re = @re.compile(profile=re_profile_utf16, lowered_pat)
#| self.re = Some(re)
#| re
#| }
#| }
#|}
#|pub fn Regex::unsafe_from_string(pattern : StringView) -> Regex {
#| try! Regex(pattern)
#|}
#|pub fn Regex::string(str : StringView) -> Regex {
#| let pat = @re.seq(
#| ReadOnlyArray::from_array(
#| str.to_array().map(b => @re.char(@re.RecharSet::char(b.to_int()))),
#| ),
#| )
#| { pat, re: None, }
#|}
#|pub fn Regex::repeat(
#| self : Regex,
#| min? : Int = 0,
#| max? : Int,
#| greedy? : Bool = true,
#|) -> Regex {
#| guard min >= 0 && min <= MAX_REPEAT_QUANTIFIER else { panic() }
#| guard max is None ||
#| (max is Some(max) && max >= min && max <= MAX_REPEAT_QUANTIFIER) else {
#| panic()
#| }
#| {
#| pat: @re.quantifier(self.pat, {
#| min,
#| max,
#| mode: if greedy {
#| Greedy
#| } else {
#| NonGreedy
#| },
#| }),
#| re: None,
#| }
#|}
#|#intrinsic("%regex.seq")
#|pub impl Add for Regex with fn add(self, other) -> Regex {
#| { pat: @re.seq([self.pat, other.pat]), re: None, }
#|}
#|#intrinsic("%regex.alt")
#|pub impl BitOr for Regex with fn lor(self, other) -> Regex {
#| { pat: @re.alt([self.pat, other.pat]), re: None, }
#|}
#|pub fn Regex::execute(
#| self : Regex,
#| input : StringView,
#| last_index? : Int = 0,
#|) -> MatchResult? {
#| match self.re().execute(input, last_index) {
#| None => None
#| Some(result) =>
#| Some({ input, group_names: self.re().group_names(), result, })
#| }
#|}
#|pub fn Regex::capture(self : Regex, group_name : String) -> Regex {
#| { pat: @re.capture(name=group_name, self.pat), re: None, }
#|}
),
"regex_methods.mbt": (
#|fn StringView::next_char_index(self : StringView, index : Int) -> Int {
#| if index < self.length() && self.unsafe_get(index).is_leading_surrogate() {
#| index + 2
#| } else {
#| index + 1
#| }
#|}
#|pub fn Regex::replace_by(
#| regex : Regex,
#| str : StringView,
#| replacer : (MatchResult) -> StringView,
#| limit? : Int,
#|) -> StringView {
#| let mut buf : StringBuilder? = None
#| let copy_index = for copy_index = 0, search_index = 0, replaced = 0; search_index <=
#| str.length(); {
#| if limit is Some(limit) && replaced >= limit {
#| break copy_index
#| }
#| match regex.execute(str, last_index=search_index) {
#| None => break copy_index
#| Some(m) => {
#| guard m.result.group(0) is Some((start, end)) else { break copy_index }
#| let b = match buf {
#| Some(b) => b
#| None => {
#| let b = StringBuilder()
#| buf = Some(b)
#| b
#| }
#| }
#| b.write_stringview(str[copy_index:start])
#| b.write_stringview(replacer(m))
#| let search_index = if start == end {
#| str.next_char_index(end)
#| } else {
#| end
#| }
#| continue end, search_index, replaced + 1
#| }
#| }
#| } nobreak {
#| copy_index
#| }
#| match buf {
#| None => str
#| Some(b) => {
#| b.write_stringview(str[copy_index:])
#| b.to_string()
#| }
#| }
#|}
#|pub fn Regex::find(regex : Regex, str : StringView) -> Iter[MatchResult] {
#| let mut search_index = 0
#| let len = str.length()
#| Iter::new(() => {
#| guard search_index <= len else { None }
#| match regex.execute(str, last_index=search_index) {
#| None => None
#| Some(m) => {
#| guard m.result.group(0) is Some((start, end)) else { return None }
#| search_index = if start == end { str.next_char_index(end) } else { end }
#| Some(m)
#| }
#| }
#| })
#|}
#|pub fn Regex::split(regex : Regex, str : StringView) -> Iter[StringView] {
#| let mut copy_index = 0
#| let mut search_index = 0
#| let len = str.length()
#| let mut done = false
#| Iter::new(() => {
#| guard !done else { None }
#| while search_index <= len {
#| match regex.execute(str, last_index=search_index) {
#| None => {
#| done = true
#| return Some(str[copy_index:])
#| }
#| Some(m) => {
#| guard m.result.group(0) is Some((start, end)) else {
#| done = true
#| return Some(str[copy_index:])
#| }
#| let part = str[copy_index:start]
#| copy_index = end
#| search_index = if start == end {
#| str.next_char_index(end)
#| } else {
#| end
#| }
#| return Some(part)
#| }
#| }
#| }
#| done = true
#| Some(str[copy_index:])
#| })
#|}
),
"regex_pattern.mbt": (
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|struct Pattern(@re.Pattern)
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|pub fn Pattern::epsilon() -> Pattern {
#| Pattern(@re.epsilon)
#|}
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|pub fn Pattern::empty() -> Pattern {
#| Pattern(@re.empty)
#|}
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|pub fn Pattern::char_range(lo : Int, hi : Int) -> Pattern {
#| Pattern(@re.char(@re.RecharSet::char_range(lo, hi)))
#|}
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|pub fn Pattern::char_set(cs : ReadOnlyArray[(Int, Int)]) -> Pattern {
#| Pattern(@re.char(@re.RecharSet::from_sorted_array(cs)))
#|}
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|pub fn Pattern::seq(pats : ReadOnlyArray[Pattern]) -> Pattern {
#| Pattern(@re.seq(pats.map(p => p.0)))
#|}
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|pub fn Pattern::alt(pats : ReadOnlyArray[Pattern]) -> Pattern {
#| Pattern(@re.alt(pats.map(p => p.0)))
#|}
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|pub fn Pattern::quantifier(
#| pat : Pattern,
#| min~ : Int,
#| max~ : Int?,
#| greedy~ : Bool,
#|) -> Pattern {
#| Pattern(
#| @re.quantifier(pat.0, {
#| min,
#| max,
#| mode: if greedy {
#| Greedy
#| } else {
#| NonGreedy
#| },
#| }),
#| )
#|}
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|pub fn Pattern::capture(pat : Pattern, name? : String) -> Pattern {
#| Pattern(@re.capture(pat.0, name?))
#|}
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|pub fn Pattern::start_of_input() -> Pattern {
#| Pattern(@re.start_of_input)
#|}
#|#internal(internal, "not intended for public use")
#|#doc(hidden)
#|pub fn Pattern::end_of_input() -> Pattern {
#| Pattern(@re.end_of_input)
#|}
),
"regex_profile.mbt": (
#|let word_set : @re.RecharSet = @re.RecharSet::char_range('a', 'z') +
#| @re.RecharSet::char_range('A', 'Z') +
#| @re.RecharSet::char_range('0', '9') +
#| @re.RecharSet::char('_')
#|let re_profile_unicode : @re.Profile = Profile(
#| valid=@re.RecharSet::char_range(0, 0x10FFFF) -
#| @re.RecharSet::char_range(0xD800, 0xDFFF),
#| word=word_set,
#| category=c => {
#| match c {
#| 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => @re.Category::word()
#| '\n' => @re.Category::newline() + @re.Category::not_word()
#| _ => @re.Category::not_word()
#| }
#| },
#|)
#|let re_profile_utf16 : @re.Profile = Profile(
#| valid=@re.RecharSet::char_range(0, 0xFFFF),
#| word=re_profile_unicode.word,
#| word_symbolize_splits=[
#| word_set,
#| @re.RecharSet::char_range(0xD800, 0xDBFF),
#| @re.RecharSet::char_range(0xDC00, 0xDFFF),
#| ],
#| category=c => {
#| match c {
#| 0xD800..=0xDBFF => @re.Category::not_word_start()
#| 0xDC00..=0xDFFF => @re.Category::not_word_end()
#| _ => (re_profile_unicode.category)(c)
#| }
#| },
#|)
),
"regex_utf16.mbt": (
#|fn re_surrogate_pair(codepoint : Int) -> (Int, Int) {
#| let cp = codepoint - 0x10000
#| let high = 0xD800 + ((cp >> 10) & 0x3FF)
#| let low = 0xDC00 + (cp & 0x3FF)
#| (high, low)
#|}
#|fn re_lower_cset(cs : @re.RecharSet) -> @re.Pattern {
#| let cset1 = cs & @re.RecharSet::char_range(0x0000, 0xFFFF)
#| let cset2 = cs & @re.RecharSet::char_range(0x10000, 0x10FFFF)
#| let alts = []
#| if !cset1.is_empty() {
#| alts.push(@re.char(cset1))
#| }
#| for interval in cset2.intervals() {
#| let (lo, hi) = interval
#| if lo == hi {
#| let pair = re_surrogate_pair(lo)
#| alts.push(
#| @re.seq([
#| @re.char(@re.RecharSet::char(pair.0)),
#| @re.char(@re.RecharSet::char(pair.1)),
#| ]),
#| )
#| } else {
#| let lo = re_surrogate_pair(lo)
#| let hi = re_surrogate_pair(hi)
#| if lo.0 == hi.0 {
#| alts.push(
#| @re.seq([
#| @re.char(@re.RecharSet::char(lo.0)),
#| @re.char(@re.RecharSet::char_range(lo.1, hi.1)),
#| ]),
#| )
#| } else {
#| alts.push(
#| @re.seq([
#| @re.char(@re.RecharSet::char(lo.0)),
#| @re.char(@re.RecharSet::char_range(lo.1, 0xDFFF)),
#| ]),
#| )
#| if lo.0 + 1 < hi.0 {
#| alts.push(
#| @re.seq([
#| @re.char(@re.RecharSet::char_range(lo.0 + 1, hi.0 - 1)),
#| @re.char(@re.RecharSet::char_range(0xDC00, 0xDFFF)),
#| ]),
#| )
#| }
#| alts.push(
#| @re.seq([
#| @re.char(@re.RecharSet::char(hi.0)),
#| @re.char(@re.RecharSet::char_range(0xDC00, hi.1)),
#| ]),
#| )
#| }
#| }
#| }
#| @re.shortest(@re.alt(ReadOnlyArray::from_array(alts)))
#|}
#|fn re_lower_to_utf16(ast : @re.Pattern) -> @re.Pattern {
#| match ast.desc {
#| Char(cs) => re_lower_cset(cs)
#| Sequence(exprs) => @re.seq(exprs.map(e => re_lower_to_utf16(e)))
#| Alternation(exprs) => @re.alt(exprs.map(e => re_lower_to_utf16(e)))
#| Quantifier(q, expr) => @re.quantifier(re_lower_to_utf16(expr), q)
#| Preference(p, expr) => @re.preference(p, re_lower_to_utf16(expr))
#| Capture(name~, expr) => @re.capture(name?, re_lower_to_utf16(expr))
#| Assertion(a) => @re.assertion(a)
#| }
#|}
),
"strconv.mbt": (
#|pub using @internal/strconv {
#| parse_int64,
#| parse_int,
#| parse_uint64,
#| parse_uint,
#| parse_bool,
#| parse_double,
#|}
),
"strconv_traits.mbt": (
#|pub(open) trait FromStr {
#| #as_free_fn
#| fn from_str(StringView) -> Self raise
#|}
#|pub impl FromStr for Bool with fn from_str(str) {
#| parse_bool(str)
#|}
#|pub impl FromStr for Int with fn from_str(str) {
#| parse_int(str)
#|}
#|pub impl FromStr for Int64 with fn from_str(str) {
#| parse_int64(str)
#|}
#|pub impl FromStr for UInt with fn from_str(str) {
#| parse_uint(str)
#|}
#|pub impl FromStr for UInt64 with fn from_str(str) {
#| parse_uint64(str)
#|}
#|pub impl FromStr for Double with fn from_str(str) {
#| parse_double(str)
#|}
#|pub impl FromStr for @bigint.BigInt with fn from_str(str) {
#| parse_bigint(str)
#|}
#|test "parse" {
#| let b : Bool = from_str("true")
#| inspect(b, content="true")
#| let i : Int = from_str("12345")
#| inspect(i, content="12345")
#| let i64 : Int64 = from_str("9223372036854775807")
#| @test.assert_eq(i64, 9223372036854775807L)
#| let ui : UInt = from_str("4294967295")
#| inspect(ui, content="4294967295")
#| let ui64 : UInt64 = from_str("18446744073709551615")
#| @test.assert_eq(ui64, 18446744073709551615UL)
#| let d : Double = from_str("1234.56789")
#| @test.assert_eq(d, 1234.56789)
#| let bigint : @bigint.BigInt = from_str("123456789012345678901234567890")
#| inspect(bigint, content="123456789012345678901234567890")
#|}
),
"string.mbt": (
#|#deprecated
#|#doc(hidden)
#|pub fn from_array(chars : ArrayView[Char]) -> String {
#| String::from_array(chars)
#|}
#|#deprecated
#|#doc(hidden)
#|pub fn from_iter(iter : Iter[Char]) -> String {
#| String::from_iter(iter)
#|}
#|#deprecated
#|#doc(hidden)
#|pub fn from_iterator(iter : Iter[Char]) -> String {
#| String::from_iter(iter)
#|}
#|#deprecated("Use `String::default` instead")
#|#doc(hidden)
#|pub fn default() -> String {
#| ""
#|}
),
"utils.mbt": (
#|fn code_point_of_surrogate_pair(leading : UInt16, trailing : UInt16) -> Char {
#| ((leading - 0xD800).to_int() * 0x400 + trailing.to_int() - 0xDC00 + 0x10000).unsafe_to_char()
#|}
#|test "code_point_of_surrogate_pair" {
#| let s = "😀"
#| let leading = s.code_unit_at(0)
#| let trailing = s.code_unit_at(1)
#| inspect(code_point_of_surrogate_pair(leading, trailing), content="😀")
#|}
#|test "is_leading_surrogate" {
#| inspect("🤣".code_unit_at(0).is_leading_surrogate(), content="true")
#| inspect("🤣".code_unit_at(1).is_leading_surrogate(), content="false")
#|}
#|test "is_trailing_surrogate" {
#| inspect("🤣".code_unit_at(0).is_trailing_surrogate(), content="false")
#| inspect("🤣".code_unit_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": (
#|pub using @builtin {trait ToStringView}
#|#deprecated("@string.View is deprecated, use StringView instead.")
#|pub type View = StringView
),
},
)
///|
let moonbitlang_core_string_internal_regex_engine_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/string/internal/regex_engine",
deps={},
files={
"compile.mbt": (
#|pub fn compile(profile~ : Profile, ast : Pattern) -> Regex {
#| let ast = if ast.is_anchored() {
#| capture(ast)
#| } else {
#| seq([
#| shortest(
#| quantifier(char(profile.valid), { min: 0, max: None, mode: Greedy, }),
#| ),
#| capture(ast),
#| ])
#| }
#| let symbol_map = @symbol_map.new()
#| symbolize(profile~, symbol_map~, ast)
#| let (symbol_table, symbol_repr) = symbol_map.finalize(profile.lb, profile.ub)
#| let ctx = @automata.Context()
#| let tc = TranslateContext::new(ctx, symbol_table)
#| let (expr, pref) = translate(tc, ast)
#| let expr = enforce_pref(tc.ctx, First, pref, expr)
#| Regex::new(
#| profile,
#| ctx,
#| expr,
#| ReadOnlyArray::from_array(tc.groups),
#| symbol_table,
#| symbol_repr,
#| )
#|}
),
"execute.mbt": (
#|struct MatchResult(Array[Int]) derive(@debug.Debug)
#|const NULL_SYMBOL : Rechar = -1
#|fn category_from_symbol(
#| profile~ : Profile,
#| symbol_repr~ : ReadOnlyArray[Rechar],
#| symbol : Rechar,
#|) -> Category {
#| if symbol is NULL_SYMBOL {
#| Category::inexistant()
#| } else {
#| (profile.category)(symbol_repr[symbol])
#| }
#|}
#|pub fn MatchResult::group(self : MatchResult, index : Int) -> (Int, Int)? {
#| let start_pos = self.0.get(index * 2)
#| guard start_pos is Some(start_pos) && start_pos >= 0 else { None }
#| let end_pos = self.0[index * 2 + 1]
#| guard end_pos >= 0 else { panic() }
#| Some((start_pos, end_pos))
#|}
#|pub fn Regex::execute(
#| self : Regex,
#| input : StringView,
#| last_index : Int,
#|) -> MatchResult? {
#| guard last_index >= 0 && last_index <= input.length() else { panic() }
#| let symbol_table = self.symbol_table
#| let prev_cat = category_from_symbol(
#| profile=self.profile,
#| symbol_repr=self.symbol_repr,
#| if last_index == 0 {
#| NULL_SYMBOL
#| } else {
#| let ch = input.unsafe_get(last_index - 1).to_int()
#| symbol_table.map(ch)
#| },
#| )
#| let start_state_id = self.stablize_start_state(prev_cat)
#| let positions = Positions::new()
#| let mut transition_table = self.transition_table
#| let data = input.data()
#| let mut pos = input.start_offset() + last_index
#| let end = input.start_offset() + input.length()
#| let mut state_id = start_state_id
#| while pos < end {
#| let ch = data.unsafe_get(pos).to_int()
#| let symbol = symbol_table.map(ch)
#| let transition_index = state_id.transition_base() + symbol
#| let prev_state_id = state_id
#| state_id = transition_table.unsafe_get(transition_index)
#| if state_id.is_pending() {
#| state_id = self.stablize_next_state(prev_state_id, symbol)
#| transition_table = self.transition_table
#| transition_table[transition_index] = state_id
#| }
#| let slot = state_id.slot()
#| if slot.index >= positions.0.length() {
#| positions.0.resize(slot.index + 8, -1)
#| }
#| positions.0[slot.index] = pos
#| if state_id.is_break() {
#| break
#| }
#| pos += 1
#| }
#| let state = self.get_state(state_id)
#| let matched = match state.status() {
#| Failed => None
#| Running => {
#| let next_cat = category_from_symbol(
#| profile=self.profile,
#| symbol_repr=self.symbol_repr,
#| if pos >= end {
#| NULL_SYMBOL
#| } else {
#| let ch = data.unsafe_get(pos).to_int()
#| symbol_table.map(ch)
#| },
#| )
#| let (slot, status) = self.stablize_final(state_id, state, next_cat)
#| match status {
#| Failed | Running => None
#| Match(marks) => {
#| positions.set(slot, pos)
#| Some(marks)
#| }
#| }
#| }
#| Match(marks) => Some(marks)
#| }
#| match matched {
#| None => None
#| Some(marks) => {
#| let mark_pos = Array::make(self.groups.length() * 2, -1)
#| let shift = input.start_offset()
#| for mark, slot in marks {
#| mark_pos[mark.0] = positions.get(slot) - shift
#| }
#| Some(MatchResult(mark_pos))
#| }
#| }
#|}
),
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend MatchResult with @debug.Debug::{to_repr}
),
"positions.mbt": (
#|priv struct Positions(Array[Int])
#|fn Positions::new() -> Positions {
#| Positions(Array::make(8, -1))
#|}
#|#alias("_[_]=_")
#|fn Positions::set(self : Positions, slot : @automata.Slot, pos : Int) -> Unit {
#| if slot.index >= self.0.length() {
#| self.0.resize(slot.index + 8, -1)
#| }
#| self.0[slot.index] = pos
#|}
#|#alias("_[_]")
#|fn Positions::get(self : Positions, slot : @automata.Slot) -> Int {
#| if slot.index >= self.0.length() {
#| -1
#| } else {
#| self.0[slot.index]
#| }
#|}
),
"regex.mbt": (
#|struct Regex {
#| profile : Profile
#| ctx : @automata.Context
#| expr : @automata.Expr
#| groups : ReadOnlyArray[String?]
#| symbol_table : @symbol_map.Table
#| symbol_repr : ReadOnlyArray[Rechar]
#| start_states : Array[(Category, StateId)]
#| state_table : @hashmap.HashMap[@automata.State, StateId]
#| mut transition_table : FixedArray[StateId]
#| mut final_table : FixedArray[
#| @list.List[(Category, @automata.Slot, @automata.Status)],
#| ]
#| mut states : FixedArray[@automata.State]
#| mut num_states : Int
#|}
#|pub fn Regex::group_names(self : Regex) -> ReadOnlyArray[String?] {
#| self.groups
#|}
#|fn Regex::new(
#| profile : Profile,
#| ctx : @automata.Context,
#| expr : @automata.Expr,
#| groups : ReadOnlyArray[String?],
#| symbol_table : @symbol_map.Table,
#| symbol_repr : ReadOnlyArray[Rechar],
#|) -> Regex {
#| {
#| profile,
#| ctx,
#| expr,
#| groups,
#| symbol_table,
#| symbol_repr,
#| start_states: [],
#| state_table: HashMap([]),
#| transition_table: [],
#| final_table: [],
#| states: [],
#| num_states: 0,
#| }
#|}
#|fn Regex::num_symbols(self : Regex) -> Int {
#| self.symbol_repr.length()
#|}
),
"state_id.mbt": (
#|priv struct StateId(Int64)
#|let pending_state_id : StateId = -1
#|fn StateId::new(
#| index~ : Int,
#| slot~ : @automata.Slot,
#| is_break~ : Bool,
#| num_symbols~ : Int,
#|) -> StateId {
#| debug_assert(() => {
#| index <= 0b1111_1111_1111_1111_1110 &&
#| slot.index <= 0b111_1111_1111 &&
#| num_symbols <= 0b111_1111_1110
#| })
#| let transition_base = index * num_symbols
#| let encoded_index = if is_break { -2 - index } else { index }
#| let id = StateId(
#| (((encoded_index << 11) | slot.index).to_int64() << 32) |
#| transition_base.to_int64(),
#| )
#| debug_assert(() => {
#| id.index() == index && id.slot() == slot && id.is_break() == is_break
#| })
#| id
#|}
#|fn StateId::is_pending(self : StateId) -> Bool {
#| self.0 == -1
#|}
#|fn StateId::is_break(self : StateId) -> Bool {
#| self.0 < -1
#|}
#|fn StateId::transition_base(self : StateId) -> Int {
#| self.0.to_int()
#|}
#|fn StateId::index(self : StateId) -> Int {
#| let x = (self.0 >> 43).to_int()
#| if x < 0 {
#| -(x + 2)
#| } else {
#| x
#| }
#|}
#|fn StateId::slot(self : StateId) -> @automata.Slot {
#| @automata.Slot::from_index((self.0 >> 32).to_int() & 0b111_1111_1111)
#|}
),
"states.mbt": (
#|fn Regex::get_state(self : Regex, state_id : StateId) -> @automata.State {
#| self.states.unsafe_get(state_id.index())
#|}
#|fn Regex::stablize_start_state(self : Regex, prev_cat : Category) -> StateId {
#| for start_state in self.start_states {
#| let (cat, state_id) = start_state
#| if cat == prev_cat {
#| return state_id
#| }
#| }
#| let state_id = self.stablize_state(
#| @automata.State::start(prev_cat, self.expr),
#| )
#| self.start_states.push((prev_cat, state_id))
#| state_id
#|}
#|fn Regex::stablize_state(self : Regex, state : @automata.State) -> StateId {
#| self.state_table.get_or_init(state, () => {
#| let index = self.num_states
#| self.num_states += 1
#| let num_symbols = self.num_symbols()
#| if index >= self.states.length() {
#| let new_states_len = Int::max(self.states.length() * 2, 4)
#| let new_states = FixedArray::make(new_states_len, @automata.st_dummy)
#| self.states.blit_to(new_states, len=self.states.length())
#| let new_transition_table = FixedArray::make(
#| new_states_len * num_symbols,
#| pending_state_id,
#| )
#| self.transition_table.blit_to(
#| new_transition_table,
#| len=self.transition_table.length(),
#| )
#| let new_final_table = FixedArray::make(new_states_len, @list.empty())
#| self.final_table.blit_to(new_final_table, len=self.final_table.length())
#| self.states = new_states
#| self.transition_table = new_transition_table
#| self.final_table = new_final_table
#| }
#| self.states[index] = state
#| let state_id = StateId::new(
#| index~,
#| slot=state.slot(),
#| is_break=state.status() is (Match(_) | Failed),
#| num_symbols~,
#| )
#| state_id
#| })
#|}
#|fn Regex::stablize_next_state(
#| self : Regex,
#| prev_state_id : StateId,
#| symbol : Rechar,
#|) -> StateId {
#| let cat = category_from_symbol(
#| profile=self.profile,
#| symbol_repr=self.symbol_repr,
#| symbol,
#| )
#| let prev_state = self.get_state(prev_state_id)
#| let state = @automata.delta(ctx=self.ctx, prev_state, symbol, next_cat=cat)
#| self.stablize_state(state)
#|}
#|fn Regex::stablize_final(
#| self : Regex,
#| state_id : StateId,
#| state : @automata.State,
#| next_cat : Category,
#|) -> (@automata.Slot, @automata.Status) {
#| let state_index = state_id.index()
#| for entry = self.final_table[state_index] {
#| match entry {
#| Empty => {
#| let next_state = @automata.delta(
#| ctx=self.ctx,
#| state,
#| NULL_SYMBOL,
#| next_cat~,
#| )
#| let slot = next_state.slot()
#| let status = next_state.status()
#| self.final_table[state_index] = @list.cons(
#| (next_cat, slot, status),
#| self.final_table[state_index],
#| )
#| break (slot, status)
#| }
#| More(head, tail~) =>
#| if head.0 == next_cat {
#| break (head.1, head.2)
#| } else {
#| continue tail
#| }
#| }
#| }
#|}
),
"symbolize.mbt": (
#|fn symbolize(
#| profile~ : Profile,
#| symbol_map~ : @symbol_map.SymbolMap,
#| expr : Pattern,
#|) -> Unit {
#| fn aux(expr : Pattern) {
#| match expr.desc {
#| Char(s) => symbol_map.split(s)
#| Sequence(l) => l.each(aux)
#| Alternation(l) => l.each(aux)
#| Quantifier(_, r) => aux(r)
#| Assertion(StartOfLine) | Assertion(EndOfLine) =>
#| symbol_map.split(RecharSet::char('\n'))
#| Assertion(StartOfWord)
#| | Assertion(EndOfWord)
#| | Assertion(NotWordBoundary) =>
#| for split in profile.word_symbolize_splits {
#| symbol_map.split(split)
#| }
#| Assertion(StartOfInput) | Assertion(EndOfInput) => ()
#| Preference(_, r) => aux(r)
#| Capture(r, ..) => aux(r)
#| }
#| }
#| aux(expr)
#|}
),
"translate.mbt": (
#|priv struct TranslateContext {
#| ctx : @automata.Context
#| pref : Preference
#| groups : Array[String?]
#| symbol_table : @symbol_map.Table
#|}
#|fn TranslateContext::new(
#| ctx : @automata.Context,
#| symbol_table : @symbol_map.Table,
#|) -> TranslateContext {
#| { ctx, pref: First, groups: [], symbol_table, }
#|}
#|fn translate(
#| tc : TranslateContext,
#| ast : Pattern,
#|) -> (@automata.Expr, Preference) {
#| let { ctx, pref, groups, symbol_table, } = tc
#| match ast.desc {
#| Char(c) => (@automata.e_cset(ctx~, symbol_table.map_set(c)), pref)
#| Sequence(exprs) => (transl_seq(tc, exprs), pref)
#| Alternation(exprs) => {
#| let alts = []
#| for expr in exprs {
#| let (cr, pref2) = translate(tc, expr)
#| alts.push(enforce_pref(ctx, pref, pref2, cr))
#| }
#| (@automata.e_alt(ctx~, alts), pref)
#| }
#| Quantifier(q, expr) => {
#| let (cr, pref2) = translate(tc, expr)
#| let rem = match q.max {
#| None => @automata.e_rep(ctx~, q.mode, pref2, cr)
#| Some(max) => {
#| let repeater = match q.mode {
#| Greedy =>
#| rem => {
#| @automata.e_alt(ctx~, [
#| @automata.e_seq(ctx~, pref2, @automata.e_copy(ctx~, cr), rem),
#| @automata.e_eps,
#| ])
#| }
#| NonGreedy =>
#| rem => {
#| @automata.e_alt(ctx~, [
#| @automata.e_eps,
#| @automata.e_seq(ctx~, pref2, @automata.e_copy(ctx~, cr), rem),
#| ])
#| }
#| }
#| iter(max - q.min, repeater, @automata.e_eps)
#| }
#| }
#| let result = iter(
#| q.min,
#| rem => @automata.e_seq(ctx~, pref2, @automata.e_copy(ctx~, cr), rem),
#| rem,
#| )
#| (result, pref)
#| }
#| Preference(pref2, expr) => {
#| let (cr, pref3) = translate({ ..tc, pref: pref2, }, expr)
#| (enforce_pref(ctx, pref2, pref3, cr), pref2)
#| }
#| Capture(name~, expr) => {
#| let group_index = groups.length()
#| groups.push(name)
#| let (cr, pref2) = translate(tc, expr)
#| (
#| @automata.e_seq(
#| ctx~,
#| First,
#| @automata.e_mark(ctx~, Mark(group_index * 2)),
#| @automata.e_seq(
#| ctx~,
#| First,
#| cr,
#| @automata.e_mark(ctx~, Mark(group_index * 2 + 1)),
#| ),
#| ),
#| pref2,
#| )
#| }
#| Assertion(asrt) => (transl_asrt(ctx, asrt), pref)
#| }
#|}
#|fn transl_asrt(ctx : @automata.Context, asrt : Assertion) -> @automata.Expr {
#| match asrt {
#| StartOfLine => @automata.e_after(ctx~, Category::inexistant_or_newline())
#| EndOfLine => @automata.e_before(ctx~, Category::inexistant_or_newline())
#| StartOfWord =>
#| @automata.e_seq(
#| ctx~,
#| First,
#| @automata.e_after(ctx~, Category::inexistant_or_non_word_end()),
#| @automata.e_before(ctx~, Category::word()),
#| )
#| EndOfWord =>
#| @automata.e_seq(
#| ctx~,
#| First,
#| @automata.e_after(ctx~, Category::word()),
#| @automata.e_before(ctx~, Category::inexistant_or_non_word_start()),
#| )
#| NotWordBoundary =>
#| @automata.e_alt(ctx~, [
#| @automata.e_seq(
#| ctx~,
#| First,
#| @automata.e_after(ctx~, Category::word()),
#| @automata.e_before(ctx~, Category::word()),
#| ),
#| @automata.e_seq(
#| ctx~,
#| First,
#| @automata.e_after(ctx~, Category::inexistant_or_non_word_end()),
#| @automata.e_before(ctx~, Category::inexistant_or_non_word_start()),
#| ),
#| ])
#| StartOfInput => @automata.e_after(ctx~, Category::inexistant())
#| EndOfInput => @automata.e_before(ctx~, Category::inexistant())
#| }
#|}
#|fn transl_seq(
#| tc : TranslateContext,
#| exprs : ReadOnlyArray[Pattern],
#|) -> @automata.Expr {
#| fn compose(
#| pref2 : Preference,
#| cr : @automata.Expr,
#| cr2 : @automata.Expr,
#| ) -> @automata.Expr {
#| if @automata.is_eps(cr2) {
#| enforce_pref(tc.ctx, tc.pref, pref2, cr)
#| } else if @automata.is_eps(cr) {
#| cr2
#| } else {
#| @automata.e_seq(ctx=tc.ctx, pref2, cr, cr2)
#| }
#| }
#| fn go(i : Int) -> @automata.Expr {
#| if i >= exprs.length() {
#| @automata.e_eps
#| } else {
#| let (cr, pref2) = translate(tc, exprs[i])
#| let cr2 = go(i + 1)
#| compose(pref2, cr, cr2)
#| }
#| }
#| go(0)
#|}
#|fn enforce_pref(
#| ctx : @automata.Context,
#| pref : Preference,
#| pref2 : Preference,
#| cr : @automata.Expr,
#|) -> @automata.Expr {
#| match (pref, pref2) {
#| (First, First) => cr
#| (First, k) => @automata.e_seq(ctx~, k, cr, @automata.e_eps)
#| _ => cr
#| }
#|}
#|fn[T] iter(n : Int, f : (T) -> T, init : T) -> T {
#| for i = n, acc = init {
#| if i == 0 {
#| break acc
#| } else {
#| continue i - 1, f(acc)
#| }
#| }
#|}
),
"using.mbt": (
#|pub using @shared_types {
#| type Profile,
#| type Rechar,
#| type RecharSet,
#| type Preference,
#| type Category,
#| type QuantifierMode,
#|}
#|pub using @ast {
#| type Pattern,
#| type Assertion,
#| type Quantifier,
#| char,
#| epsilon,
#| seq,
#| empty,
#| alt,
#| quantifier,
#| preference,
#| shortest,
#| longest,
#| first,
#| capture,
#| assertion,
#| start_of_input,
#| end_of_input,
#| start_of_line,
#| end_of_line,
#| start_of_word,
#| end_of_word,
#| not_word_boundary,
#|}
),
},
)
///|
let moonbitlang_core_string_internal_regex_engine_ast_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/string/internal/regex_engine/ast",
deps={},
files={
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Assertion with @debug.Debug::{to_repr}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Pattern with @debug.Debug::{to_repr}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend PatternDesc with @debug.Debug::{to_repr}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Quantifier with @debug.Debug::{to_repr}
),
"pattern.mbt": (
#|pub(all) struct Quantifier {
#| min : Int
#| max : Int?
#| mode : @shared_types.QuantifierMode
#|} derive(@debug.Debug)
#|pub enum Assertion {
#| StartOfInput
#| EndOfInput
#| StartOfLine
#| EndOfLine
#| StartOfWord
#| EndOfWord
#| NotWordBoundary
#|} derive(@debug.Debug)
#|pub struct Pattern {
#| desc : PatternDesc
#| nullable : Bool
#|}
#|pub impl @debug.Debug for Pattern with fn to_repr(self) {
#| Repr(self.desc)
#|}
#|pub enum PatternDesc {
#| Char(@shared_types.RecharSet)
#| Sequence(ReadOnlyArray[Pattern])
#| Alternation(ReadOnlyArray[Pattern])
#| Quantifier(Quantifier, Pattern)
#| Preference(@shared_types.Preference, Pattern)
#| Capture(name~ : String?, Pattern)
#| Assertion(Assertion)
#|} derive(@debug.Debug)
#|pub fn Pattern::is_anchored(self : Pattern) -> Bool {
#| match self.desc {
#| Char(_) => false
#| Sequence(exprs) => exprs.any(e => e.is_anchored())
#| Alternation(exprs) => exprs.all(e => e.is_anchored())
#| Quantifier(q, expr) => q.min > 0 && expr.is_anchored()
#| Preference(_, expr) => expr.is_anchored()
#| Capture(expr, ..) => expr.is_anchored()
#| Assertion(StartOfInput) => true
#| Assertion(_) => false
#| }
#|}
#|pub fn char(cs : @shared_types.RecharSet) -> Pattern {
#| if cs.is_empty() {
#| empty
#| } else {
#| { desc: Char(cs), nullable: false, }
#| }
#|}
#|pub let epsilon : Pattern = { desc: Sequence([]), nullable: true, }
#|pub fn seq(exprs : ReadOnlyArray[Pattern]) -> Pattern {
#| let flatten = []
#| for expr in exprs {
#| if expr.desc is Sequence(nested) {
#| for e in nested {
#| flatten.push(e)
#| }
#| } else {
#| flatten.push(expr)
#| }
#| }
#| match flatten {
#| [expr] | ([] with expr = epsilon) => expr
#| exprs =>
#| {
#| desc: Sequence(ReadOnlyArray::from_array(exprs)),
#| nullable: exprs.all(e => e.nullable),
#| }
#| }
#|}
#|pub let empty : Pattern = { desc: Alternation([]), nullable: false, }
#|pub fn alt(exprs : ReadOnlyArray[Pattern]) -> Pattern {
#| match exprs {
#| [expr] | ([] with expr = empty) => expr
#| exprs => { desc: Alternation(exprs), nullable: exprs.any(e => e.nullable), }
#| }
#|}
#|pub fn quantifier(expr : Pattern, q : Quantifier) -> Pattern {
#| guard q.min >= 0 else { panic() }
#| guard q.max is None || (q.max is Some(max) && max >= q.min) else { panic() }
#| { desc: Quantifier(q, expr), nullable: expr.nullable || q.min == 0, }
#|}
#|pub fn preference(pref : @shared_types.Preference, expr : Pattern) -> Pattern {
#| if expr.desc is Char(_) {
#| expr
#| } else {
#| { desc: Preference(pref, expr), nullable: expr.nullable, }
#| }
#|}
#|pub fn longest(expr : Pattern) -> Pattern {
#| preference(Longest, expr)
#|}
#|pub fn shortest(expr : Pattern) -> Pattern {
#| preference(Shortest, expr)
#|}
#|pub fn first(expr : Pattern) -> Pattern {
#| preference(First, expr)
#|}
#|pub fn capture(name? : String, expr : Pattern) -> Pattern {
#| { desc: Capture(name~, expr), nullable: expr.nullable, }
#|}
#|pub fn assertion(a : Assertion) -> Pattern {
#| { desc: Assertion(a), nullable: true, }
#|}
#|pub let start_of_input : Pattern = assertion(StartOfInput)
#|pub let end_of_input : Pattern = assertion(EndOfInput)
#|pub let start_of_line : Pattern = assertion(StartOfLine)
#|pub let end_of_line : Pattern = assertion(EndOfLine)
#|pub let start_of_word : Pattern = assertion(StartOfWord)
#|pub let end_of_word : Pattern = assertion(EndOfWord)
#|pub let not_word_boundary : Pattern = assertion(NotWordBoundary)
),
"using.mbt": "",
},
)
///|
let moonbitlang_core_string_internal_regex_engine_symbol_map_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/string/internal/regex_engine/symbol_map",
deps={},
files={
"symbol_map.mbt": (
#|struct SymbolMap(@sorted_set.SortedSet[@shared_types.Rechar])
#|pub fn new() -> SymbolMap {
#| SymbolMap(SortedSet([]))
#|}
#|pub fn SymbolMap::split(
#| self : SymbolMap,
#| set : @shared_types.RecharSet,
#|) -> Unit {
#| for interval in set.intervals() {
#| let (start, stop) = interval
#| self.0.add(start)
#| if stop + 1 > stop {
#| self.0.add(stop + 1)
#| }
#| }
#|}
#|pub fn SymbolMap::finalize(
#| self : SymbolMap,
#| lb : @shared_types.Rechar,
#| ub : @shared_types.Rechar,
#|) -> (Table, ReadOnlyArray[@shared_types.Rechar]) {
#| guard lb >= 0 else { panic() }
#| let repr = []
#| let table = Array::make(128, -1)
#| if ub < 128 {
#| self.each_intervals(0, ub, (lo, hi) => {
#| let symbol = repr.length()
#| repr.push(Int::max(lo, lb))
#| for c in lo..<=hi {
#| table[c] = symbol
#| }
#| })
#| } else {
#| self.each_intervals(0, 127, (lo, hi) => {
#| let symbol = repr.length()
#| repr.push(Int::max(lo, lb))
#| for c in lo..<=hi {
#| table[c] = symbol
#| }
#| })
#| self.each_intervals(128, ub, (lo, hi) => {
#| let symbol = repr.length()
#| repr.push(Int::max(lo, lb))
#| table.push(lo)
#| table.push(hi)
#| table.push(symbol)
#| })
#| }
#| (Table(FixedArray::from_array(table)), ReadOnlyArray::from_array(repr))
#|}
#|#locals(f)
#|fn SymbolMap::each_intervals(
#| self : SymbolMap,
#| lb : @shared_types.Rechar,
#| ub : @shared_types.Rechar,
#| f : (@shared_types.Rechar, @shared_types.Rechar) -> Unit,
#|) -> Unit {
#| if self.0.is_empty() {
#| f(lb, ub)
#| } else {
#| let last_stop = for stop in self.0; last_stop = lb {
#| if stop > ub {
#| break last_stop
#| }
#| if stop - 1 >= last_stop {
#| f(last_stop, stop - 1)
#| continue stop
#| } else {
#| continue last_stop
#| }
#| } nobreak {
#| last_stop
#| }
#| if ub >= last_stop {
#| f(last_stop, ub)
#| }
#| }
#|}
),
"table.mbt": (
#|struct Table(FixedArray[@shared_types.Rechar])
#|pub fn Table::map(
#| self : Table,
#| c : @shared_types.Rechar,
#|) -> @shared_types.Rechar {
#| if c < 128 {
#| self.0.unsafe_get(c)
#| } else {
#| let arr = self.0
#| let mut left = 0
#| let mut right = (arr.length() - 128) / 3 - 1
#| while left <= right {
#| let mid = left + (right - left) / 2
#| let entry_base = 128 + mid * 3
#| if c < arr[entry_base] {
#| right = mid - 1
#| } else if c > arr[entry_base + 1] {
#| left = mid + 1
#| } else {
#| return arr[entry_base + 2]
#| }
#| }
#| panic()
#| }
#|}
#|pub fn Table::map_set(
#| self : Table,
#| set : @shared_types.RecharSet,
#|) -> @shared_types.RecharSet {
#| set.offset_by(c => self.map(c))
#|}
),
"using.mbt": "",
},
)
///|
let moonbitlang_core_string_internal_regex_parser_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/string/internal/regex_parser",
deps={},
files={
"extends.mbt": (
#|pub extend ParserError with Show::{to_string}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ParserError with @debug.Debug::{to_repr}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend ParserError with Show::{output}
),
"parser.mbt": (
#|priv type Parser
#|priv enum CharOrClass {
#| Char(@re.Rechar)
#| Class(@re.RecharSet)
#|}
#|const MAX_QUANT = 256
#|fn Parser::class_atom(
#| rest : StringView,
#| ctx~ : ParserContext,
#|) -> (StringView, CharOrClass) raise ParserError {
#| lexmatch rest with longest {
#| (re"^\\[dDsSwW]", after=_) =>
#| raise ctx.error_at(rest, HINT_USE_POSIX_CHARACTER_CLASS)
#| (re"^\\b", after=rest) => (rest, Char('\b'))
#| (re"^\\f", after=rest) => (rest, Char('\f'))
#| (re"^\\n", after=rest) => (rest, Char('\n'))
#| (re"^\\r", after=rest) => (rest, Char('\r'))
#| (re"^\\t", after=rest) => (rest, Char('\t'))
#| (re"^\\x" + (re"[0-9A-Fa-f]{2}" as hex), after=rest) => {
#| if ctx.mode is String {
#| raise ctx.error_at(rest, HINT_BYTE_ESCAPE_NOT_ALLOWED)
#| }
#| (rest, Char(hex2i(hex)))
#| }
#| (re"^\\u" + (re"[0-9A-Fa-f]{4}" as hex), after=rest2) => {
#| if ctx.mode is Bytes {
#| raise ctx.error_at(rest, HINT_UNICODE_ESCAPE_NOT_ALLOWED)
#| }
#| let c = hex2i(hex)
#| guard ctx.profile.valid.contains(c) else {
#| raise ctx.error_at(rest, HINT_CHARACTER_OUT_OF_RANGE)
#| }
#| (rest2, Char(c))
#| }
#| (re"^\\u[{]" + (re"[0-9A-Fa-f]{1,6}" as hex) + re"[}]", after=rest) => {
#| if ctx.mode is Bytes {
#| raise ctx.error_at(rest, HINT_UNICODE_ESCAPE_NOT_ALLOWED)
#| }
#| let c = hex2i(hex)
#| guard ctx.profile.valid.contains(c) else {
#| raise ctx.error_at(rest, HINT_CHARACTER_OUT_OF_RANGE)
#| }
#| (rest, Char(c))
#| }
#| (re"^\\u", after=_) => raise ctx.error_at(rest, HINT_INVALID_ESCAPE)
#| (re"^\\" + (re"[\^$\\.*+?()\[\]{}|/\"\-:&]" as c), after=rest) =>
#| (rest, Char(c.to_int()))
#| (re"^\[:ascii:\]", after=rest) => (rest, Class(posix_cset_ascii))
#| (re"^\[:upper:\]", after=rest) => (rest, Class(posix_cset_upper))
#| (re"^\[:lower:\]", after=rest) => (rest, Class(posix_cset_lower))
#| (re"^\[:alpha:\]", after=rest) => (rest, Class(posix_cset_alpha))
#| (re"^\[:alnum:\]", after=rest) => (rest, Class(posix_cset_alnum))
#| (re"^\[:digit:\]", after=rest) => (rest, Class(posix_cset_digit))
#| (re"^\[:xdigit:\]", after=rest) => (rest, Class(posix_cset_xdigit))
#| (re"^\[:blank:\]", after=rest) => (rest, Class(posix_cset_blank))
#| (re"^\[:space:\]", after=rest) => (rest, Class(posix_cset_space))
#| (re"^\[:word:\]", after=rest) => (rest, Class(ctx.profile.word))
#| (re"^\[:[A-Za-z0-9_\-]+:\]", after=_) =>
#| raise ctx.error_at(rest, HINT_UNSUPPORTED_POSIX_CLASS)
#| (re"^\[:", after=_) => raise ctx.error_at(rest, HINT_INVALID_POSIX_CLASS)
#| (re"^." as c, after=rest) => {
#| guard ctx.profile.valid.contains(c.to_int()) else {
#| raise ctx.error_at(rest, HINT_CHARACTER_OUT_OF_RANGE)
#| }
#| (rest, Char(c.to_int()))
#| }
#| _ => panic()
#| }
#|}
#|fn Parser::class_contents(
#| rest : StringView,
#| ctx~ : ParserContext,
#|) -> (StringView, @re.RecharSet) raise ParserError {
#| outer~: for rest = rest, char_set = @re.RecharSet::empty() {
#| match rest {
#| [] => raise ctx.error_at(rest, HINT_UNCLOSED_CHAR_CLASS)
#| [']', ..] => break outer~ (rest, char_set)
#| _ => {
#| let (rest, left) = match rest {
#| ['[', ':', ..] =>
#| Parser::class_atom(rest, ctx~)
#| ['[', ..] =>
#| raise ctx.error_at(rest, HINT_UNSUPPORTED_NESTED_CHAR_CLASS)
#| _ => Parser::class_atom(rest, ctx~)
#| }
#| let (rest, left_set) = match left {
#| Char(c) =>
#| match rest {
#| ['-', '-', ..] =>
#| raise ctx.error_at(rest, HINT_UNSUPPORTED_CLASS_SET_EXPRESSION)
#| ['-', ']', ..] => raise ctx.error_at(rest, HINT_DASH_AT_BOUNDARY)
#| ['-', .. rest] => {
#| let (rest2, right) = Parser::class_atom(rest, ctx~)
#| match right {
#| Char(c2) => {
#| guard c <= c2 else {
#| raise ctx.error_at(rest, HINT_INVALID_CHAR_RANGE)
#| }
#| (rest2, @re.RecharSet::char_range(c, c2))
#| }
#| Class(_) =>
#| raise ctx.error_at(
#| rest,
#| offset=1,
#| HINT_CHAR_RANGE_OVER_SETS,
#| )
#| }
#| }
#| _ => (rest, @re.RecharSet::char(c))
#| }
#| Class(cs) => (rest, cs)
#| }
#| let char_set = char_set + left_set
#| match rest {
#| [.. "--", ..] =>
#| raise ctx.error_at(rest, HINT_UNSUPPORTED_CLASS_SET_EXPRESSION)
#| [.. "&&", ..] =>
#| raise ctx.error_at(rest, HINT_UNSUPPORTED_CLASS_SET_EXPRESSION)
#| _ => continue outer~ rest, char_set
#| }
#| }
#| }
#| }
#|}
#|fn Parser::character_class(
#| rest : StringView,
#| ctx~ : ParserContext,
#|) -> (StringView, @re.RecharSet) raise ParserError {
#| let (rest, neg) = match rest {
#| ['[', '^', .. rest] => (rest, true)
#| ['[', .. rest] => (rest, false)
#| _ => raise ctx.error_at(rest, HINT_UNEXPECTED_CHAR)
#| }
#| match rest {
#| ['-', ..] => raise ctx.error_at(rest, HINT_DASH_AT_BOUNDARY)
#| _ => ()
#| }
#| let (rest, char_set) = Parser::class_contents(rest, ctx~)
#| match rest {
#| [']', .. rest] =>
#| (
#| rest,
#| if neg {
#| ctx.profile.valid - char_set
#| } else {
#| char_set & ctx.profile.valid
#| },
#| )
#| [] => raise ctx.error_at(rest, HINT_UNCLOSED_CHAR_CLASS)
#| _ => panic()
#| }
#|}
#|fn Parser::quantifier_opt(
#| rest : StringView,
#| ctx~ : ParserContext,
#|) -> (StringView, @re.Quantifier?) raise ParserError {
#| let (rest, range) = lexmatch rest with longest {
#| (re"^\*", after=rest) => (rest, Some((0, None)))
#| (re"^\+", after=rest) => (rest, Some((1, None)))
#| (re"^\?", after=rest) => (rest, Some((0, Some(1))))
#| (re"^[{]" + (re"[0-9]+" as min) + re"[}]", after=rest) => {
#| let min = Parser::quant_bound(min, ctx~)
#| (rest, Some((min, Some(min))))
#| }
#| (re"^[{]" + (re"[0-9]+" as min) + re",[}]", after=rest) => {
#| let min = Parser::quant_bound(min, ctx~)
#| (rest, Some((min, None)))
#| }
#| (
#| re"^[{]" +
#| (re"[0-9]+" as min) +
#| re"," +
#| (re"[0-9]+" as max) +
#| re"[}]",
#| after=rest,
#| ) => {
#| let min = Parser::quant_bound(min, ctx~)
#| let max = Parser::quant_bound(max, ctx~)
#| guard min <= max else {
#| raise ctx.error_at(rest, HINT_INVALID_QUANTIFIER)
#| }
#| (rest, Some((min, Some(max))))
#| }
#| (re"^[{]", after=_) => raise ctx.error_at(rest, HINT_INVALID_QUANTIFIER)
#| _ => (rest, None)
#| }
#| match range {
#| Some((min, max)) => {
#| let rest0 = rest
#| let (rest, mode) = match rest {
#| ['?', .. rest] => (rest, @re.QuantifierMode::NonGreedy)
#| ['+', ..] =>
#| raise ctx.error_at(rest0, HINT_UNSUPPORTED_POSSESSIVE_QUANTIFIER)
#| _ => (rest, Greedy)
#| }
#| (rest, Some({ min, max, mode, }))
#| }
#| None => (rest, None)
#| }
#|}
#|fn Parser::quant_bound(
#| digits : StringView,
#| ctx~ : ParserContext,
#|) -> Int raise ParserError {
#| for c in digits; value = 0 {
#| let digit = c.to_int() - '0'
#| let next = value * 10 + digit
#| guard next <= MAX_QUANT else {
#| raise ctx.error_at(digits, HINT_QUANTIFIER_TOO_LARGE)
#| }
#| continue next
#| } nobreak {
#| value
#| }
#|}
#|fn Parser::term(
#| rest : StringView,
#| ctx~ : ParserContext,
#|) -> (StringView, @re.Pattern) raise ParserError {
#| let (rest, pat, is_assertion) = lexmatch rest with longest {
#| (re"^\^", after=rest) => (rest, @re.start_of_input, true)
#| (re"^\$", after=rest) => (rest, @re.end_of_input, true)
#| (re"^\\b", after=rest) =>
#| (rest, @re.alt([@re.start_of_word, @re.end_of_word]), true)
#| (re"^\\B", after=rest) => (rest, @re.not_word_boundary, true)
#| (re"^\\[dDsSwW]", after=_) =>
#| raise ctx.error_at(rest, HINT_USE_POSIX_CHARACTER_CLASS)
#| (re"^\\f", after=rest) => (rest, @re.char(@re.RecharSet::char('\f')), false)
#| (re"^\\n", after=rest) => (rest, @re.char(@re.RecharSet::char('\n')), false)
#| (re"^\\r", after=rest) => (rest, @re.char(@re.RecharSet::char('\r')), false)
#| (re"^\\t", after=rest) => (rest, @re.char(@re.RecharSet::char('\t')), false)
#| (re"^\\v", after=rest) =>
#| (rest, @re.char(@re.RecharSet::char('\u{0b}')), false)
#| (re"^\\x" + (re"[0-9A-Fa-f]{2}" as hex), after=rest) => {
#| if ctx.mode is String {
#| raise ctx.error_at(rest, HINT_BYTE_ESCAPE_NOT_ALLOWED)
#| }
#| (rest, @re.char(@re.RecharSet::char(hex2i(hex))), false)
#| }
#| (re"^\\u" + (re"[0-9A-Fa-f]{4}" as hex), after=rest) => {
#| if ctx.mode is Bytes {
#| raise ctx.error_at(rest, HINT_UNICODE_ESCAPE_NOT_ALLOWED)
#| }
#| let c = hex2i(hex)
#| guard ctx.profile.valid.contains(c) else {
#| raise ctx.error_at(rest, HINT_CHARACTER_OUT_OF_RANGE)
#| }
#| (rest, @re.char(@re.RecharSet::char(c)), false)
#| }
#| (re"^\\u[{]" + (re"[0-9A-Fa-f]{1,6}" as hex) + re"[}]", after=rest) => {
#| if ctx.mode is Bytes {
#| raise ctx.error_at(rest, HINT_UNICODE_ESCAPE_NOT_ALLOWED)
#| }
#| let c = hex2i(hex)
#| guard ctx.profile.valid.contains(c) else {
#| raise ctx.error_at(rest, HINT_CHARACTER_OUT_OF_RANGE)
#| }
#| (rest, @re.char(@re.RecharSet::char(c)), false)
#| }
#| (re"^\\u", after=_) => raise ctx.error_at(rest, HINT_INVALID_ESCAPE)
#| (re"^\\" + (re"[\^$\\.*+?()\[\]{}|/\"]" as c), after=rest) =>
#| (rest, @re.char(@re.RecharSet::char(c.to_int())), false)
#| (re"^\\.", after=_) => raise ctx.error_at(rest, HINT_INVALID_ESCAPE)
#| (re"^\.", after=rest) => (rest, @re.char(ctx.profile.valid), false)
#| (re"^\(\?=", after=_) =>
#| raise ctx.error_at(rest, HINT_UNSUPPORTED_LOOKAHEAD)
#| (re"^\(\?!", after=_) =>
#| raise ctx.error_at(rest, HINT_UNSUPPORTED_NEGATIVE_LOOKAHEAD)
#| (re"^\(\?<=", after=_) =>
#| raise ctx.error_at(rest, HINT_UNSUPPORTED_LOOKBEHIND)
#| (re"^\(\?
#| raise ctx.error_at(rest, HINT_UNSUPPORTED_NEGATIVE_LOOKBEHIND)
#| (re"^\(\?<" + (re"[A-Za-z_][A-Za-z0-9_]*" as name) + re">", after=rest) => {
#| let (rest, pat) = Parser::parse_group_continue(rest, ctx~)
#| (rest, @re.capture(name=name.to_owned(), pat), false)
#| }
#| (re"^\(\?:", after=rest) => {
#| let (rest, pat) = Parser::parse_group_continue(rest, ctx~)
#| (rest, pat, false)
#| }
#| (re"^\(\?<", after=_) => raise ctx.error_at(rest, HINT_INVALID_GROUP)
#| (re"^\(\?" + (re"[A-Za-z]+" as modifier) + re":", after=rest) =>
#| match modifier {
#| "i" => {
#| let need_process = !ctx.ignore_case
#| let (rest, pat) = Parser::parse_group_continue(rest, ctx={
#| ..ctx,
#| ignore_case: true,
#| })
#| (
#| rest,
#| if need_process {
#| pattern_map_char(pat, ignore_case)
#| } else {
#| pat
#| },
#| false,
#| )
#| }
#| _ => raise ctx.error_at(rest, HINT_INVALID_GROUP)
#| }
#| (re"^\(", after=rest) => {
#| let (rest, pat) = Parser::parse_group_continue(rest, ctx~)
#| (rest, @re.capture(pat), false)
#| }
#| (re"^\[:", after=_) => raise ctx.error_at(rest, HINT_BARE_POSIX_CLASS)
#| (re"^\[", after=_) => {
#| let (rest, char_set) = Parser::character_class(rest, ctx~)
#| (rest, @re.char(char_set), false)
#| }
#| (re"^[\^$\\.*+?()\[\]{}|]", after=_) =>
#| raise ctx.error_at(rest, HINT_UNEXPECTED_CHAR)
#| (re"^." as c, after=rest2) => {
#| guard ctx.profile.valid.contains(c.to_int()) else {
#| raise ctx.error_at(rest, HINT_CHARACTER_OUT_OF_RANGE)
#| }
#| (rest2, @re.char(@re.RecharSet::char(c.to_int())), false)
#| }
#| _ => raise ctx.error_at(rest, HINT_UNEXPECTED_CHAR)
#| }
#| if !is_assertion {
#| let (rest, quantifier) = Parser::quantifier_opt(rest, ctx~)
#| match quantifier {
#| Some(q) => (rest, @re.quantifier(pat, q))
#| None => (rest, pat)
#| }
#| } else {
#| (rest, pat)
#| }
#|}
#|fn Parser::alternative(
#| rest : StringView,
#| ctx~ : ParserContext,
#|) -> (StringView, @re.Pattern) raise ParserError {
#| let seq = []
#| let rest = for rest = rest {
#| match rest {
#| [] | ['|' | ')', ..] => break rest
#| _ => {
#| let (rest, pat) = Parser::term(rest, ctx~)
#| seq.push(pat)
#| continue rest
#| }
#| }
#| }
#| (rest, @re.seq(ReadOnlyArray::from_array(seq)))
#|}
#|fn Parser::parse_group_continue(
#| rest : StringView,
#| ctx~ : ParserContext,
#|) -> (StringView, @re.Pattern) raise ParserError {
#| let (rest, pat) = Parser::disjunction(rest, ctx~)
#| match rest {
#| [')', .. rest] => (rest, pat)
#| [] => raise ctx.error_at(rest, HINT_UNCLOSED_GROUP)
#| _ => raise ctx.error_at(rest, HINT_UNEXPECTED_CHAR)
#| }
#|}
#|fn Parser::disjunction(
#| rest : StringView,
#| ctx~ : ParserContext,
#|) -> (StringView, @re.Pattern) raise ParserError {
#| let alts = []
#| let (rest, alt) = Parser::alternative(rest, ctx~)
#| alts.push(alt)
#| let rest = for rest = rest {
#| match rest {
#| ['|', .. rest] => {
#| let (rest, pat) = Parser::alternative(rest, ctx~)
#| alts.push(pat)
#| continue rest
#| }
#| _ => break rest
#| }
#| }
#| (rest, @re.alt(ReadOnlyArray::from_array(alts)))
#|}
#|pub fn parse(
#| profile~ : @re.Profile,
#| mode~ : Mode,
#| pattern : StringView,
#|) -> @re.Pattern raise ParserError {
#| let ctx = ParserContext::new(profile~, base=pattern.start_offset(), mode~)
#| let (rest, pat) = Parser::disjunction(pattern, ctx~)
#| if !rest.is_empty() {
#| raise ctx.error_at(rest, HINT_UNEXPECTED_CHAR)
#| }
#| pat
#|}
),
"parser_context.mbt": (
#|pub(all) enum Mode {
#| Bytes
#| String
#|}
#|priv struct ParserContext {
#| profile : @re.Profile
#| base : Int
#| ignore_case : Bool
#| mode : Mode
#|}
#|fn ParserContext::new(
#| profile~ : @re.Profile,
#| base~ : Int,
#| mode~ : Mode,
#|) -> ParserContext {
#| { profile, base, ignore_case: false, mode, }
#|}
#|fn ParserContext::error_at(
#| self : ParserContext,
#| view : StringView,
#| hint : String,
#| offset? : Int = 0,
#|) -> ParserError {
#| ParserError(at=view.start_offset() - self.base + offset, hint~)
#|}
),
"parser_error.mbt": (
#|suberror ParserError {
#| ParserError(at~ : Int, hint~ : String)
#|} derive(@debug.Debug)
#|pub impl Show for ParserError with fn output(self, logger) {
#| match self {
#| ParserError(at~, hint~) =>
#| logger <+
#| $|ParserError at position \{at}: \{hint}
#| }
#|}
#|const HINT_UNCLOSED_CHAR_CLASS = "Unclosed character class"
#|const HINT_UNCLOSED_GROUP = "Unclosed group"
#|const HINT_UNEXPECTED_CHAR = "Unexpected character"
#|const HINT_QUANTIFIER_TOO_LARGE = "Quantifier too large"
#|const HINT_INVALID_QUANTIFIER = "Invalid quantifier"
#|const HINT_INVALID_ESCAPE = "Invalid escape sequence"
#|const HINT_UNICODE_ESCAPE_NOT_ALLOWED = "Unicode escape sequences are not allowed"
#|const HINT_BYTE_ESCAPE_NOT_ALLOWED = "Byte escape sequences are not allowed"
#|const HINT_CHARACTER_OUT_OF_RANGE = "Character out of range"
#|const HINT_INVALID_GROUP = "Invalid group"
#|const HINT_UNSUPPORTED_LOOKAHEAD = "Unsupported lookahead assertion"
#|const HINT_UNSUPPORTED_NEGATIVE_LOOKAHEAD = "Unsupported negative lookahead assertion"
#|const HINT_UNSUPPORTED_LOOKBEHIND = "Unsupported lookbehind assertion"
#|const HINT_UNSUPPORTED_NEGATIVE_LOOKBEHIND = "Unsupported negative lookbehind assertion"
#|const HINT_INVALID_POSIX_CLASS = "Invalid POSIX character class"
#|const HINT_BARE_POSIX_CLASS = "Invalid character class, bare POSIX character class not allowed"
#|const HINT_UNSUPPORTED_POSIX_CLASS = "Unsupported POSIX character class"
#|const HINT_CHAR_RANGE_OVER_SETS = "Character class range over sets"
#|const HINT_INVALID_CHAR_RANGE = "Invalid character class range"
#|const HINT_UNSUPPORTED_CLASS_SET_EXPRESSION = "Unsupported character class set expression"
#|const HINT_UNSUPPORTED_POSSESSIVE_QUANTIFIER = "Unsupported possessive quantifier"
#|const HINT_UNSUPPORTED_NESTED_CHAR_CLASS = "Unsupported nested character class"
#|const HINT_USE_POSIX_CHARACTER_CLASS = "Use POSIX character class instead of \\w, \\W, \\d, \\D, \\s, \\S"
#|const HINT_DASH_AT_BOUNDARY = "Dash at the start or end of character class is not supported, use \\- to match a literal dash"
),
"parser_util.mbt": (
#|fn hex2i(hex : StringView) -> Int {
#| for c in hex; value = 0 {
#| let value = value * 16
#| match c {
#| '0'..='9' => continue value + (c.to_int() - '0')
#| 'a'..='f' => continue value + (c.to_int() - 'a' + 10)
#| 'A'..='F' => continue value + (c.to_int() - 'A' + 10)
#| _ => panic()
#| }
#| } nobreak {
#| value
#| }
#|}
#|fn pattern_map_char(
#| pat : @re.Pattern,
#| f : (@re.RecharSet) -> @re.RecharSet,
#|) -> @re.Pattern {
#| match pat.desc {
#| Capture(name~, pat) => @re.capture(name?, pattern_map_char(pat, f))
#| Preference(pref, pat) => @re.preference(pref, pattern_map_char(pat, f))
#| Quantifier(quant, pat) => @re.quantifier(pattern_map_char(pat, f), quant)
#| Alternation(pats) => @re.alt(pats.map(p => pattern_map_char(p, f)))
#| Sequence(pats) => @re.seq(pats.map(p => pattern_map_char(p, f)))
#| Char(c) => @re.char(f(c))
#| Assertion(a) => @re.assertion(a)
#| }
#|}
#|fn ignore_case(cs : @re.RecharSet) -> @re.RecharSet {
#| cs +
#| (cs & @re.RecharSet::char_range('A', 'Z')).offset_by(it => it + 32) +
#| (cs & @re.RecharSet::char_range('a', 'z')).offset_by(it => it - 32)
#|}
#|let posix_cset_ascii : @re.RecharSet = @re.RecharSet::char_range(0, 0x7f)
#|let posix_cset_upper : @re.RecharSet = @re.RecharSet::char_range('A', 'Z')
#|let posix_cset_lower : @re.RecharSet = @re.RecharSet::char_range('a', 'z')
#|let posix_cset_alpha : @re.RecharSet = posix_cset_upper + posix_cset_lower
#|let posix_cset_digit : @re.RecharSet = @re.RecharSet::char_range('0', '9')
#|let posix_cset_xdigit : @re.RecharSet = posix_cset_digit +
#| @re.RecharSet::char_range('a', 'f') +
#| @re.RecharSet::char_range('A', 'F')
#|let posix_cset_alnum : @re.RecharSet = posix_cset_alpha + posix_cset_digit
#|let posix_cset_space : @re.RecharSet = @re.RecharSet::char(' ') +
#| @re.RecharSet::char('\t') +
#| @re.RecharSet::char('\n') +
#| @re.RecharSet::char('\r') +
#| @re.RecharSet::char('\u{000B}') +
#| @re.RecharSet::char('\f')
#|let posix_cset_blank : @re.RecharSet = @re.RecharSet::char(' ') +
#| @re.RecharSet::char('\t')
),
"using.mbt": "",
},
)
///|
let moonbitlang_core_test_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/test",
deps={},
files={
"extends.mbt": (
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Test with @debug.Debug::{to_repr}
),
"test.mbt": (
#|fn[T : Show] debug_string(t : T) -> String {
#| let buf = StringBuilder(size_hint=50)
#| t.output(buf)
#| buf.to_string()
#|}
#|pub using @debug {assert_eq}
#|#callsite(autofill(loc))
#|pub fn[T : Eq + @debug.Debug] assert_not_eq(
#| a : T,
#| b : T,
#| msg? : String,
#| loc~ : SourceLoc,
#|) -> Unit raise {
#| if !(a != b) {
#| let fail_msg = match msg {
#| Some(msg)
#| | (None with msg = "`\{@debug.to_string(a)} == \{@debug.to_string(b)}`") =>
#| msg
#| }
#| fail(fail_msg, loc~)
#| }
#|}
#|#deprecated("use `@test.assert_same_object` instead", skip_current_package=true)
#|#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 : @debug.Debug] assert_same_object(
#| a : T,
#| b : T,
#| loc~ : SourceLoc,
#|) -> Unit raise {
#| if !physical_equal(a, b) {
#| let a = @debug.to_string(a)
#| let b = @debug.to_string(b)
#| fail("`\{a} is \{b}`", loc~)
#| }
#|}
#|#deprecated("use `@test.assert_not_same_object` instead", skip_current_package=true)
#|#callsite(autofill(loc))
#|#alias(is_not, deprecated)
#|pub fn[T : Show] not_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 : @debug.Debug] assert_not_same_object(
#| a : T,
#| b : T,
#| loc~ : SourceLoc,
#|) -> Unit raise {
#| if physical_equal(a, b) {
#| let a = @debug.to_string(a)
#| let b = @debug.to_string(b)
#| fail("`!(\{a} is \{b})`", loc~)
#| }
#|}
#|#callsite(autofill(loc))
#|pub fn[T] fail(msg : StringView, loc~ : SourceLoc) -> T raise {
#| @builtin.fail(msg, loc~)
#|}
#|#callsite(autofill(loc))
#|pub fn[T, E : Error] assert_raise(
#| f : () -> T raise E,
#| loc~ : SourceLoc,
#|) -> Unit raise {
#| try f() catch {
#| _ => ()
#| } noraise {
#| _ =>
#| @builtin.fail(
#| "expected error, but program succeed without raising anything",
#| loc~,
#| )
#| }
#|}
#|#callsite(autofill(loc))
#|pub fn[T, E : Error] expect_error(
#| f : () -> T raise E,
#| loc~ : SourceLoc,
#|) -> E raise {
#| try f() catch {
#| err => err
#| } noraise {
#| _ =>
#| @builtin.fail(
#| "expected error, but program succeed without raising anything",
#| loc~,
#| )
#| }
#|}
#|pub fn Test::write(self : Test, obj : &Show) -> Unit {
#| self.buffer.write_string(obj.to_string())
#|}
#|pub fn Test::writeln(self : Test, obj : &Show) -> Unit {
#| self.write(obj)
#| self.buffer.write_char('\n')
#|}
#|#callsite(autofill(args_loc, loc))
#|pub fn Test::snapshot(
#| self : Test,
#| filename~ : String,
#| loc~ : SourceLoc,
#| args_loc~ : ArgsLoc,
#|) -> Unit raise SnapshotError {
#| let loc = loc.to_json_string()
#| let args_loc = args_loc.to_json()
#| 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}
#| ),
#| )
#|}
#|pub fn Test::name(self : Self) -> String {
#| self.name
#|}
),
"types.mbt": (
#|struct Test {
#| name : String
#| buffer : StringBuilder
#|} derive(@debug.Debug)
#|#alias(new, deprecated="Use `Test()` instead")
#|#as_free_fn
#|#as_free_fn(new, deprecated="Use `Test()` instead")
#|pub fn Test::Test(name : String) -> Test {
#| { name, buffer: StringBuilder(), }
#|}
),
},
)
///|
let moonbitlang_core_tuple_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/tuple",
deps={},
files={
"extends.mbt": (
#|type Tuple2[A, B] = (A, B)
#|type Tuple3[A, B, C] = (A, B, C)
#|type Tuple4[A, B, C, D] = (A, B, C, D)
#|type Tuple5[A, B, C, D, E] = (A, B, C, D, E)
#|type Tuple6[A, B, C, D, E, F] = (A, B, C, D, E, F)
#|type Tuple7[A, B, C, D, E, F, G] = (A, B, C, D, E, F, G)
#|type Tuple8[A, B, C, D, E, F, G, H] = (A, B, C, D, E, F, G, H)
#|type Tuple9[A, B, C, D, E, F, G, H, I] = (A, B, C, D, E, F, G, H, I)
#|type Tuple10[A, B, C, D, E, F, G, H, I, J] = (A, B, C, D, E, F, G, H, I, J)
#|type Tuple11[A, B, C, D, E, F, G, H, I, J, K] = (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#| H,
#| I,
#| J,
#| K,
#|)
#|type Tuple12[A, B, C, D, E, F, G, H, I, J, K, L] = (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#| H,
#| I,
#| J,
#| K,
#| L,
#|)
#|type Tuple13[A, B, C, D, E, F, G, H, I, J, K, L, M] = (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#| H,
#| I,
#| J,
#| K,
#| L,
#| M,
#|)
#|type Tuple14[A, B, C, D, E, F, G, H, I, J, K, L, M, N] = (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#| H,
#| I,
#| J,
#| K,
#| L,
#| M,
#| N,
#|)
#|type Tuple15[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O] = (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#| H,
#| I,
#| J,
#| K,
#| L,
#| M,
#| N,
#| O,
#|)
#|type Tuple16[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P] = (
#| A,
#| B,
#| C,
#| D,
#| E,
#| F,
#| G,
#| H,
#| I,
#| J,
#| K,
#| L,
#| M,
#| N,
#| O,
#| P,
#|)
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple10 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple11 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple12 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple13 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple14 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple15 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple16 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple2 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple3 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple4 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple5 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple6 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple7 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple8 with Default::{default}
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend Tuple9 with Default::{default}
),
"tuple_default.mbt": (
#|pub impl[A : Default, B : Default] Default for (A, B) with fn default() {
#| (Default::default(), Default::default())
#|}
#|pub impl[A : Default, B : Default, C : Default] Default for (A, B, C) with fn default() {
#| (Default::default(), Default::default(), Default::default())
#|}
#|pub impl[A : Default, B : Default, C : Default, D : Default] Default for (
#| A,
#| B,
#| C,
#| D,
#|) with fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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 fn 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={},
files={
"extends.mbt": (
#|#deprecated("Use `Default::default` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend UInt with Default::{default}
),
"uint.mbt": (
#|pub const MIN_VALUE : UInt = 0U
#|#deprecated("Use `MIN_VALUE` instead")
#|pub let min_value : UInt = 0U
#|pub const MAX_VALUE : UInt = 4294967295U
#|#deprecated("Use `MAX_VALUE` instead")
#|pub let max_value : UInt = 4294967295U
#|pub fn UInt::to_int64(self : UInt) -> Int64 {
#| self.to_uint64().reinterpret_as_int64()
#|}
#|pub impl Default for UInt with fn default() {
#| 0
#|}
#|pub fn default() -> UInt {
#| 0
#|}
#|#deprecated
#|#doc(hidden)
#|pub fn UInt::to_be_bytes(self : UInt) -> Bytes {
#| [
#| (self >> 24).to_byte(),
#| (self >> 16).to_byte(),
#| (self >> 8).to_byte(),
#| self.to_byte(),
#| ]
#|}
#|#deprecated
#|#doc(hidden)
#|pub fn UInt::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={},
files={
"uint16.mbt": (
#|pub const MAX_VALUE : UInt16 = 65535
#|#deprecated("Use `MAX_VALUE` instead")
#|pub let max_value : UInt16 = 65535
#|pub const MIN_VALUE : UInt16 = 0
#|#deprecated("Use `MIN_VALUE` instead")
#|pub let min_value : UInt16 = 0
#|#deprecated("Use `Int16::reinterpret_from_uint16` instead")
#|pub fn UInt16::reinterpret_as_int16(self : UInt16) -> Int16 {
#| Int16::from_int(self.to_int())
#|}
),
},
)
///|
let moonbitlang_core_uint64_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/uint64",
deps={},
files={
"uint64.mbt": (
#|pub const MIN_VALUE : UInt64 = 0UL
#|#deprecated("Use `MIN_VALUE` instead")
#|pub let min_value : UInt64 = 0UL
#|pub const MAX_VALUE : UInt64 = 18446744073709551615UL
#|#deprecated("Use `MAX_VALUE` instead")
#|pub let max_value : UInt64 = 18446744073709551615UL
),
},
)
///|
let moonbitlang_core_unit_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/unit",
deps={},
files={
"unit.mbt": (
#|#deprecated("Use `()` instead")
#|pub fn default() -> Unit {
#| ()
#|}
),
},
)
///|
let moonbitlang_core_v128_module : RuntimePackage = RuntimePackage::new(
"moonbitlang/core/v128",
deps={},
files={
"extends.mbt": (
#|pub extend V128 with Eq::{equal}
#|pub extend V128 with Show::{to_string}
#|#deprecated("Use `Debug::to_repr` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend V128 with @debug.Debug::{to_repr}
#|#deprecated("Use `!=` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend V128 with Eq::{not_equal}
#|#deprecated("Use `Show::output` via the trait or `to_string` instead", skip_current_package=true)
#|#doc(hidden)
#|pub extend V128 with Show::{output}
),
"lanes.mbt": (
#|fn u8_lane(value : V128, lane : Int) -> Byte {
#| let word = if lane < 8 { lo(value) } else { hi(value) }
#| ((word >> (lane % 8 * 8)) & 0xffUL).to_byte()
#|}
#|fn u16_lane(value : V128, lane : Int) -> UInt16 {
#| let word = if lane < 4 { lo(value) } else { hi(value) }
#| ((word >> (lane % 4 * 16)) & 0xffffUL).to_uint16()
#|}
#|fn u32_lane(value : V128, lane : Int) -> UInt {
#| let word = if lane < 2 { lo(value) } else { hi(value) }
#| ((word >> (lane % 2 * 32)) & 0xffffffffUL).to_uint()
#|}
#|fn u64_lane(value : V128, lane : Int) -> UInt64 {
#| if lane == 0 {
#| lo(value)
#| } else {
#| hi(value)
#| }
#|}
#|fn pack_u8x16_by(f : (Int) -> Byte) -> V128 {
#| let mut lo_word = 0UL
#| for i in 0..<8 {
#| lo_word = lo_word | (f(i).to_uint64() << (i * 8))
#| }
#| let mut hi_word = 0UL
#| for i in 0..<8 {
#| hi_word = hi_word | (f(i + 8).to_uint64() << (i * 8))
#| }
#| make(lo_word, hi_word)
#|}
#|fn pack_u16x8_by(f : (Int) -> UInt16) -> V128 {
#| let mut lo_word = 0UL
#| for i in 0..<4 {
#| lo_word = lo_word | (f(i).to_uint64() << (i * 16))
#| }
#| let mut hi_word = 0UL
#| for i in 0..<4 {
#| hi_word = hi_word | (f(i + 4).to_uint64() << (i * 16))
#| }
#| make(lo_word, hi_word)
#|}
#|fn pack_u32x4_by(f : (Int) -> UInt) -> V128 {
#| make(
#| f(0).to_uint64() | (f(1).to_uint64() << 32),
#| f(2).to_uint64() | (f(3).to_uint64() << 32),
#| )
#|}
#|fn pack_u64x2_by(f : (Int) -> UInt64) -> V128 {
#| make(f(0), f(1))
#|}
#|fn widen_u8x4_to_u16x4(value : UInt64) -> UInt64 {
#| (value & 0xffUL) |
#| ((value & 0xff00UL) << 8) |
#| ((value & 0xff0000UL) << 16) |
#| ((value & 0xff000000UL) << 24)
#|}
#|fn sign_extend_u8x4_to_u16x4(value : UInt64) -> UInt64 {
#| let value = widen_u8x4_to_u16x4(value)
#| value | (((value & 0x0080008000800080UL) << 1) * 0xffUL)
#|}
#|fn widen_u16x2_to_u32x2(value : UInt64) -> UInt64 {
#| (value & 0xffffUL) | ((value & 0xffff0000UL) << 16)
#|}
#|fn sign_extend_u16x2_to_u32x2(value : UInt64) -> UInt64 {
#| let value = widen_u16x2_to_u32x2(value)
#| value | (((value & 0x0000800000008000UL) << 1) * 0xffffUL)
#|}
#|fn sign_extend_u32_to_u64(value : UInt64) -> UInt64 {
#| let value = value & 0xffffffffUL
#| if (value & 0x80000000UL) != 0UL {
#| value | 0xffffffff00000000UL
#| } else {
#| value
#| }
#|}
#|fn i8_signed(value : Byte) -> Int {
#| let value = value.to_int()
#| if value >= 128 {
#| value - 256
#| } else {
#| value
#| }
#|}
#|fn i16_signed(value : UInt16) -> Int {
#| Int16::reinterpret_from_uint16(value).to_int()
#|}
#|fn bool_to_u8_mask(value : Bool) -> Byte {
#| if value {
#| 0xff
#| } else {
#| 0
#| }
#|}
#|fn bool_to_u16_mask(value : Bool) -> UInt16 {
#| if value {
#| 0xffff
#| } else {
#| 0
#| }
#|}
#|fn bool_to_u32_mask(value : Bool) -> UInt {
#| if value {
#| 0xffffffff
#| } else {
#| 0
#| }
#|}
#|fn bool_to_u64_mask(value : Bool) -> UInt64 {
#| if value {
#| 0xffffffffffffffffUL
#| } else {
#| 0UL
#| }
#|}
#|fn i8_abs(value : Byte) -> Byte {
#| let value = i8_signed(value)
#| if value < 0 {
#| (-value).to_byte()
#| } else {
#| value.to_byte()
#| }
#|}
#|fn i16_abs(value : UInt16) -> UInt16 {
#| Int16::abs(Int16::reinterpret_from_uint16(value)).reinterpret_as_uint16()
#|}
#|fn i8_add_sat_s(a : Byte, b : Byte) -> Byte {
#| let sum = i8_signed(a) + i8_signed(b)
#| if sum > 127 {
#| 0x7f
#| } else if sum < -128 {
#| 0x80
#| } else {
#| sum.to_byte()
#| }
#|}
#|fn i8_add_sat_u(a : Byte, b : Byte) -> Byte {
#| let sum = a.to_uint() + b.to_uint()
#| if sum > 255 {
#| 0xff
#| } else {
#| sum.to_byte()
#| }
#|}
#|fn i8_sub_sat_s(a : Byte, b : Byte) -> Byte {
#| let diff = i8_signed(a) - i8_signed(b)
#| if diff > 127 {
#| 0x7f
#| } else if diff < -128 {
#| 0x80
#| } else {
#| diff.to_byte()
#| }
#|}
#|fn i8_sub_sat_u(a : Byte, b : Byte) -> Byte {
#| if a < b {
#| 0
#| } else {
#| a - b
#| }
#|}
#|fn i8_min_s(a : Byte, b : Byte) -> Byte {
#| if i8_signed(a) < i8_signed(b) {
#| a
#| } else {
#| b
#| }
#|}
#|fn i8_max_s(a : Byte, b : Byte) -> Byte {
#| if i8_signed(a) > i8_signed(b) {
#| a
#| } else {
#| b
#| }
#|}
#|fn i8_avgr_u(a : Byte, b : Byte) -> Byte {
#| ((a.to_uint() + b.to_uint() + 1) / 2).to_byte()
#|}
#|fn i16_add_sat_s(a : UInt16, b : UInt16) -> UInt16 {
#| let sum = i16_signed(a) + i16_signed(b)
#| if sum > 32767 {
#| 0x7fff
#| } else if sum < -32768 {
#| 0x8000
#| } else {
#| sum.to_uint16()
#| }
#|}
#|fn i16_add_sat_u(a : UInt16, b : UInt16) -> UInt16 {
#| let sum = a.to_uint() + b.to_uint()
#| if sum > 65535 {
#| 0xffff
#| } else {
#| sum.to_uint16()
#| }
#|}
#|fn i16_sub_sat_s(a : UInt16, b : UInt16) -> UInt16 {
#| let diff = i16_signed(a) - i16_signed(b)
#| if diff > 32767 {
#| 0x7fff
#| } else if diff < -32768 {
#| 0x8000
#| } else {
#| diff.to_uint16()
#| }
#|}
#|fn i16_sub_sat_u(a : UInt16, b : UInt16) -> UInt16 {
#| if a < b {
#| 0
#| } else {
#| a - b
#| }
#|}
#|fn i16_min_s(a : UInt16, b : UInt16) -> UInt16 {
#| if i16_signed(a) < i16_signed(b) {
#| a
#| } else {
#| b
#| }
#|}
#|fn i16_max_s(a : UInt16, b : UInt16) -> UInt16 {
#| if i16_signed(a) > i16_signed(b) {
#| a
#| } else {
#| b
#| }
#|}
#|fn i16_avgr_u(a : UInt16, b : UInt16) -> UInt16 {
#| ((a.to_uint() + b.to_uint() + 1) / 2).to_uint16()
#|}
),
"simd_basic.mbt": (
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub impl Eq for V128 with fn equal(self : V128, other : V128) -> Bool {
#| lo(self) == lo(other) && hi(self) == hi(other)
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub impl Eq for V128 with fn not_equal(self : V128, other : V128) -> Bool {
#| lo(self) != lo(other) || hi(self) != hi(other)
#|}
#|fn u64_hex_to(logger : &Logger, value : UInt64) -> Unit {
#| let digits = value.to_string(radix=16)
#| logger <+ "0x"
#| for _ in digits.length()..<16 {
#| logger.write_char('0')
#| }
#| logger.write_string(digits)
#|}
#|fn u64_hex(value : UInt64) -> String {
#| let buf = StringBuilder()
#| u64_hex_to(buf, value)
#| buf.to_string()
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub impl Show for V128 with fn output(self : V128, logger) {
#| logger <+
#| "V128(\{cb => u64_hex_to(cb, lo(self))}, \{cb => u64_hex_to(cb, hi(self))})"
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub impl @debug.Debug for V128 with fn to_repr(self) {
#| @debug.Repr::opaque_(
#| "V128",
#| @debug.Repr::tuple([
#| @debug.Repr::literal(u64_hex(lo(self))),
#| @debug.Repr::literal(u64_hex(hi(self))),
#| ]),
#| )
#|}
#|#intrinsic("%v128.v128_const_i8x16")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_const(
#| a0 : Byte,
#| a1 : Byte,
#| a2 : Byte,
#| a3 : Byte,
#| a4 : Byte,
#| a5 : Byte,
#| a6 : Byte,
#| a7 : Byte,
#| a8 : Byte,
#| a9 : Byte,
#| a10 : Byte,
#| a11 : Byte,
#| a12 : Byte,
#| a13 : Byte,
#| a14 : Byte,
#| a15 : Byte,
#|) -> V128 {
#| make(
#| a0.to_uint64() |
#| (a1.to_uint64() << 8) |
#| (a2.to_uint64() << 16) |
#| (a3.to_uint64() << 24) |
#| (a4.to_uint64() << 32) |
#| (a5.to_uint64() << 40) |
#| (a6.to_uint64() << 48) |
#| (a7.to_uint64() << 56),
#| a8.to_uint64() |
#| (a9.to_uint64() << 8) |
#| (a10.to_uint64() << 16) |
#| (a11.to_uint64() << 24) |
#| (a12.to_uint64() << 32) |
#| (a13.to_uint64() << 40) |
#| (a14.to_uint64() << 48) |
#| (a15.to_uint64() << 56),
#| )
#|}
#|#intrinsic("%v128.v128_const_i16x8")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_const(
#| a0 : UInt16,
#| a1 : UInt16,
#| a2 : UInt16,
#| a3 : UInt16,
#| a4 : UInt16,
#| a5 : UInt16,
#| a6 : UInt16,
#| a7 : UInt16,
#|) -> V128 {
#| make(
#| a0.to_uint64() |
#| (a1.to_uint64() << 16) |
#| (a2.to_uint64() << 32) |
#| (a3.to_uint64() << 48),
#| a4.to_uint64() |
#| (a5.to_uint64() << 16) |
#| (a6.to_uint64() << 32) |
#| (a7.to_uint64() << 48),
#| )
#|}
#|#intrinsic("%v128.v128_const_i32x4")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_const(a0 : UInt, a1 : UInt, a2 : UInt, a3 : UInt) -> V128 {
#| make(
#| a0.to_uint64() | (a1.to_uint64() << 32),
#| a2.to_uint64() | (a3.to_uint64() << 32),
#| )
#|}
#|#intrinsic("%v128.v128_const_i64x2")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_const(a0 : UInt64, a1 : UInt64) -> V128 {
#| make(a0, a1)
#|}
#|#intrinsic("%v128.v128_const_f32x4")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_const(a0 : Float, a1 : Float, a2 : Float, a3 : Float) -> V128 {
#| i32x4_const(
#| a0.reinterpret_as_uint(),
#| a1.reinterpret_as_uint(),
#| a2.reinterpret_as_uint(),
#| a3.reinterpret_as_uint(),
#| )
#|}
#|#intrinsic("%v128.v128_const_f64x2")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_const(a0 : Double, a1 : Double) -> V128 {
#| i64x2_const(a0.reinterpret_as_uint64(), a1.reinterpret_as_uint64())
#|}
#|#intrinsic("%v128.i8x16_splat")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_splat(value : Byte) -> V128 {
#| pack_u8x16_by(_ => value)
#|}
#|#intrinsic("%v128.i16x8_splat")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_splat(value : UInt16) -> V128 {
#| pack_u16x8_by(_ => value)
#|}
#|#intrinsic("%v128.i32x4_splat")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_splat(value : UInt) -> V128 {
#| pack_u32x4_by(_ => value)
#|}
#|#intrinsic("%v128.i64x2_splat")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_splat(value : UInt64) -> V128 {
#| make(value, value)
#|}
#|#intrinsic("%v128.f32x4_splat")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_splat(value : Float) -> V128 {
#| f32x4_const(value, value, value, value)
#|}
#|#intrinsic("%v128.f64x2_splat")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_splat(value : Double) -> V128 {
#| f64x2_const(value, value)
#|}
#|#intrinsic("%v128.i8x16_extract_lane_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_extract_lane_u(value : V128, lane : Int) -> UInt {
#| u8_lane(value, lane).to_uint()
#|}
#|#intrinsic("%v128.i8x16_extract_lane_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_extract_lane_s(value : V128, lane : Int) -> UInt {
#| i8_signed(u8_lane(value, lane)).reinterpret_as_uint()
#|}
#|#intrinsic("%v128.i16x8_extract_lane_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_extract_lane_u(value : V128, lane : Int) -> UInt {
#| u16_lane(value, lane).to_uint()
#|}
#|#intrinsic("%v128.i16x8_extract_lane_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_extract_lane_s(value : V128, lane : Int) -> UInt {
#| i16_signed(u16_lane(value, lane)).reinterpret_as_uint()
#|}
#|#intrinsic("%v128.i32x4_extract_lane")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_extract_lane(value : V128, lane : Int) -> UInt {
#| u32_lane(value, lane)
#|}
#|#intrinsic("%v128.i64x2_extract_lane")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_extract_lane(value : V128, lane : Int) -> UInt64 {
#| u64_lane(value, lane)
#|}
#|#intrinsic("%v128.f32x4_extract_lane")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_extract_lane(value : V128, lane : Int) -> Float {
#| Float::reinterpret_from_uint(u32_lane(value, lane))
#|}
#|#intrinsic("%v128.f64x2_extract_lane")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_extract_lane(value : V128, lane : Int) -> Double {
#| u64_lane(value, lane).reinterpret_as_double()
#|}
#|#intrinsic("%v128.i8x16_replace_lane")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_replace_lane(value : V128, replacement : UInt, lane : Int) -> V128 {
#| guard lane >= 0 && lane < 16 else { return value }
#| let shift = (lane & 7) * 8
#| let mask = 0xffUL << shift
#| let bits = (replacement.to_uint64() & 0xffUL) << shift
#| if lane < 8 {
#| make((lo(value) & mask.lnot()) | bits, hi(value))
#| } else {
#| make(lo(value), (hi(value) & mask.lnot()) | bits)
#| }
#|}
#|#intrinsic("%v128.i16x8_replace_lane")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_replace_lane(value : V128, replacement : UInt, lane : Int) -> V128 {
#| guard lane >= 0 && lane < 8 else { return value }
#| let shift = (lane & 3) * 16
#| let mask = 0xffffUL << shift
#| let bits = (replacement.to_uint64() & 0xffffUL) << shift
#| if lane < 4 {
#| make((lo(value) & mask.lnot()) | bits, hi(value))
#| } else {
#| make(lo(value), (hi(value) & mask.lnot()) | bits)
#| }
#|}
#|#intrinsic("%v128.i32x4_replace_lane")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_replace_lane(value : V128, replacement : UInt, lane : Int) -> V128 {
#| guard lane >= 0 && lane < 4 else { return value }
#| let shift = (lane & 1) * 32
#| let mask = 0xffffffffUL << shift
#| let bits = replacement.to_uint64() << shift
#| if lane < 2 {
#| make((lo(value) & mask.lnot()) | bits, hi(value))
#| } else {
#| make(lo(value), (hi(value) & mask.lnot()) | bits)
#| }
#|}
#|#intrinsic("%v128.i64x2_replace_lane")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_replace_lane(
#| value : V128,
#| replacement : UInt64,
#| lane : Int,
#|) -> V128 {
#| if lane == 0 {
#| make(replacement, hi(value))
#| } else if lane == 1 {
#| make(lo(value), replacement)
#| } else {
#| value
#| }
#|}
#|#intrinsic("%v128.f32x4_replace_lane")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_replace_lane(
#| value : V128,
#| replacement : Float,
#| lane : Int,
#|) -> V128 {
#| i32x4_replace_lane(value, replacement.reinterpret_as_uint(), lane)
#|}
#|#intrinsic("%v128.f64x2_replace_lane")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_replace_lane(
#| value : V128,
#| replacement : Double,
#| lane : Int,
#|) -> V128 {
#| i64x2_replace_lane(value, replacement.reinterpret_as_uint64(), lane)
#|}
#|#intrinsic("%v128.v128_not")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_not(value : V128) -> V128 {
#| make(lo(value).lnot(), hi(value).lnot())
#|}
#|#intrinsic("%v128.v128_and")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_and_(value : V128, other : V128) -> V128 {
#| make(lo(value) & lo(other), hi(value) & hi(other))
#|}
#|#intrinsic("%v128.v128_or")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_or_(value : V128, other : V128) -> V128 {
#| make(lo(value) | lo(other), hi(value) | hi(other))
#|}
#|#intrinsic("%v128.v128_xor")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_xor(value : V128, other : V128) -> V128 {
#| make(lo(value) ^ lo(other), hi(value) ^ hi(other))
#|}
#|#intrinsic("%v128.v128_andnot")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_andnot(value : V128, other : V128) -> V128 {
#| v128_and_(value, v128_not(other))
#|}
#|#intrinsic("%v128.v128_bitselect")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_bitselect(value : V128, other : V128, mask : V128) -> V128 {
#| v128_or_(v128_and_(value, mask), v128_andnot(other, mask))
#|}
#|#intrinsic("%v128.v128_any_true")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_any_true(value : V128) -> Bool {
#| lo(value) != 0UL || hi(value) != 0UL
#|}
),
"simd_float.mbt": (
#|fn pack_f32x4_by(f : (Int) -> Float) -> V128 {
#| pack_u32x4_by(i => f(i).reinterpret_as_uint())
#|}
#|fn pack_f64x2_by(f : (Int) -> Double) -> V128 {
#| pack_u64x2_by(i => f(i).reinterpret_as_uint64())
#|}
#|fn f32x4_map(value : V128, f : (Float) -> Float) -> V128 {
#| pack_f32x4_by(i => f(f32x4_extract_lane(value, i)))
#|}
#|fn f64x2_map(value : V128, f : (Double) -> Double) -> V128 {
#| pack_f64x2_by(i => f(f64x2_extract_lane(value, i)))
#|}
#|fn f32x4_zip(value : V128, other : V128, f : (Float, Float) -> Float) -> V128 {
#| pack_f32x4_by(i => {
#| f(f32x4_extract_lane(value, i), f32x4_extract_lane(other, i))
#| })
#|}
#|fn f64x2_zip(
#| value : V128,
#| other : V128,
#| f : (Double, Double) -> Double,
#|) -> V128 {
#| pack_f64x2_by(i => {
#| f(f64x2_extract_lane(value, i), f64x2_extract_lane(other, i))
#| })
#|}
#|fn f32x4_compare(
#| value : V128,
#| other : V128,
#| f : (Float, Float) -> Bool,
#|) -> V128 {
#| pack_u32x4_by(i => {
#| bool_to_u32_mask(
#| f(f32x4_extract_lane(value, i), f32x4_extract_lane(other, i)),
#| )
#| })
#|}
#|fn f64x2_compare(
#| value : V128,
#| other : V128,
#| f : (Double, Double) -> Bool,
#|) -> V128 {
#| pack_u64x2_by(i => {
#| bool_to_u64_mask(
#| f(f64x2_extract_lane(value, i), f64x2_extract_lane(other, i)),
#| )
#| })
#|}
#|fn f32_nearest_even(value : Float) -> Float {
#| if value.is_nan() || value.is_inf() || value == 0.0F {
#| value
#| } else {
#| let down = value.floor()
#| let up = value.ceil()
#| let down_delta = value - down
#| let up_delta = up - value
#| if down_delta < up_delta {
#| down
#| } else if down_delta > up_delta {
#| up
#| } else if (down / 2.0F).trunc() * 2.0F == down {
#| down
#| } else {
#| up
#| }
#| }
#|}
#|fn f64_nearest_even(value : Double) -> Double {
#| if value.is_nan() || value.is_inf() || value == 0.0 {
#| value
#| } else {
#| let down = value.floor()
#| let up = value.ceil()
#| let down_delta = value - down
#| let up_delta = up - value
#| if down_delta < up_delta {
#| down
#| } else if down_delta > up_delta {
#| up
#| } else if (down / 2.0).trunc() * 2.0 == down {
#| down
#| } else {
#| up
#| }
#| }
#|}
#|fn f32_min(value : Float, other : Float) -> Float {
#| if value.is_nan() {
#| value
#| } else if other.is_nan() {
#| other
#| } else if value == other {
#| Float::reinterpret_from_uint(
#| value.reinterpret_as_uint() | other.reinterpret_as_uint(),
#| )
#| } else if value < other {
#| value
#| } else {
#| other
#| }
#|}
#|fn f32_max(value : Float, other : Float) -> Float {
#| if value.is_nan() {
#| value
#| } else if other.is_nan() {
#| other
#| } else if value == other {
#| Float::reinterpret_from_uint(
#| value.reinterpret_as_uint() & other.reinterpret_as_uint(),
#| )
#| } else if value > other {
#| value
#| } else {
#| other
#| }
#|}
#|fn f64_min(value : Double, other : Double) -> Double {
#| if value.is_nan() {
#| value
#| } else if other.is_nan() {
#| other
#| } else if value == other {
#| (value.reinterpret_as_uint64() | other.reinterpret_as_uint64()).reinterpret_as_double()
#| } else if value < other {
#| value
#| } else {
#| other
#| }
#|}
#|fn f64_max(value : Double, other : Double) -> Double {
#| if value.is_nan() {
#| value
#| } else if other.is_nan() {
#| other
#| } else if value == other {
#| (value.reinterpret_as_uint64() & other.reinterpret_as_uint64()).reinterpret_as_double()
#| } else if value > other {
#| value
#| } else {
#| other
#| }
#|}
#|fn f32_pmin(value : Float, other : Float) -> Float {
#| if other < value {
#| other
#| } else {
#| value
#| }
#|}
#|fn f32_pmax(value : Float, other : Float) -> Float {
#| if value < other {
#| other
#| } else {
#| value
#| }
#|}
#|fn f64_pmin(value : Double, other : Double) -> Double {
#| if other < value {
#| other
#| } else {
#| value
#| }
#|}
#|fn f64_pmax(value : Double, other : Double) -> Double {
#| if value < other {
#| other
#| } else {
#| value
#| }
#|}
#|fn f32_trunc_sat_s(value : Float) -> UInt {
#| value.to_int().reinterpret_as_uint()
#|}
#|fn f32_trunc_sat_u(value : Float) -> UInt {
#| value.to_double().to_uint()
#|}
#|fn f64_trunc_sat_s(value : Double) -> UInt {
#| value.to_int().reinterpret_as_uint()
#|}
#|fn f64_trunc_sat_u(value : Double) -> UInt {
#| value.to_uint()
#|}
#|#intrinsic("%v128.f32x4_abs")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_abs(value : V128) -> V128 {
#| f32x4_map(value, fn(x) { x.abs() })
#|}
#|#intrinsic("%v128.f32x4_neg")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_neg(value : V128) -> V128 {
#| f32x4_map(value, fn(x) { -x })
#|}
#|#intrinsic("%v128.f32x4_sqrt")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_sqrt(value : V128) -> V128 {
#| f32x4_map(value, fn(x) { x.sqrt() })
#|}
#|#intrinsic("%v128.f32x4_ceil")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_ceil(value : V128) -> V128 {
#| f32x4_map(value, fn(x) { x.ceil() })
#|}
#|#intrinsic("%v128.f32x4_floor")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_floor(value : V128) -> V128 {
#| f32x4_map(value, fn(x) { x.floor() })
#|}
#|#intrinsic("%v128.f32x4_trunc")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_trunc(value : V128) -> V128 {
#| f32x4_map(value, fn(x) { x.trunc() })
#|}
#|#intrinsic("%v128.f32x4_nearest")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_nearest(value : V128) -> V128 {
#| f32x4_map(value, f32_nearest_even)
#|}
#|#intrinsic("%v128.f32x4_add")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_add(value : V128, other : V128) -> V128 {
#| f32x4_zip(value, other, fn(x, y) { x + y })
#|}
#|#intrinsic("%v128.f32x4_sub")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_sub(value : V128, other : V128) -> V128 {
#| f32x4_zip(value, other, fn(x, y) { x - y })
#|}
#|#intrinsic("%v128.f32x4_mul")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_mul(value : V128, other : V128) -> V128 {
#| f32x4_zip(value, other, fn(x, y) { x * y })
#|}
#|#intrinsic("%v128.f32x4_div")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_div(value : V128, other : V128) -> V128 {
#| f32x4_zip(value, other, fn(x, y) { x / y })
#|}
#|#intrinsic("%v128.f32x4_min")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_min(value : V128, other : V128) -> V128 {
#| f32x4_zip(value, other, f32_min)
#|}
#|#intrinsic("%v128.f32x4_max")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_max(value : V128, other : V128) -> V128 {
#| f32x4_zip(value, other, f32_max)
#|}
#|#intrinsic("%v128.f32x4_pmin")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_pmin(value : V128, other : V128) -> V128 {
#| f32x4_zip(value, other, f32_pmin)
#|}
#|#intrinsic("%v128.f32x4_pmax")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_pmax(value : V128, other : V128) -> V128 {
#| f32x4_zip(value, other, f32_pmax)
#|}
#|#intrinsic("%v128.f32x4_relaxed_min")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_relaxed_min(value : V128, other : V128) -> V128 {
#| f32x4_min(value, other)
#|}
#|#intrinsic("%v128.f32x4_relaxed_max")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_relaxed_max(value : V128, other : V128) -> V128 {
#| f32x4_max(value, other)
#|}
#|#intrinsic("%v128.f32x4_relaxed_madd")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_relaxed_madd(value : V128, other : V128, addend : V128) -> V128 {
#| pack_f32x4_by(i => {
#| f32x4_extract_lane(value, i) * f32x4_extract_lane(other, i) +
#| f32x4_extract_lane(addend, i)
#| })
#|}
#|#intrinsic("%v128.f32x4_relaxed_nmadd")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_relaxed_nmadd(value : V128, other : V128, addend : V128) -> V128 {
#| pack_f32x4_by(i => {
#| f32x4_extract_lane(addend, i) -
#| f32x4_extract_lane(value, i) * f32x4_extract_lane(other, i)
#| })
#|}
#|#intrinsic("%v128.f32x4_eq")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_eq(value : V128, other : V128) -> V128 {
#| f32x4_compare(value, other, fn(x, y) { x == y })
#|}
#|#intrinsic("%v128.f32x4_ne")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_ne(value : V128, other : V128) -> V128 {
#| f32x4_compare(value, other, fn(x, y) { x != y })
#|}
#|#intrinsic("%v128.f32x4_lt")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_lt(value : V128, other : V128) -> V128 {
#| f32x4_compare(value, other, fn(x, y) { x < y })
#|}
#|#intrinsic("%v128.f32x4_le")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_le(value : V128, other : V128) -> V128 {
#| f32x4_compare(value, other, fn(x, y) { x <= y })
#|}
#|#intrinsic("%v128.f32x4_gt")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_gt(value : V128, other : V128) -> V128 {
#| f32x4_compare(value, other, fn(x, y) { x > y })
#|}
#|#intrinsic("%v128.f32x4_ge")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_ge(value : V128, other : V128) -> V128 {
#| f32x4_compare(value, other, fn(x, y) { x >= y })
#|}
#|#intrinsic("%v128.f32x4_convert_i32x4_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_convert_i32x4_s(value : V128) -> V128 {
#| pack_f32x4_by(i => Float::from_int(u32_lane(value, i).reinterpret_as_int()))
#|}
#|#intrinsic("%v128.f32x4_convert_i32x4_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_convert_i32x4_u(value : V128) -> V128 {
#| pack_f32x4_by(i => Float::from_uint(u32_lane(value, i)))
#|}
#|#intrinsic("%v128.f32x4_demote_f64x2_zero")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f32x4_demote_f64x2_zero(value : V128) -> V128 {
#| f32x4_const(
#| Float::from_double(f64x2_extract_lane(value, 0)),
#| Float::from_double(f64x2_extract_lane(value, 1)),
#| 0.0F,
#| 0.0F,
#| )
#|}
#|#intrinsic("%v128.i32x4_trunc_sat_f32x4_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_trunc_sat_f32x4_s(value : V128) -> V128 {
#| pack_u32x4_by(i => f32_trunc_sat_s(f32x4_extract_lane(value, i)))
#|}
#|#intrinsic("%v128.i32x4_trunc_sat_f32x4_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_trunc_sat_f32x4_u(value : V128) -> V128 {
#| pack_u32x4_by(i => f32_trunc_sat_u(f32x4_extract_lane(value, i)))
#|}
#|#intrinsic("%v128.i32x4_relaxed_trunc_f32x4_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_relaxed_trunc_f32x4_s(value : V128) -> V128 {
#| i32x4_trunc_sat_f32x4_s(value)
#|}
#|#intrinsic("%v128.i32x4_relaxed_trunc_f32x4_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_relaxed_trunc_f32x4_u(value : V128) -> V128 {
#| i32x4_trunc_sat_f32x4_u(value)
#|}
#|#intrinsic("%v128.f64x2_abs")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_abs(value : V128) -> V128 {
#| f64x2_map(value, fn(x) { x.abs() })
#|}
#|#intrinsic("%v128.f64x2_neg")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_neg(value : V128) -> V128 {
#| f64x2_map(value, fn(x) { -x })
#|}
#|#intrinsic("%v128.f64x2_sqrt")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_sqrt(value : V128) -> V128 {
#| f64x2_map(value, fn(x) { x.sqrt() })
#|}
#|#intrinsic("%v128.f64x2_ceil")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_ceil(value : V128) -> V128 {
#| f64x2_map(value, fn(x) { x.ceil() })
#|}
#|#intrinsic("%v128.f64x2_floor")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_floor(value : V128) -> V128 {
#| f64x2_map(value, fn(x) { x.floor() })
#|}
#|#intrinsic("%v128.f64x2_trunc")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_trunc(value : V128) -> V128 {
#| f64x2_map(value, fn(x) { x.trunc() })
#|}
#|#intrinsic("%v128.f64x2_nearest")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_nearest(value : V128) -> V128 {
#| f64x2_map(value, f64_nearest_even)
#|}
#|#intrinsic("%v128.f64x2_add")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_add(value : V128, other : V128) -> V128 {
#| f64x2_zip(value, other, fn(x, y) { x + y })
#|}
#|#intrinsic("%v128.f64x2_sub")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_sub(value : V128, other : V128) -> V128 {
#| f64x2_zip(value, other, fn(x, y) { x - y })
#|}
#|#intrinsic("%v128.f64x2_mul")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_mul(value : V128, other : V128) -> V128 {
#| f64x2_zip(value, other, fn(x, y) { x * y })
#|}
#|#intrinsic("%v128.f64x2_div")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_div(value : V128, other : V128) -> V128 {
#| f64x2_zip(value, other, fn(x, y) { x / y })
#|}
#|#intrinsic("%v128.f64x2_min")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_min(value : V128, other : V128) -> V128 {
#| f64x2_zip(value, other, f64_min)
#|}
#|#intrinsic("%v128.f64x2_max")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_max(value : V128, other : V128) -> V128 {
#| f64x2_zip(value, other, f64_max)
#|}
#|#intrinsic("%v128.f64x2_pmin")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_pmin(value : V128, other : V128) -> V128 {
#| f64x2_zip(value, other, f64_pmin)
#|}
#|#intrinsic("%v128.f64x2_pmax")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_pmax(value : V128, other : V128) -> V128 {
#| f64x2_zip(value, other, f64_pmax)
#|}
#|#intrinsic("%v128.f64x2_relaxed_min")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_relaxed_min(value : V128, other : V128) -> V128 {
#| f64x2_min(value, other)
#|}
#|#intrinsic("%v128.f64x2_relaxed_max")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_relaxed_max(value : V128, other : V128) -> V128 {
#| f64x2_max(value, other)
#|}
#|#intrinsic("%v128.f64x2_relaxed_madd")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_relaxed_madd(value : V128, other : V128, addend : V128) -> V128 {
#| pack_f64x2_by(i => {
#| f64x2_extract_lane(value, i) * f64x2_extract_lane(other, i) +
#| f64x2_extract_lane(addend, i)
#| })
#|}
#|#intrinsic("%v128.f64x2_relaxed_nmadd")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_relaxed_nmadd(value : V128, other : V128, addend : V128) -> V128 {
#| pack_f64x2_by(i => {
#| f64x2_extract_lane(addend, i) -
#| f64x2_extract_lane(value, i) * f64x2_extract_lane(other, i)
#| })
#|}
#|#intrinsic("%v128.f64x2_eq")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_eq(value : V128, other : V128) -> V128 {
#| f64x2_compare(value, other, fn(x, y) { x == y })
#|}
#|#intrinsic("%v128.f64x2_ne")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_ne(value : V128, other : V128) -> V128 {
#| f64x2_compare(value, other, fn(x, y) { x != y })
#|}
#|#intrinsic("%v128.f64x2_lt")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_lt(value : V128, other : V128) -> V128 {
#| f64x2_compare(value, other, fn(x, y) { x < y })
#|}
#|#intrinsic("%v128.f64x2_le")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_le(value : V128, other : V128) -> V128 {
#| f64x2_compare(value, other, fn(x, y) { x <= y })
#|}
#|#intrinsic("%v128.f64x2_gt")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_gt(value : V128, other : V128) -> V128 {
#| f64x2_compare(value, other, fn(x, y) { x > y })
#|}
#|#intrinsic("%v128.f64x2_ge")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_ge(value : V128, other : V128) -> V128 {
#| f64x2_compare(value, other, fn(x, y) { x >= y })
#|}
#|#intrinsic("%v128.f64x2_convert_low_i32x4_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_convert_low_i32x4_s(value : V128) -> V128 {
#| pack_f64x2_by(i => Double::from_int(u32_lane(value, i).reinterpret_as_int()))
#|}
#|#intrinsic("%v128.f64x2_convert_low_i32x4_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_convert_low_i32x4_u(value : V128) -> V128 {
#| pack_f64x2_by(i => Double::convert_uint(u32_lane(value, i)))
#|}
#|#intrinsic("%v128.f64x2_promote_low_f32x4")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn f64x2_promote_low_f32x4(value : V128) -> V128 {
#| pack_f64x2_by(i => f32x4_extract_lane(value, i).to_double())
#|}
#|#intrinsic("%v128.i32x4_trunc_sat_f64x2_s_zero")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_trunc_sat_f64x2_s_zero(value : V128) -> V128 {
#| i32x4_const(
#| f64_trunc_sat_s(f64x2_extract_lane(value, 0)),
#| f64_trunc_sat_s(f64x2_extract_lane(value, 1)),
#| 0,
#| 0,
#| )
#|}
#|#intrinsic("%v128.i32x4_trunc_sat_f64x2_u_zero")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_trunc_sat_f64x2_u_zero(value : V128) -> V128 {
#| i32x4_const(
#| f64_trunc_sat_u(f64x2_extract_lane(value, 0)),
#| f64_trunc_sat_u(f64x2_extract_lane(value, 1)),
#| 0,
#| 0,
#| )
#|}
#|#intrinsic("%v128.i32x4_relaxed_trunc_f64x2_s_zero")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_relaxed_trunc_f64x2_s_zero(value : V128) -> V128 {
#| i32x4_trunc_sat_f64x2_s_zero(value)
#|}
#|#intrinsic("%v128.i32x4_relaxed_trunc_f64x2_u_zero")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_relaxed_trunc_f64x2_u_zero(value : V128) -> V128 {
#| i32x4_trunc_sat_f64x2_u_zero(value)
#|}
),
"simd_int_arith.mbt": (
#|#intrinsic("%v128.i8x16_add")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_add(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => u8_lane(value, i) + u8_lane(other, i))
#|}
#|#intrinsic("%v128.i8x16_sub")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_sub(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => u8_lane(value, i) - u8_lane(other, i))
#|}
#|#intrinsic("%v128.i8x16_add_sat_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_add_sat_s(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => i8_add_sat_s(u8_lane(value, i), u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i8x16_add_sat_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_add_sat_u(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => i8_add_sat_u(u8_lane(value, i), u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i8x16_sub_sat_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_sub_sat_s(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => i8_sub_sat_s(u8_lane(value, i), u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i8x16_sub_sat_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_sub_sat_u(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => i8_sub_sat_u(u8_lane(value, i), u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i8x16_neg")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_neg(value : V128) -> V128 {
#| pack_u8x16_by(i => (0 : Byte) - u8_lane(value, i))
#|}
#|#intrinsic("%v128.i8x16_abs")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_abs(value : V128) -> V128 {
#| pack_u8x16_by(i => i8_abs(u8_lane(value, i)))
#|}
#|#intrinsic("%v128.i8x16_min_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_min_s(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => i8_min_s(u8_lane(value, i), u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i8x16_min_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_min_u(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => {
#| if u8_lane(value, i) < u8_lane(other, i) {
#| u8_lane(value, i)
#| } else {
#| u8_lane(other, i)
#| }
#| })
#|}
#|#intrinsic("%v128.i8x16_max_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_max_s(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => i8_max_s(u8_lane(value, i), u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i8x16_max_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_max_u(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => {
#| if u8_lane(value, i) > u8_lane(other, i) {
#| u8_lane(value, i)
#| } else {
#| u8_lane(other, i)
#| }
#| })
#|}
#|#intrinsic("%v128.i8x16_avgr_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_avgr_u(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => i8_avgr_u(u8_lane(value, i), u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i8x16_popcnt")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_popcnt(value : V128) -> V128 {
#| pack_u8x16_by(i => u8_lane(value, i).to_uint().popcnt().to_byte())
#|}
#|#intrinsic("%v128.i16x8_add")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_add(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => u16_lane(value, i) + u16_lane(other, i))
#|}
#|#intrinsic("%v128.i16x8_sub")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_sub(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => u16_lane(value, i) - u16_lane(other, i))
#|}
#|#intrinsic("%v128.i16x8_add_sat_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_add_sat_s(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => i16_add_sat_s(u16_lane(value, i), u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_add_sat_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_add_sat_u(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => i16_add_sat_u(u16_lane(value, i), u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_sub_sat_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_sub_sat_s(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => i16_sub_sat_s(u16_lane(value, i), u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_sub_sat_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_sub_sat_u(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => i16_sub_sat_u(u16_lane(value, i), u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_mul")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_mul(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => u16_lane(value, i) * u16_lane(other, i))
#|}
#|#intrinsic("%v128.i16x8_neg")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_neg(value : V128) -> V128 {
#| pack_u16x8_by(i => (0 : UInt16) - u16_lane(value, i))
#|}
#|#intrinsic("%v128.i16x8_abs")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_abs(value : V128) -> V128 {
#| pack_u16x8_by(i => i16_abs(u16_lane(value, i)))
#|}
#|#intrinsic("%v128.i16x8_min_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_min_s(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => i16_min_s(u16_lane(value, i), u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_min_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_min_u(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => {
#| if u16_lane(value, i) < u16_lane(other, i) {
#| u16_lane(value, i)
#| } else {
#| u16_lane(other, i)
#| }
#| })
#|}
#|#intrinsic("%v128.i16x8_max_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_max_s(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => i16_max_s(u16_lane(value, i), u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_max_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_max_u(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => {
#| if u16_lane(value, i) > u16_lane(other, i) {
#| u16_lane(value, i)
#| } else {
#| u16_lane(other, i)
#| }
#| })
#|}
#|#intrinsic("%v128.i16x8_avgr_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_avgr_u(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => i16_avgr_u(u16_lane(value, i), u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i32x4_add")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_add(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => u32_lane(value, i) + u32_lane(other, i))
#|}
#|#intrinsic("%v128.i32x4_sub")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_sub(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => u32_lane(value, i) - u32_lane(other, i))
#|}
#|#intrinsic("%v128.i32x4_mul")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_mul(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => u32_lane(value, i) * u32_lane(other, i))
#|}
#|#intrinsic("%v128.i32x4_neg")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_neg(value : V128) -> V128 {
#| pack_u32x4_by(i => (0U : UInt) - u32_lane(value, i))
#|}
#|#intrinsic("%v128.i32x4_abs")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_abs(value : V128) -> V128 {
#| pack_u32x4_by(i => {
#| u32_lane(value, i).reinterpret_as_int().abs().reinterpret_as_uint()
#| })
#|}
#|#intrinsic("%v128.i32x4_min_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_min_s(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => {
#| if u32_lane(value, i).reinterpret_as_int() <
#| u32_lane(other, i).reinterpret_as_int() {
#| u32_lane(value, i)
#| } else {
#| u32_lane(other, i)
#| }
#| })
#|}
#|#intrinsic("%v128.i32x4_min_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_min_u(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => {
#| if u32_lane(value, i) < u32_lane(other, i) {
#| u32_lane(value, i)
#| } else {
#| u32_lane(other, i)
#| }
#| })
#|}
#|#intrinsic("%v128.i32x4_max_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_max_s(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => {
#| if u32_lane(value, i).reinterpret_as_int() >
#| u32_lane(other, i).reinterpret_as_int() {
#| u32_lane(value, i)
#| } else {
#| u32_lane(other, i)
#| }
#| })
#|}
#|#intrinsic("%v128.i32x4_max_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_max_u(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => {
#| if u32_lane(value, i) > u32_lane(other, i) {
#| u32_lane(value, i)
#| } else {
#| u32_lane(other, i)
#| }
#| })
#|}
#|#intrinsic("%v128.i64x2_add")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_add(value : V128, other : V128) -> V128 {
#| make(lo(value) + lo(other), hi(value) + hi(other))
#|}
#|#intrinsic("%v128.i64x2_sub")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_sub(value : V128, other : V128) -> V128 {
#| make(lo(value) - lo(other), hi(value) - hi(other))
#|}
#|#intrinsic("%v128.i64x2_mul")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_mul(value : V128, other : V128) -> V128 {
#| make(lo(value) * lo(other), hi(value) * hi(other))
#|}
#|#intrinsic("%v128.i64x2_neg")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_neg(value : V128) -> V128 {
#| make(0UL - lo(value), 0UL - hi(value))
#|}
#|#intrinsic("%v128.i64x2_abs")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_abs(value : V128) -> V128 {
#| pack_u64x2_by(i => {
#| u64_lane(value, i).reinterpret_as_int64().abs().reinterpret_as_uint64()
#| })
#|}
),
"simd_int_compare.mbt": (
#|#intrinsic("%v128.i8x16_eq")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_eq(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => bool_to_u8_mask(u8_lane(value, i) == u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i8x16_ne")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_ne(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => bool_to_u8_mask(u8_lane(value, i) != u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i8x16_lt_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_lt_s(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => {
#| bool_to_u8_mask(i8_signed(u8_lane(value, i)) < i8_signed(u8_lane(other, i)))
#| })
#|}
#|#intrinsic("%v128.i8x16_lt_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_lt_u(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => bool_to_u8_mask(u8_lane(value, i) < u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i8x16_le_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_le_s(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => {
#| bool_to_u8_mask(
#| i8_signed(u8_lane(value, i)) <= i8_signed(u8_lane(other, i)),
#| )
#| })
#|}
#|#intrinsic("%v128.i8x16_le_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_le_u(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => bool_to_u8_mask(u8_lane(value, i) <= u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i8x16_gt_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_gt_s(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => {
#| bool_to_u8_mask(i8_signed(u8_lane(value, i)) > i8_signed(u8_lane(other, i)))
#| })
#|}
#|#intrinsic("%v128.i8x16_gt_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_gt_u(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => bool_to_u8_mask(u8_lane(value, i) > u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i8x16_ge_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_ge_s(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => {
#| bool_to_u8_mask(
#| i8_signed(u8_lane(value, i)) >= i8_signed(u8_lane(other, i)),
#| )
#| })
#|}
#|#intrinsic("%v128.i8x16_ge_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_ge_u(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => bool_to_u8_mask(u8_lane(value, i) >= u8_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_eq")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_eq(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => bool_to_u16_mask(u16_lane(value, i) == u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_ne")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_ne(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => bool_to_u16_mask(u16_lane(value, i) != u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_lt_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_lt_s(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => {
#| bool_to_u16_mask(
#| i16_signed(u16_lane(value, i)) < i16_signed(u16_lane(other, i)),
#| )
#| })
#|}
#|#intrinsic("%v128.i16x8_lt_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_lt_u(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => bool_to_u16_mask(u16_lane(value, i) < u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_le_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_le_s(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => {
#| bool_to_u16_mask(
#| i16_signed(u16_lane(value, i)) <= i16_signed(u16_lane(other, i)),
#| )
#| })
#|}
#|#intrinsic("%v128.i16x8_le_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_le_u(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => bool_to_u16_mask(u16_lane(value, i) <= u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_gt_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_gt_s(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => {
#| bool_to_u16_mask(
#| i16_signed(u16_lane(value, i)) > i16_signed(u16_lane(other, i)),
#| )
#| })
#|}
#|#intrinsic("%v128.i16x8_gt_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_gt_u(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => bool_to_u16_mask(u16_lane(value, i) > u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_ge_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_ge_s(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => {
#| bool_to_u16_mask(
#| i16_signed(u16_lane(value, i)) >= i16_signed(u16_lane(other, i)),
#| )
#| })
#|}
#|#intrinsic("%v128.i16x8_ge_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_ge_u(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => bool_to_u16_mask(u16_lane(value, i) >= u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i32x4_eq")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_eq(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => bool_to_u32_mask(u32_lane(value, i) == u32_lane(other, i)))
#|}
#|#intrinsic("%v128.i32x4_ne")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_ne(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => bool_to_u32_mask(u32_lane(value, i) != u32_lane(other, i)))
#|}
#|#intrinsic("%v128.i32x4_lt_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_lt_s(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => {
#| bool_to_u32_mask(
#| u32_lane(value, i).reinterpret_as_int() <
#| u32_lane(other, i).reinterpret_as_int(),
#| )
#| })
#|}
#|#intrinsic("%v128.i32x4_lt_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_lt_u(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => bool_to_u32_mask(u32_lane(value, i) < u32_lane(other, i)))
#|}
#|#intrinsic("%v128.i32x4_le_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_le_s(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => {
#| bool_to_u32_mask(
#| u32_lane(value, i).reinterpret_as_int() <=
#| u32_lane(other, i).reinterpret_as_int(),
#| )
#| })
#|}
#|#intrinsic("%v128.i32x4_le_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_le_u(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => bool_to_u32_mask(u32_lane(value, i) <= u32_lane(other, i)))
#|}
#|#intrinsic("%v128.i32x4_gt_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_gt_s(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => {
#| bool_to_u32_mask(
#| u32_lane(value, i).reinterpret_as_int() >
#| u32_lane(other, i).reinterpret_as_int(),
#| )
#| })
#|}
#|#intrinsic("%v128.i32x4_gt_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_gt_u(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => bool_to_u32_mask(u32_lane(value, i) > u32_lane(other, i)))
#|}
#|#intrinsic("%v128.i32x4_ge_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_ge_s(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => {
#| bool_to_u32_mask(
#| u32_lane(value, i).reinterpret_as_int() >=
#| u32_lane(other, i).reinterpret_as_int(),
#| )
#| })
#|}
#|#intrinsic("%v128.i32x4_ge_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_ge_u(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => bool_to_u32_mask(u32_lane(value, i) >= u32_lane(other, i)))
#|}
#|#intrinsic("%v128.i64x2_eq")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_eq(value : V128, other : V128) -> V128 {
#| pack_u64x2_by(i => bool_to_u64_mask(u64_lane(value, i) == u64_lane(other, i)))
#|}
#|#intrinsic("%v128.i64x2_ne")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_ne(value : V128, other : V128) -> V128 {
#| pack_u64x2_by(i => bool_to_u64_mask(u64_lane(value, i) != u64_lane(other, i)))
#|}
#|#intrinsic("%v128.i64x2_lt_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_lt_s(value : V128, other : V128) -> V128 {
#| pack_u64x2_by(i => {
#| bool_to_u64_mask(
#| u64_lane(value, i).reinterpret_as_int64() <
#| u64_lane(other, i).reinterpret_as_int64(),
#| )
#| })
#|}
#|#intrinsic("%v128.i64x2_le_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_le_s(value : V128, other : V128) -> V128 {
#| pack_u64x2_by(i => {
#| bool_to_u64_mask(
#| u64_lane(value, i).reinterpret_as_int64() <=
#| u64_lane(other, i).reinterpret_as_int64(),
#| )
#| })
#|}
#|#intrinsic("%v128.i64x2_gt_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_gt_s(value : V128, other : V128) -> V128 {
#| pack_u64x2_by(i => {
#| bool_to_u64_mask(
#| u64_lane(value, i).reinterpret_as_int64() >
#| u64_lane(other, i).reinterpret_as_int64(),
#| )
#| })
#|}
#|#intrinsic("%v128.i64x2_ge_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_ge_s(value : V128, other : V128) -> V128 {
#| pack_u64x2_by(i => {
#| bool_to_u64_mask(
#| u64_lane(value, i).reinterpret_as_int64() >=
#| u64_lane(other, i).reinterpret_as_int64(),
#| )
#| })
#|}
),
"simd_int_extend.mbt": (
#|fn narrow_i16_to_i8_s(value : UInt16) -> Byte {
#| let value = i16_signed(value)
#| if value > 127 {
#| 0x7f
#| } else if value < -128 {
#| 0x80
#| } else {
#| value.to_byte()
#| }
#|}
#|fn narrow_i16_to_i8_u(value : UInt16) -> Byte {
#| let signed = i16_signed(value)
#| if signed < 0 {
#| 0
#| } else if signed > 255 {
#| 0xff
#| } else {
#| signed.to_byte()
#| }
#|}
#|fn narrow_i32_to_i16_s(value : UInt) -> UInt16 {
#| let signed = value.reinterpret_as_int()
#| if signed > 32767 {
#| 0x7fff
#| } else if signed < -32768 {
#| 0x8000
#| } else {
#| signed.to_uint16()
#| }
#|}
#|fn narrow_i32_to_i16_u(value : UInt) -> UInt16 {
#| let signed = value.reinterpret_as_int()
#| if signed < 0 {
#| 0
#| } else if signed > 65535 {
#| 0xffff
#| } else {
#| signed.to_uint16()
#| }
#|}
#|fn i16_q15mulr_sat_s(value : UInt16, other : UInt16) -> UInt16 {
#| let rounded = (i16_signed(value) * i16_signed(other) + 0x4000) >> 15
#| if rounded > 32767 {
#| 0x7fff
#| } else if rounded < -32768 {
#| 0x8000
#| } else {
#| rounded.to_uint16()
#| }
#|}
#|fn i16_pair_dot(value : V128, other : V128, pair : Int) -> UInt {
#| (i16_signed(u16_lane(value, pair * 2)) * i16_signed(u16_lane(other, pair * 2)) +
#| i16_signed(u16_lane(value, pair * 2 + 1)) *
#| i16_signed(u16_lane(other, pair * 2 + 1))).reinterpret_as_uint()
#|}
#|#intrinsic("%v128.i16x8_extend_low_i8x16_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_extend_low_i8x16_s(value : V128) -> V128 {
#| pack_u16x8_by(i => i8_signed(u8_lane(value, i)).to_uint16())
#|}
#|#intrinsic("%v128.i16x8_extend_high_i8x16_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_extend_high_i8x16_s(value : V128) -> V128 {
#| pack_u16x8_by(i => i8_signed(u8_lane(value, i + 8)).to_uint16())
#|}
#|#intrinsic("%v128.i16x8_extend_low_i8x16_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_extend_low_i8x16_u(value : V128) -> V128 {
#| pack_u16x8_by(i => u8_lane(value, i).to_uint16())
#|}
#|#intrinsic("%v128.i16x8_extend_high_i8x16_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_extend_high_i8x16_u(value : V128) -> V128 {
#| pack_u16x8_by(i => u8_lane(value, i + 8).to_uint16())
#|}
#|#intrinsic("%v128.i32x4_extend_low_i16x8_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_extend_low_i16x8_s(value : V128) -> V128 {
#| pack_u32x4_by(i => i16_signed(u16_lane(value, i)).reinterpret_as_uint())
#|}
#|#intrinsic("%v128.i32x4_extend_high_i16x8_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_extend_high_i16x8_s(value : V128) -> V128 {
#| pack_u32x4_by(i => i16_signed(u16_lane(value, i + 4)).reinterpret_as_uint())
#|}
#|#intrinsic("%v128.i32x4_extend_low_i16x8_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_extend_low_i16x8_u(value : V128) -> V128 {
#| pack_u32x4_by(i => u16_lane(value, i).to_uint())
#|}
#|#intrinsic("%v128.i32x4_extend_high_i16x8_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_extend_high_i16x8_u(value : V128) -> V128 {
#| pack_u32x4_by(i => u16_lane(value, i + 4).to_uint())
#|}
#|#intrinsic("%v128.i64x2_extend_low_i32x4_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_extend_low_i32x4_s(value : V128) -> V128 {
#| pack_u64x2_by(i => {
#| u32_lane(value, i).reinterpret_as_int().to_int64().reinterpret_as_uint64()
#| })
#|}
#|#intrinsic("%v128.i64x2_extend_high_i32x4_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_extend_high_i32x4_s(value : V128) -> V128 {
#| pack_u64x2_by(i => {
#| u32_lane(value, i + 2)
#| .reinterpret_as_int()
#| .to_int64()
#| .reinterpret_as_uint64()
#| })
#|}
#|#intrinsic("%v128.i64x2_extend_low_i32x4_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_extend_low_i32x4_u(value : V128) -> V128 {
#| pack_u64x2_by(i => u32_lane(value, i).to_uint64())
#|}
#|#intrinsic("%v128.i64x2_extend_high_i32x4_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_extend_high_i32x4_u(value : V128) -> V128 {
#| pack_u64x2_by(i => u32_lane(value, i + 2).to_uint64())
#|}
#|#intrinsic("%v128.i8x16_relaxed_laneselect")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_relaxed_laneselect(
#| value : V128,
#| other : V128,
#| mask : V128,
#|) -> V128 {
#| pack_u8x16_by(i => {
#| if (u8_lane(mask, i) & 0x80) != 0 {
#| u8_lane(value, i)
#| } else {
#| u8_lane(other, i)
#| }
#| })
#|}
#|#intrinsic("%v128.i16x8_relaxed_laneselect")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_relaxed_laneselect(
#| value : V128,
#| other : V128,
#| mask : V128,
#|) -> V128 {
#| pack_u16x8_by(i => {
#| if (u16_lane(mask, i) & 0x8000) != 0 {
#| u16_lane(value, i)
#| } else {
#| u16_lane(other, i)
#| }
#| })
#|}
#|#intrinsic("%v128.i32x4_relaxed_laneselect")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_relaxed_laneselect(
#| value : V128,
#| other : V128,
#| mask : V128,
#|) -> V128 {
#| pack_u32x4_by(i => {
#| if (u32_lane(mask, i) & 0x80000000) != 0 {
#| u32_lane(value, i)
#| } else {
#| u32_lane(other, i)
#| }
#| })
#|}
#|#intrinsic("%v128.i64x2_relaxed_laneselect")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_relaxed_laneselect(
#| value : V128,
#| other : V128,
#| mask : V128,
#|) -> V128 {
#| pack_u64x2_by(i => {
#| if (u64_lane(mask, i) & 0x8000000000000000UL) != 0UL {
#| u64_lane(value, i)
#| } else {
#| u64_lane(other, i)
#| }
#| })
#|}
#|#intrinsic("%v128.i8x16_narrow_i16x8_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_narrow_i16x8_s(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => {
#| if i < 8 {
#| narrow_i16_to_i8_s(u16_lane(value, i))
#| } else {
#| narrow_i16_to_i8_s(u16_lane(other, i - 8))
#| }
#| })
#|}
#|#intrinsic("%v128.i8x16_narrow_i16x8_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_narrow_i16x8_u(value : V128, other : V128) -> V128 {
#| pack_u8x16_by(i => {
#| if i < 8 {
#| narrow_i16_to_i8_u(u16_lane(value, i))
#| } else {
#| narrow_i16_to_i8_u(u16_lane(other, i - 8))
#| }
#| })
#|}
#|#intrinsic("%v128.i16x8_narrow_i32x4_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_narrow_i32x4_s(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => {
#| if i < 4 {
#| narrow_i32_to_i16_s(u32_lane(value, i))
#| } else {
#| narrow_i32_to_i16_s(u32_lane(other, i - 4))
#| }
#| })
#|}
#|#intrinsic("%v128.i16x8_narrow_i32x4_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_narrow_i32x4_u(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => {
#| if i < 4 {
#| narrow_i32_to_i16_u(u32_lane(value, i))
#| } else {
#| narrow_i32_to_i16_u(u32_lane(other, i - 4))
#| }
#| })
#|}
#|#intrinsic("%v128.i16x8_extmul_low_i8x16_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_extmul_low_i8x16_s(value : V128, other : V128) -> V128 {
#| i16x8_mul(i16x8_extend_low_i8x16_s(value), i16x8_extend_low_i8x16_s(other))
#|}
#|#intrinsic("%v128.i16x8_extmul_high_i8x16_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_extmul_high_i8x16_s(value : V128, other : V128) -> V128 {
#| i16x8_mul(i16x8_extend_high_i8x16_s(value), i16x8_extend_high_i8x16_s(other))
#|}
#|#intrinsic("%v128.i16x8_extmul_low_i8x16_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_extmul_low_i8x16_u(value : V128, other : V128) -> V128 {
#| i16x8_mul(i16x8_extend_low_i8x16_u(value), i16x8_extend_low_i8x16_u(other))
#|}
#|#intrinsic("%v128.i16x8_extmul_high_i8x16_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_extmul_high_i8x16_u(value : V128, other : V128) -> V128 {
#| i16x8_mul(i16x8_extend_high_i8x16_u(value), i16x8_extend_high_i8x16_u(other))
#|}
#|#intrinsic("%v128.i32x4_extmul_low_i16x8_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_extmul_low_i16x8_s(value : V128, other : V128) -> V128 {
#| i32x4_mul(i32x4_extend_low_i16x8_s(value), i32x4_extend_low_i16x8_s(other))
#|}
#|#intrinsic("%v128.i32x4_extmul_high_i16x8_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_extmul_high_i16x8_s(value : V128, other : V128) -> V128 {
#| i32x4_mul(i32x4_extend_high_i16x8_s(value), i32x4_extend_high_i16x8_s(other))
#|}
#|#intrinsic("%v128.i32x4_extmul_low_i16x8_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_extmul_low_i16x8_u(value : V128, other : V128) -> V128 {
#| i32x4_mul(i32x4_extend_low_i16x8_u(value), i32x4_extend_low_i16x8_u(other))
#|}
#|#intrinsic("%v128.i32x4_extmul_high_i16x8_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_extmul_high_i16x8_u(value : V128, other : V128) -> V128 {
#| i32x4_mul(i32x4_extend_high_i16x8_u(value), i32x4_extend_high_i16x8_u(other))
#|}
#|#intrinsic("%v128.i64x2_extmul_low_i32x4_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_extmul_low_i32x4_s(value : V128, other : V128) -> V128 {
#| pack_u64x2_by(i => {
#| (u32_lane(value, i).reinterpret_as_int().to_int64() *
#| u32_lane(other, i).reinterpret_as_int().to_int64()).reinterpret_as_uint64()
#| })
#|}
#|#intrinsic("%v128.i64x2_extmul_high_i32x4_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_extmul_high_i32x4_s(value : V128, other : V128) -> V128 {
#| pack_u64x2_by(i => {
#| (u32_lane(value, i + 2).reinterpret_as_int().to_int64() *
#| u32_lane(other, i + 2).reinterpret_as_int().to_int64()).reinterpret_as_uint64()
#| })
#|}
#|#intrinsic("%v128.i64x2_extmul_low_i32x4_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_extmul_low_i32x4_u(value : V128, other : V128) -> V128 {
#| pack_u64x2_by(i => {
#| u32_lane(value, i).to_uint64() * u32_lane(other, i).to_uint64()
#| })
#|}
#|#intrinsic("%v128.i64x2_extmul_high_i32x4_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_extmul_high_i32x4_u(value : V128, other : V128) -> V128 {
#| pack_u64x2_by(i => {
#| u32_lane(value, i + 2).to_uint64() * u32_lane(other, i + 2).to_uint64()
#| })
#|}
#|#intrinsic("%v128.i16x8_q15mulr_sat_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_q15mulr_sat_s(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => i16_q15mulr_sat_s(u16_lane(value, i), u16_lane(other, i)))
#|}
#|#intrinsic("%v128.i16x8_relaxed_q15mulr_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_relaxed_q15mulr_s(value : V128, other : V128) -> V128 {
#| i16x8_q15mulr_sat_s(value, other)
#|}
#|#intrinsic("%v128.i16x8_extadd_pairwise_i8x16_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_extadd_pairwise_i8x16_s(value : V128) -> V128 {
#| pack_u16x8_by(i => {
#| (i8_signed(u8_lane(value, i * 2)) + i8_signed(u8_lane(value, i * 2 + 1))).to_uint16()
#| })
#|}
#|#intrinsic("%v128.i16x8_extadd_pairwise_i8x16_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_extadd_pairwise_i8x16_u(value : V128) -> V128 {
#| pack_u16x8_by(i => {
#| u8_lane(value, i * 2).to_uint16() + u8_lane(value, i * 2 + 1).to_uint16()
#| })
#|}
#|#intrinsic("%v128.i32x4_extadd_pairwise_i16x8_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_extadd_pairwise_i16x8_s(value : V128) -> V128 {
#| pack_u32x4_by(i => {
#| (i16_signed(u16_lane(value, i * 2)) + i16_signed(u16_lane(value, i * 2 + 1))).reinterpret_as_uint()
#| })
#|}
#|#intrinsic("%v128.i32x4_extadd_pairwise_i16x8_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_extadd_pairwise_i16x8_u(value : V128) -> V128 {
#| pack_u32x4_by(i => {
#| u16_lane(value, i * 2).to_uint() + u16_lane(value, i * 2 + 1).to_uint()
#| })
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_relaxed_dot_i8x16_i7x16_s(value : V128, other : V128) -> V128 {
#| pack_u16x8_by(i => {
#| (i8_signed(u8_lane(value, i * 2)) * i8_signed(u8_lane(other, i * 2)) +
#| i8_signed(u8_lane(value, i * 2 + 1)) * i8_signed(u8_lane(other, i * 2 + 1))).to_uint16()
#| })
#|}
#|#intrinsic("%v128.i32x4_dot_i16x8_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_dot_i16x8_s(value : V128, other : V128) -> V128 {
#| pack_u32x4_by(i => i16_pair_dot(value, other, i))
#|}
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_relaxed_dot_i8x16_i7x16_add_s(
#| value : V128,
#| other : V128,
#| accumulator : V128,
#|) -> V128 {
#| i32x4_add(
#| i32x4_extadd_pairwise_i16x8_s(i16x8_relaxed_dot_i8x16_i7x16_s(value, other)),
#| accumulator,
#| )
#|}
),
"simd_int_shift.mbt": (
#|fn has_zero_byte(value : UInt64) -> Bool {
#| ((value - 0x0101010101010101UL) & value.lnot() & 0x8080808080808080UL) != 0UL
#|}
#|fn has_zero_u16_lane(value : UInt64) -> Bool {
#| let bytes = value | (value >> 8) | 0xff00ff00ff00ff00UL
#| has_zero_byte(bytes)
#|}
#|#intrinsic("%v128.i8x16_shl")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_shl(value : V128, shift : Int) -> V128 {
#| let shift = shift & 7
#| pack_u8x16_by(i => (u8_lane(value, i).to_uint() << shift).to_byte())
#|}
#|#intrinsic("%v128.i8x16_shr_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_shr_u(value : V128, shift : Int) -> V128 {
#| let shift = shift & 7
#| pack_u8x16_by(i => (u8_lane(value, i).to_uint() >> shift).to_byte())
#|}
#|#intrinsic("%v128.i8x16_shr_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_shr_s(value : V128, shift : Int) -> V128 {
#| let shift = shift & 7
#| pack_u8x16_by(i => (i8_signed(u8_lane(value, i)) >> shift).to_byte())
#|}
#|#intrinsic("%v128.i16x8_shl")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_shl(value : V128, shift : Int) -> V128 {
#| let shift = shift & 15
#| pack_u16x8_by(i => (u16_lane(value, i).to_uint() << shift).to_uint16())
#|}
#|#intrinsic("%v128.i16x8_shr_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_shr_u(value : V128, shift : Int) -> V128 {
#| let shift = shift & 15
#| pack_u16x8_by(i => (u16_lane(value, i).to_uint() >> shift).to_uint16())
#|}
#|#intrinsic("%v128.i16x8_shr_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_shr_s(value : V128, shift : Int) -> V128 {
#| let shift = shift & 15
#| pack_u16x8_by(i => (i16_signed(u16_lane(value, i)) >> shift).to_uint16())
#|}
#|#intrinsic("%v128.i32x4_shl")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_shl(value : V128, shift : Int) -> V128 {
#| let shift = shift & 31
#| pack_u32x4_by(i => u32_lane(value, i) << shift)
#|}
#|#intrinsic("%v128.i32x4_shr_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_shr_u(value : V128, shift : Int) -> V128 {
#| let shift = shift & 31
#| pack_u32x4_by(i => u32_lane(value, i) >> shift)
#|}
#|#intrinsic("%v128.i32x4_shr_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_shr_s(value : V128, shift : Int) -> V128 {
#| let shift = shift & 31
#| pack_u32x4_by(i => {
#| (u32_lane(value, i).reinterpret_as_int() >> shift).reinterpret_as_uint()
#| })
#|}
#|#intrinsic("%v128.i64x2_shl")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_shl(value : V128, shift : Int) -> V128 {
#| let shift = shift & 63
#| make(lo(value) << shift, hi(value) << shift)
#|}
#|#intrinsic("%v128.i64x2_shr_u")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_shr_u(value : V128, shift : Int) -> V128 {
#| let shift = shift & 63
#| make(lo(value) >> shift, hi(value) >> shift)
#|}
#|#intrinsic("%v128.i64x2_shr_s")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_shr_s(value : V128, shift : Int) -> V128 {
#| let shift = shift & 63
#| pack_u64x2_by(i => {
#| (u64_lane(value, i).reinterpret_as_int64() >> shift).reinterpret_as_uint64()
#| })
#|}
#|#intrinsic("%v128.i8x16_all_true")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_all_true(value : V128) -> Bool {
#| !has_zero_byte(lo(value)) && !has_zero_byte(hi(value))
#|}
#|#intrinsic("%v128.i16x8_all_true")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_all_true(value : V128) -> Bool {
#| !has_zero_u16_lane(lo(value)) && !has_zero_u16_lane(hi(value))
#|}
#|#intrinsic("%v128.i32x4_all_true")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_all_true(value : V128) -> Bool {
#| let lo_word = lo(value)
#| let hi_word = hi(value)
#| (lo_word & 0xffffffffUL) != 0UL &&
#| lo_word >> 32 != 0UL &&
#| (hi_word & 0xffffffffUL) != 0UL &&
#| hi_word >> 32 != 0UL
#|}
#|#intrinsic("%v128.i64x2_all_true")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_all_true(value : V128) -> Bool {
#| lo(value) != 0UL && hi(value) != 0UL
#|}
#|#intrinsic("%v128.i8x16_bitmask")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_bitmask(value : V128) -> Int {
#| let mut result = 0
#| for i in 0..<16 {
#| result = result | (((u8_lane(value, i).to_int() >> 7) & 1) << i)
#| }
#| result
#|}
#|#intrinsic("%v128.i16x8_bitmask")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i16x8_bitmask(value : V128) -> Int {
#| let mut result = 0
#| for i in 0..<8 {
#| result = result | (((u16_lane(value, i).to_int() >> 15) & 1) << i)
#| }
#| result
#|}
#|#intrinsic("%v128.i32x4_bitmask")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i32x4_bitmask(value : V128) -> Int {
#| let mut result = 0
#| for i in 0..<4 {
#| result = result |
#| ((u32_lane(value, i).reinterpret_as_int() >> 31) & (1 << i))
#| }
#| result
#|}
#|#intrinsic("%v128.i64x2_bitmask")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i64x2_bitmask(value : V128) -> Int {
#| let mut result = 0
#| for i in 0..<2 {
#| result = result | ((u64_lane(value, i) >> 63).to_int() << i)
#| }
#| result
#|}
),
"simd_memory.mbt": (
#|fn load_u16_le(bytes : FixedArray[Byte], offset : Int) -> UInt16 {
#| bytes.unsafe_get(offset).to_uint16() |
#| (bytes.unsafe_get(offset + 1).to_uint16() << 8)
#|}
#|fn load_u16x4_le(str : String, offset : Int) -> UInt64 {
#| for i in 0..<4; word = (0 : UInt64) {
#| continue word | (str.unsafe_get(offset + i).to_uint64() << (16 * i))
#| } nobreak {
#| word
#| }
#|}
#|fn load_u32_le(bytes : FixedArray[Byte], offset : Int) -> UInt {
#| bytes.unsafe_get(offset).to_uint() |
#| (bytes.unsafe_get(offset + 1).to_uint() << 8) |
#| (bytes.unsafe_get(offset + 2).to_uint() << 16) |
#| (bytes.unsafe_get(offset + 3).to_uint() << 24)
#|}
#|fn load_u64_le(bytes : FixedArray[Byte], offset : Int) -> UInt64 {
#| bytes.unsafe_get(offset).to_uint64() |
#| (bytes.unsafe_get(offset + 1).to_uint64() << 8) |
#| (bytes.unsafe_get(offset + 2).to_uint64() << 16) |
#| (bytes.unsafe_get(offset + 3).to_uint64() << 24) |
#| (bytes.unsafe_get(offset + 4).to_uint64() << 32) |
#| (bytes.unsafe_get(offset + 5).to_uint64() << 40) |
#| (bytes.unsafe_get(offset + 6).to_uint64() << 48) |
#| (bytes.unsafe_get(offset + 7).to_uint64() << 56)
#|}
#|fn store_u16_le(bytes : FixedArray[Byte], offset : Int, value : UInt16) -> Unit {
#| bytes.unsafe_set(offset, value.to_byte())
#| bytes.unsafe_set(offset + 1, (value >> 8).to_byte())
#|}
#|fn store_u32_le(bytes : FixedArray[Byte], offset : Int, value : UInt) -> Unit {
#| bytes.unsafe_set(offset, value.to_byte())
#| bytes.unsafe_set(offset + 1, (value >> 8).to_byte())
#| bytes.unsafe_set(offset + 2, (value >> 16).to_byte())
#| bytes.unsafe_set(offset + 3, (value >> 24).to_byte())
#|}
#|fn store_u64_le(bytes : FixedArray[Byte], offset : Int, value : UInt64) -> Unit {
#| bytes.unsafe_set(offset, value.to_byte())
#| bytes.unsafe_set(offset + 1, (value >> 8).to_byte())
#| bytes.unsafe_set(offset + 2, (value >> 16).to_byte())
#| bytes.unsafe_set(offset + 3, (value >> 24).to_byte())
#| bytes.unsafe_set(offset + 4, (value >> 32).to_byte())
#| bytes.unsafe_set(offset + 5, (value >> 40).to_byte())
#| bytes.unsafe_set(offset + 6, (value >> 48).to_byte())
#| bytes.unsafe_set(offset + 7, (value >> 56).to_byte())
#|}
#|#intrinsic("%v128.i8x16_swizzle")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_swizzle(value : V128, indices : V128) -> V128 {
#| pack_u8x16_by(i => {
#| let index = u8_lane(indices, i).to_int()
#| if index < 16 {
#| u8_lane(value, index)
#| } else {
#| 0
#| }
#| })
#|}
#|#intrinsic("%v128.i8x16_relaxed_swizzle")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_relaxed_swizzle(value : V128, indices : V128) -> V128 {
#| i8x16_swizzle(value, indices)
#|}
#|fn shuffle_lane(value : V128, other : V128, index : Int) -> Byte {
#| if index < 16 {
#| u8_lane(value, index)
#| } else {
#| u8_lane(other, index - 16)
#| }
#|}
#|#intrinsic("%v128.i8x16_shuffle")
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn i8x16_shuffle(
#| value : V128,
#| other : V128,
#| i0 : Int,
#| i1 : Int,
#| i2 : Int,
#| i3 : Int,
#| i4 : Int,
#| i5 : Int,
#| i6 : Int,
#| i7 : Int,
#| i8 : Int,
#| i9 : Int,
#| i10 : Int,
#| i11 : Int,
#| i12 : Int,
#| i13 : Int,
#| i14 : Int,
#| i15 : Int,
#|) -> V128 {
#| pack_u8x16_by(fn(i) {
#| match i {
#| 0 => shuffle_lane(value, other, i0)
#| 1 => shuffle_lane(value, other, i1)
#| 2 => shuffle_lane(value, other, i2)
#| 3 => shuffle_lane(value, other, i3)
#| 4 => shuffle_lane(value, other, i4)
#| 5 => shuffle_lane(value, other, i5)
#| 6 => shuffle_lane(value, other, i6)
#| 7 => shuffle_lane(value, other, i7)
#| 8 => shuffle_lane(value, other, i8)
#| 9 => shuffle_lane(value, other, i9)
#| 10 => shuffle_lane(value, other, i10)
#| 11 => shuffle_lane(value, other, i11)
#| 12 => shuffle_lane(value, other, i12)
#| 13 => shuffle_lane(value, other, i13)
#| 14 => shuffle_lane(value, other, i14)
#| _ => shuffle_lane(value, other, i15)
#| }
#| })
#|}
#|#intrinsic("%v128.v128_load")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| make(load_u64_le(bytes, offset), load_u64_le(bytes, offset + 8))
#|}
#|#intrinsic("%v128.v128_load_i16x8")
#|#borrow(str)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load_i16x8(str : String, offset : Int) -> V128 {
#| make(load_u16x4_le(str, offset), load_u16x4_le(str, offset + 4))
#|}
#|#intrinsic("%v128.v128_load8x8_s")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load8x8_s(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| let value = load_u64_le(bytes, offset)
#| make(sign_extend_u8x4_to_u16x4(value), sign_extend_u8x4_to_u16x4(value >> 32))
#|}
#|#intrinsic("%v128.v128_load8x8_u")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load8x8_u(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| let value = load_u64_le(bytes, offset)
#| make(widen_u8x4_to_u16x4(value), widen_u8x4_to_u16x4(value >> 32))
#|}
#|#intrinsic("%v128.v128_load16x4_s")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load16x4_s(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| let value = load_u64_le(bytes, offset)
#| make(
#| sign_extend_u16x2_to_u32x2(value),
#| sign_extend_u16x2_to_u32x2(value >> 32),
#| )
#|}
#|#intrinsic("%v128.v128_load16x4_u")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load16x4_u(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| let value = load_u64_le(bytes, offset)
#| make(widen_u16x2_to_u32x2(value), widen_u16x2_to_u32x2(value >> 32))
#|}
#|#intrinsic("%v128.v128_load32x2_s")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load32x2_s(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| let value = load_u64_le(bytes, offset)
#| make(sign_extend_u32_to_u64(value), sign_extend_u32_to_u64(value >> 32))
#|}
#|#intrinsic("%v128.v128_load32x2_u")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load32x2_u(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| let value = load_u64_le(bytes, offset)
#| make(value & 0xffffffffUL, value >> 32)
#|}
#|#intrinsic("%v128.v128_load8_splat")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load8_splat(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| i8x16_splat(bytes.unsafe_get(offset))
#|}
#|#intrinsic("%v128.v128_load16_splat")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load16_splat(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| i16x8_splat(load_u16_le(bytes, offset))
#|}
#|#intrinsic("%v128.v128_load32_splat")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load32_splat(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| i32x4_splat(load_u32_le(bytes, offset))
#|}
#|#intrinsic("%v128.v128_load64_splat")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load64_splat(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| i64x2_splat(load_u64_le(bytes, offset))
#|}
#|#intrinsic("%v128.v128_load32_zero")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load32_zero(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| i32x4_const(load_u32_le(bytes, offset), 0, 0, 0)
#|}
#|#intrinsic("%v128.v128_load64_zero")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load64_zero(bytes : FixedArray[Byte], offset : Int) -> V128 {
#| make(load_u64_le(bytes, offset), 0UL)
#|}
#|#intrinsic("%v128.v128_load8_lane")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load8_lane(
#| bytes : FixedArray[Byte],
#| offset : Int,
#| value : V128,
#| lane : Int,
#|) -> V128 {
#| i8x16_replace_lane(value, bytes.unsafe_get(offset).to_uint(), lane)
#|}
#|#intrinsic("%v128.v128_load16_lane")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load16_lane(
#| bytes : FixedArray[Byte],
#| offset : Int,
#| value : V128,
#| lane : Int,
#|) -> V128 {
#| i16x8_replace_lane(value, load_u16_le(bytes, offset).to_uint(), lane)
#|}
#|#intrinsic("%v128.v128_load32_lane")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load32_lane(
#| bytes : FixedArray[Byte],
#| offset : Int,
#| value : V128,
#| lane : Int,
#|) -> V128 {
#| i32x4_replace_lane(value, load_u32_le(bytes, offset), lane)
#|}
#|#intrinsic("%v128.v128_load64_lane")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_load64_lane(
#| bytes : FixedArray[Byte],
#| offset : Int,
#| value : V128,
#| lane : Int,
#|) -> V128 {
#| i64x2_replace_lane(value, load_u64_le(bytes, offset), lane)
#|}
#|#intrinsic("%v128.v128_store")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_store(bytes : FixedArray[Byte], offset : Int, value : V128) -> Unit {
#| store_u64_le(bytes, offset, lo(value))
#| store_u64_le(bytes, offset + 8, hi(value))
#|}
#|#intrinsic("%v128.v128_store8_lane")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_store8_lane(
#| bytes : FixedArray[Byte],
#| offset : Int,
#| value : V128,
#| lane : Int,
#|) -> Unit {
#| bytes.unsafe_set(offset, u8_lane(value, lane))
#|}
#|#intrinsic("%v128.v128_store16_lane")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_store16_lane(
#| bytes : FixedArray[Byte],
#| offset : Int,
#| value : V128,
#| lane : Int,
#|) -> Unit {
#| store_u16_le(bytes, offset, u16_lane(value, lane))
#|}
#|#intrinsic("%v128.v128_store32_lane")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_store32_lane(
#| bytes : FixedArray[Byte],
#| offset : Int,
#| value : V128,
#| lane : Int,
#|) -> Unit {
#| store_u32_le(bytes, offset, u32_lane(value, lane))
#|}
#|#intrinsic("%v128.v128_store64_lane")
#|#borrow(bytes)
#|#internal(experimental, "subject to breaking change without notice")
#|#doc(hidden)
#|pub fn v128_store64_lane(
#| bytes : FixedArray[Byte],
#| offset : Int,
#| value : V128,
#| lane : Int,
#|) -> Unit {
#| store_u64_le(bytes, offset, u64_lane(value, lane))
#|}
),
"v128.mbt": (
#|fn make(lo : UInt64, hi : UInt64) -> V128 = "%v128.make"
#|fn lo(value : V128) -> UInt64 = "%v128.lo"
#|fn hi(value : V128) -> UInt64 = "%v128.hi"
),
},
)
|