# Copyright (c) 2023 Yuki Kimoto # MIT License class Fn { use StringBuffer; use StringList; use IntList; use Hash; use Sort; use List; enum { GET_CODE_POINT_ERROR_OVER_STRING_RANGE = -1, GET_CODE_POINT_ERROR_INVALID_UTF8 = -2, } static method BYTE_MAX : int () { return 127; } static method BYTE_MIN : int () { return -128; } native static method DBL_MAX : double (); native static method DBL_MIN : double (); native static method DOUBLE_MAX : double (); native static method DOUBLE_MIN : double (); native static method FLOAT_MAX : float (); native static method FLOAT_MIN : float(); native static method FLT_MAX : float (); native static method FLT_MIN : float(); static method INT16_MAX : int () { return 32767; } static method INT16_MIN : int () { return -32768; } static method INT32_MAX : int () { return 2147483647; } static method INT32_MIN : int () { return -2147483648; } static method INT64_MAX : long () { return 9223372036854775807L; } static method INT64_MIN : long () { return -9223372036854775808L; } static method INT8_MAX : int () { return 127; } static method INT8_MIN : int () { return -128; } static method INT_MAX : int () { return 2147483647; } static method INT_MIN : int () { return -2147483648; } static method LONG_MAX : long () { return 9223372036854775807L; } static method LONG_MIN : long () { return -9223372036854775808L; } static method RAND_MAX : int () { return 2147483647; } static method SHORT_MAX : int () { return 32767; } static method SHORT_MIN : int () { return -32768; } static method UBYTE_MAX : int () { return (byte)0xFF; } static method UINT16_MAX : int () { return (short)0xFFFF; } static method UINT32_MAX : int () { return 0xFFFFFFFF; } static method UINT64_MAX : long () { return 0xFFFFFFFFFFFFFFFFL; } static method UINT8_MAX : int () { return (byte)0xFF; } static method UINT_MAX : int () { return 0xFFFFFFFF; } static method ULONG_MAX : long () { return 0xFFFFFFFFFFFFFFFFL; } static method USHORT_MAX : int () { return (short)0xFFFF; } static method abs : int ($value : int) { my $abs = 0; if ($value > 0) { $abs = $value; } else { $abs = -$value; } return $abs; } static method chomp : void ($string : mutable string) { unless ($string) { die "The \$string must be defined."; } my $length = length $string; if ($length >= 2 && $string->[$length - 2] == '\r' && $string->[$length - 1] == '\n') { &shorten($string, $length - 2); } elsif ($length >= 1 && $string->[$length - 1] == '\n') { &shorten($string, $length - 1); } } static method chompr : string ($string : string) { unless ($string) { die "The \$string must be defined."; } my $new_string = (mutable string)copy $string; &chomp($new_string); return $new_string; } static method chr : string ($code_point : int) { my $is_unicode_scalar_value = &is_unicode_scalar_value($code_point); my $utf8_char = (string)undef; if ($is_unicode_scalar_value) { $utf8_char = &_chr_native($code_point); } return $utf8_char; } static method contains : int ($string : string, $substring : string, $string_offset : int = 0, $string_length : int = -1) { return &index($string, $substring, $string_offset, $string_length) >= 0; } static method copy_string : string ($string : string) { return copy $string; } native static method crand : int ($seed : int*); precompile static method equals_string_range : int ($string1 : string, $string1_offset : int, $string2 : string, $string2_offset : int, $length : int) { unless ($string1) { die "The \$string1 must be defined."; } unless ($string2) { die "The \$string2 must be defined."; } unless ($string1_offset >= 0) { die "The \$string1_offset must be greater than or equal to 0."; } unless ($string2_offset >= 0) { die "The \$string2_offset must be greater than or equal to 0."; } my $string1_length = length $string1; unless ($string1_offset + $length <= $string1_length) { return 0; } my $string2_length = length $string2; unless ($string1_offset + $length <= $string2_length) { return 0; } my $match = 1; for (my $i = 0; $i < $length; $i++) { my $char1 = $string1->[$string1_offset + $i]; my $char2 = $string2->[$string2_offset + $i]; unless ($char1 == $char2) { $match = 0; last; } } return $match; } native static method get_code_point : int ($string : string, $offset_ref : int*); precompile static method hex : int ($hex_string : string) { unless ($hex_string) { die "The \$hex string must be defined."; } my $hex_value = 0; my $digit = 0; my $value = 0; my $length = length $hex_string; unless ($length >= 1 && $length <= 8) { die "The length of the \$hex string must be 1 to 8."; } for (my $i = $length - 1; $i >= 0; $i--) { my $ascii_code = $hex_string->[$i]; unless (&is_hex_digit($ascii_code)) { die "The \$hex string must contain only hex characters."; } my $digit_value = 0; if ($ascii_code >= '0' && $ascii_code <= '9') { $digit_value = $ascii_code - 48; } elsif ($ascii_code >= 'a' && $ascii_code <= 'f') { $digit_value = $ascii_code - 87; } elsif ($ascii_code >= 'A' && $ascii_code <= 'F') { $digit_value = $ascii_code - 55; } $value += $digit_value * &powi(16, $digit); $digit += 1; } return $value; } precompile static method index : int ($string : string, $substring : string, $begin : int = 0, $end : int = -1) { unless ($string) { die "The \$string must be defined."; } unless ($substring) { die "The \$substring must be defined."; } unless ($begin >= 0 && $begin <= length $string) { die "The \$begin must be between 0 and the length of the \$string."; } my $string_length = length $string; if ($end < 0) { $end = $string_length; } unless ($end <= length $string) { die "The \$end must be less than or equal to the length of the \$string."; } unless ($end >= $begin) { die "The \$end must be greater than or equal to \$begin."; } my $substring_length = length $substring; if ($substring_length == 0) { return $begin; } if ($end == $string_length) { $end--; } for (my $i = $begin; $i <= $end; $i++) { my $match = 1; for (my $k = 0; $k < $substring_length; $k++) { if ($i + $k > $end) { $match = 0; last; } unless ($string->[$i + $k] == $substring->[$k]) { $match = 0; last; } } if ($match) { return $i; } } return -1; } precompile static method init_string : void ($string : mutable string, $ascii_code : int = 0, $offset : int = 0, $length : int = -1) { unless ($string) { die "The \$string must be defined."; } my $string_length = length $string; if ($length < 0) { $length = $string_length - $offset; } unless ($offset + $length <= $string_length) { die "The \$offset + the \$length must be less than or equal to the length of the \$string."; } for (my $i = $offset; $i < $offset + $length; $i++) { $string->[$i] = (byte)$ascii_code; } } static method is_alnum : int ($code_point : int) { if (($code_point >= 'A' && $code_point <= 'Z') || ($code_point >= 'a' && $code_point <= 'z') || ($code_point >= '0' && $code_point <= '9')) { return 1; } else { return 0; } } static method is_alpha : int ($code_point : int) { if (($code_point >= 'A' && $code_point <= 'Z') || ($code_point >= 'a' && $code_point <= 'z')) { return 1; } else { return 0; } } native static method is_array : int ($object : object); static method is_blank : int ($code_point : int) { # SP or HT if ($code_point >= '\x20' || $code_point <= '\x9') { return 1; } else { return 0; } } native static method is_class : int ($object : object); static method is_cntrl : int ($code_point : int) { if (($code_point >= 0x00 && $code_point <= 0x1f) || $code_point == 0x7f) { return 1; } else { return 0; } } static method is_digit : int ($code_point : int) { if ($code_point >= '0' && $code_point <= '9') { return 1; } else { return 0; } } static method is_graph : int ($code_point : int) { if ($code_point >= 0x21 && $code_point <= 0x7E) { return 1; } else { return 0; } } static method is_hex_digit : int ($code_point : int) { if (($code_point >= '0' && $code_point <= '9') || ($code_point >= 'a' && $code_point <= 'f') || ($code_point >= 'A' && $code_point <= 'F')) { return 1; } else { return 0; } } static method is_lower : int ($code_point : int) { if ($code_point >= 'a' && $code_point <= 'z') { return 1; } else { return 0; } } native static method is_mulnum_array : int ($object : object); native static method is_numeric_array : int ($object : object); native static method is_object_array : int ($object : object); # This is same as Perl ASCII mode \s static method is_perl_space : int ($code_point : int) { my $is_perl_space = 0; switch ($code_point) { case 0x20: # ' ' SP case 0x0D: # '\r' CR case 0x0A: # '\n' LF case 0x09: # '\t' HT case 0x0C: # '\f' FF { $is_perl_space = 1; break; } } return $is_perl_space; } static method is_perl_word : int ($code_point : int) { my $ispword = 0; if ($code_point >= 'a' && $code_point <= 'z') { $ispword = 1; } elsif ($code_point >= 'A' && $code_point <= 'Z') { $ispword = 1; } elsif ($code_point == '_') { $ispword = 1; } elsif ($code_point >= '0' && $code_point <= '9') { $ispword = 1; } return $ispword; } native static method is_pointer_class : int ($object : object); static method is_print : int ($code_point : int) { if ($code_point >= 0x20 && $code_point <= 0x7E) { return 1; } else { return 0; } } static method is_punct : int ($code_point : int) { if (($code_point >= 0x21 && $code_point <= 0x2F) || ($code_point >= 0x3A && $code_point <= 0x40) || ($code_point >= 0x5B && $code_point <= 0x60) || ($code_point >= 0x7B && $code_point <= 0x7E)) { return 1; } else { return 0; } } static method is_space : int ($code_point : int) { if (($code_point >= 0x09 && $code_point <= 0x0D) || $code_point == 0x20) { return 1; } else { return 0; } } private static method is_unicode_scalar_value : int ($code_point: int) { my $is_unicode_scalar_value = 0; # The range of Unicde code points if ($code_point >= 0 && $code_point <= 0x10FFFF) { # Not surrogate code points unless ($code_point >= 0xD800 && $code_point <= 0xDFFF) { $is_unicode_scalar_value = 1; } } return $is_unicode_scalar_value; } static method is_upper : int ($code_point : int) { if ($code_point >= 'A' && $code_point <= 'Z') { return 1; } else { return 0; } } static method is_xdigit : int ($code_point : int) { if (($code_point >= 'A' && $code_point <= 'F') || ($code_point >= 'a' && $code_point <= 'f') || ($code_point >= '0' && $code_point <= '9')) { return 1; } else { return 0; } } precompile static method join : string ($separator : string, $strings : string[]) { unless ($separator) { die "The \$separator must be defined."; } unless ($strings) { die "The \$strings must be defined."; } my $join_buffer = StringBuffer->new; for (my $i = 0; $i < @$strings; $i++) { my $string = $strings->[$i]; if ($string) { $join_buffer->push($string); } else { $join_buffer->push(""); } if ($i != @$strings - 1) { $join_buffer->push($separator); } } my $join = $join_buffer->to_string; return $join; } static method labs : long ($value : long) { my $labs = 0L; if ($value > 0) { $labs = $value; } else { $labs = -$value; } return $labs; } precompile static method lc : string ($string : string) { unless ($string) { die "The \$string must be defined."; } my $length = length $string; my $new_string = (mutable string)new_string_len($length); for (my $i = 0; $i < $length; $i++) { my $char = $string->[$i]; if ($char >= 'A' && $char <= 'Z') { $new_string->[$i] = (byte)($string->[$i] + 32); } else { $new_string->[$i] = $string->[$i]; } } return $new_string; } static method lcfirst : string ($string : string) { unless ($string) { die "The \$string must be defined."; } my $length = length $string; my $new_string = (mutable string)new_string_len($length); if ($length > 0) { my $char = $string->[0]; if ($char >= 'A' && $char <= 'Z') { $new_string->[0] = (byte)($char + 32); } else { $new_string->[0] = $char; } } Fn->memcpy($new_string, 1, $string, 1, $length - 1); return $new_string; } static method look_code_point : int ($string : string, $offset_ref : int*) { my $save_offset = $$offset_ref; my $code_point = &get_code_point($string, $offset_ref); $$offset_ref = $save_offset; return $code_point; } native static method memcpy : void ($dest : object, $dest_offset : int, $source : object, $source_offset : int, $length : int); native static method memmove : void ($dest : object, $dest_offset : int, $source : object, $source_offset : int, $length : int); static method ord : int ($string : string) { my $offset = 0; my $code_point = &get_code_point($string, \$offset); return $code_point; } precompile static method powi : int ($base : int, $exponant : int) { unless ($exponant >= 0) { die "The \$exponant number must be greater than or equal to 0."; } if ($base == 0) { unless ($exponant != 0) { die "If the \$base number is 0, the \$exponant number cannnot be 0."; } } my $ret = 1; for (my $i = 0; $i < $exponant; $i++) { $ret = $ret * $base; } return $ret; } precompile static method powl : long ($base : long, $exponant : long) { unless ($exponant >= 0) { die "The \$exponant number must be greater than or equal to 0."; } if ($base == 0) { unless ($exponant != 0) { die "If the \$base number is 0, the \$exponant number cannnot be 0."; } } my $ret = 1L; for (my $i = 0; $i < $exponant; $i++) { $ret = $ret * $base; } return $ret; } static method rand : double ($seed : int*, $max : int = 1) { # 0 <= random_number < 1 my $random_number = (double)&crand($seed) / ((double)&RAND_MAX() + 1); $random_number *= $max; return $random_number; } precompile static method repeat : string ($string : string, $count : int) { unless ($string) { die "The \$string must be defined."; } unless ($count >= 0) { die "The \$repeat count must be greater than or equal to 0."; } my $buffer = StringBuffer->new; for (my $i = 0; $i < $count; $i++) { $buffer->push($string); } my $repeat_string = $buffer->to_string; return $repeat_string; } precompile static method replace_chars : void ($string : mutable string, $from_ch : int, $to_ch : int) { unless ($string) { die "The \$string must be defined."; } my $string_length = length $string; for (my $i = 0; $i < $string_length; $i++) { if ($string->[$i] == $from_ch) { $string->[$i] = (byte)$to_ch; } } } precompile static method rindex : int ($string : string, $substring : string, $end : int = -1, $begin : int = 0) { unless ($string) { die "The \$string must be defined."; } unless ($substring) { die "The \$substring must be defined."; } unless ($begin >= 0 && $begin <= length $string) { die "The \$begin must be between 0 and the length of the \$string."; } my $string_length = length $string; if ($end < 0) { $end = $string_length; } unless ($end <= length $string) { die "The \$end must be less than or equal to the length of the \$string."; } unless ($end >= $begin) { die "The \$end must be greater than or equal to \$begin."; } my $substring_length = length $substring; if ($substring_length == 0) { return $end; } if ($end == $string_length) { $end--; } my $match_chars_count = 0; for (my $i = $end; $i >= $begin; $i--) { my $match = 1; for (my $k = 0; $k < $substring_length; $k++) { if ($i + $k > $end) { $match = 0; last; } unless ($string->[$i + $k] == $substring->[$k]) { $match = 0; last; } } if ($match) { return $i; } } return -1; } native static method sizeof_native_int : int (); native static method sizeof_native_pointer : int (); native static method shorten : void ($string : mutable string, $length : int); precompile static method shorten_null_char : void ($string : mutable string) { if (!$string) { die "The \$string must be defined."; } my $null_char_offset = -1; for (my $i = 0; $i < length $string; $i++) { my $char = $string->[$i]; if ($char == '\0') { $null_char_offset = $i; last; } } if ($null_char_offset >= 0) { Fn->shorten($string, $null_char_offset); } } precompile static method split : string[] ($separator : string, $string : string, $limit : int = 0) { unless ($separator) { die "The \$separator must be defined."; } unless ($string) { die "The \$string must be defined."; } my $string_length = length $string; my $separator_length = length $separator; unless ($separator_length > 0) { die "The length of the \$separator must be greater than 0."; } my $parts_list = StringList->new_len(0); my $offset = 0; my $match_count = 0; for (my $i = 0; $i < $string_length; $i++) { if ($limit > 0 && $match_count >= $limit - 1) { last; } my $match_offset = &index($string, $separator, $offset); my $match = $match_offset >= 0; if ($match) { $match_count++; my $part = &substr($string, $offset, $match_offset - $offset); $parts_list->push($part); my $match_legnth = $separator_length; $offset = $match_offset + $match_legnth; } } if ($offset == $string_length) { $parts_list->push(""); } else { my $part = &substr($string, $offset, $string_length - $offset); $parts_list->push($part); } if ($limit == 0) { while ($parts_list->length > 0) { if ($parts_list->get($parts_list->length - 1) eq "") { $parts_list->pop; } else { last; } } } my $parts = $parts_list->to_array; return $parts; } static method substr : string ($string : string, $offset : int, $length : int = -1, $replacement : string = undef) { unless ($string) { die "The \$string must be defined."; } unless ($offset >= 0) { die "The \$offset must be greater than or equal to 0."; } my $string_length = length $string; if ($length < 0) { $length = $string_length - $offset; } unless ($offset + $length <= $string_length) { die "The \$offset + the \$length must be less than or equal to the length of the \$string."; } my $substring = (string)undef; if ($replacement) { my $replacement_length = length $replacement; $substring = Fn->substr($string, 0, $offset) . $replacement . Fn->substr($string, $offset + $length); } else { $substring = (mutable string)new_string_len($length); Fn->memcpy($substring, 0, $string, $offset, $length); } return $substring; } precompile static method to_code_points : int[] ($string : string) { unless ($string) { die "The \$string must be defined."; } my $string_length = length $string; my $offset = 0; my $utf8_length = 0; my $code_points_list = IntList->new; while ($offset < $string_length) { my $code_point = &get_code_point($string, \$offset); if ($code_point < 0) { if ($code_point == &GET_CODE_POINT_ERROR_INVALID_UTF8) { die "The \$string contains a invalid Unicode code point."; } else { die "An unexpected exception is thrown."; } } $code_points_list->push($code_point); } my $code_points = $code_points_list->to_array; return $code_points; } native static method to_double : double ($string : string); native static method to_float : float ($string : string); static method to_int : int ($string : string) { return &to_int_with_base($string, 10); } native static method to_int_with_base : int ($string : string, $digit : int); static method to_long : long ($string : string) { return &to_long_with_base($string, 10); } native static method to_long_with_base : long ($string : string, $digit : int); static method to_lower : int ($code_point : int) { if ($code_point >= 'A' && $code_point <= 'Z') { $code_point = $code_point + 0x20; } return $code_point; } static method to_upper : int ($code_point : int) { if ($code_point >= 'a' && $code_point <= 'z') { $code_point = $code_point - 0x20; } return $code_point; } precompile static method to_utf8_chars : string[] ($string : string) { unless ($string) { die "The \$string must be defined."; } my $string_length = length $string; my $offset = 0; my $utf8_length = 0; my $utf8_chars_list = StringList->new; while ($offset < $string_length) { my $code_point = &get_code_point($string, \$offset); if ($code_point < 0) { if ($code_point == &GET_CODE_POINT_ERROR_INVALID_UTF8) { die "The \$string contains a invalid Unicode code point."; } else { die "An unexpected exception is thrown."; } } my $utf8_char = &chr($code_point); $utf8_chars_list->push($utf8_char); } my $utf8_chars = $utf8_chars_list->to_array; return $utf8_chars; } precompile static method tr : string ($string : string, $pattern : string, $replace : string) { unless ($string) { die "The \$string must be defined."; } unless ($pattern) { die "The \$pattern must be defined."; } unless ($replace) { die "The \$replace must be defined."; } my $replace_length = length $pattern; my $pattern_range = &_parse_range($pattern, "$pattern"); my $replace_range = &_parse_range($replace, "$replace"); my $string_length = length $string; my $offset = 0; my $buffer = StringBuffer->new; while ($offset < $string_length) { my $code_point = &get_code_point($string, \$offset); if ($code_point < 0) { if ($code_point == &GET_CODE_POINT_ERROR_INVALID_UTF8) { die "The \$string contains a invalid Unicode code point."; } else { die "An unexpected exception is thrown."; } } my $pattern_offset = 0; my $match = 0; my $replace_pos = 0; my $match_pattern_index = -1; my $match_code_point_offset = -1; my $min_code_point = $pattern_range->[0]; my $max_code_point = $pattern_range->[1]; if ($code_point >= $min_code_point && $code_point <= $max_code_point) { $match = 1; $match_code_point_offset = $code_point - $min_code_point; } if ($match) { my $replace_code_point = $replace_range->[0] + $match_code_point_offset; my $char = &chr($replace_code_point); $buffer->push($char); } else { my $char = &chr($code_point); $buffer->push($char); } } my $ret = $buffer->to_string; return $ret; } precompile static method trim : string ($string : string) { unless ($string) { die "The \$string must be defined."; } my $length = length $string; my $begin_index = -1; my $end_index = -1; for (my $i = 0; $i < $length; $i++) { if ($begin_index == -1) { if (&is_space($string->[$i])) { # Skip } else { $begin_index = $i; last; } } } for (my $i = $length - 1; $i >= 0; $i--) { if ($end_index == -1) { if (&is_space($string->[$i])) { # Skip } else { $end_index = $i; last; } } } my $trimed_string : string; if ($begin_index == -1 && $end_index == -1) { return ""; } elsif ($end_index == -1) { $trimed_string = &substr($string, $begin_index, $length - $begin_index); } elsif ($end_index == -1) { $trimed_string = &substr($string, 0, $end_index + 1); } else { $trimed_string = &substr($string, $begin_index, $end_index - $begin_index + 1); } return $trimed_string; } precompile static method uc : string ($string : string) { unless ($string) { die "The \$string must be defined."; } my $length = length $string; my $new_string = (mutable string)new_string_len($length); for (my $i = 0; $i < $length; $i++) { my $char = $string->[$i]; if ($char >= 'a' && $char <= 'z') { $new_string->[$i] = (byte)($string->[$i] - 32); } else { $new_string->[$i] = $string->[$i]; } } return $new_string; } static method ucfirst : string ($string : string) { unless ($string) { die "The \$string must be defined."; } my $length = length $string; my $new_string = (mutable string)new_string_len($length); if ($length > 0) { my $char = $string->[0]; if ($char >= 'a' && $char <= 'z') { $new_string->[0] = (byte)($char - 32); } else { $new_string->[0] = $char; } } Fn->memcpy($new_string, 1, $string, 1, $length - 1); return $new_string; } precompile static method utf8_length : int ($string : string) { unless ($string) { die "The \$string must be defined."; } my $string_length = length $string; my $offset = 0; my $utf8_length = 0; while ($offset < $string_length) { my $code_point = &get_code_point($string, \$offset); if ($code_point < 0) { if ($code_point == &GET_CODE_POINT_ERROR_INVALID_UTF8) { die "The \$string contains a invalid Unicode code point."; } else { die "An unexpected exception is thrown."; } } $utf8_length++; } return $utf8_length; } precompile static method utf8_substr : string ($string : string, $utf8_offset : int, $utf8_length : int = -1) { unless ($string) { die "The \$string must be defined."; } unless ($utf8_offset >= 0) { die "The \$utf8_offset must be greater than or equal to 0."; } my $string_length = length $string; my $offset = 0; my $current_utf8_offset = 0; my $buffer = StringBuffer->new; while ($offset < $string_length) { my $code_point = &get_code_point($string, \$offset); if ($code_point < 0) { if ($code_point == &GET_CODE_POINT_ERROR_INVALID_UTF8) { die "The \$string contains a invalid Unicode code point."; } else { die "An unexpected exception is thrown."; } } # -1:before, 0:range, 1:after my $range = 0; if ($current_utf8_offset < $utf8_offset) { $range = -1; } else { if ($utf8_length < 0) { $range = 0; } else { if ($current_utf8_offset < $utf8_offset + $utf8_length) { $range = 0; } else { $range = 1; } } } if ($range == 0) { my $utf8_char = &chr($code_point); $buffer->push($utf8_char); } elsif ($range == 1) { last; } $current_utf8_offset++; } if ($utf8_length >= 0) { unless ($utf8_offset + $utf8_length <= $current_utf8_offset) { die "The \$utf8_offset + the \$utf8_length must be less than or equal to the UTF-8 length of the \$string."; } } my $substring = $buffer->to_string; return $substring; } native static method _chr_native : string ($uchar : int); private precompile static method _parse_range : int[] ($range_format : string, $arg_name : string) { my $range = IntList->new; my $range_format_length = length $range_format; my $offset = 0; my $min_code_point = -1; my $max_code_point = -1; my $code_points_index = 0; while ($offset < $range_format_length) { my $code_point = &get_code_point($range_format, \$offset); if ($code_point < 0) { if ($code_point == &GET_CODE_POINT_ERROR_INVALID_UTF8) { die "The range format of the $arg_name cannnot be contain a invalid Unicode code point."; } else { die "Calling the get_code_point method in the Fn class to the $arg_name returns an error code: $code_point."; } } if ($code_points_index == 0) { $min_code_point = $code_point; } elsif ($code_points_index == 1) { unless ($code_point == '-') { die "The second character ot the range format of the $arg_name must be \"-\"."; } } elsif ($code_points_index == 2) { $max_code_point = $code_point; } $code_points_index++; } my $code_points_length = $code_points_index; unless ($code_points_length == 3) { if ($code_points_length == 1) { $max_code_point = $min_code_point; } if ($max_code_point < 0) { die "The range format of the $arg_name must be 1 or 3 characters."; } } unless ($min_code_point <= $max_code_point) { die "The code point of the ending character in the $arg_name must be greater than or equal to the code point of the begining caharater."; } return [$min_code_point, $max_code_point]; } precompile static method merge_options : object[] ($options1 : object[], $options2 : object[]) { unless ($options1) { die "The \$options1 must be defined."; } unless ($options2) { die "The \$options2 must be defined."; } my $options1_length = @$options1; unless ($options1_length % 2 == 0) { die "The length of the \$options1 must be an even number."; } my $options2_length = @$options2; unless ($options2_length % 2 == 0) { die "The length of the \$options2 must be an even number."; } my $merged_options_h = Hash->new; for (my $i = 0; $i < $options1_length; $i += 2) { unless ($options1->[$i]) { die "The key of the \$options1 must be defined."; } unless ($options1->[$i] isa string) { die "The key of the \$options1 must be the string type."; } my $name = (string)$options1->[$i]; my $value = $options1->[$i + 1]; $merged_options_h->set($name, $value); } for (my $i = 0; $i < $options2_length; $i += 2) { unless ($options2->[$i]) { die "The key of the \$options2 must be defined."; } unless ($options2->[$i] isa string) { die "The key of the \$options2 must be the string type."; } my $name = (string)$options2->[$i]; my $value = $options2->[$i + 1]; $merged_options_h->set($name, $value); } my $merged_options = $merged_options_h->to_array; return $merged_options; } native static method object_to_int : int ($object : object); native static method object_to_long : long ($object : object); native static method get_spvm_version_string : string (); native static method get_spvm_version_number : double (); native static method get_version_string : string ($basic_type_name : string); native static method get_version_number : double ($basic_type_name : string); }