package SPVM::Util : precompile {
use SPVM::Stringer;
use SPVM::Cloner;
use SPVM::EqualityChecker;
use SPVM::StringBuffer;
use SPVM::StringList;
use SPVM::Unicode (uchar_to_utf8);
use SPVM::Math (fabs, floor, log10, pow, sqrt, sqrtf);
use SPVM::Time (time);
INIT {
srand(time());
}
sub copy_oarray : object[] ($objects : object[], $cloner : SPVM::Cloner) {
my $length = @$objects;
my $new_objects = new object[$length];
for (my $i = 0; $i < $length; $i++) {
$new_objects->[$i] = $cloner->($objects->[$i]);
}
return $new_objects;
}
sub equals_oarray : int ($objs1 : oarray, $objs2 : oarray, $equality_checker : SPVM::EqualityChecker) {
my $is_equals = 1;
if (@$objs1 == @$objs2) {
for (my $i = 0; $i < @$objs1; $i++) {
if (!$equality_checker->($objs1->[$i], $objs2->[$i])) {
$is_equals = 0;
last;
}
}
}
else {
$is_equals = 0;
}
return $is_equals;
}
sub joino : string ($sep : string, $objects : oarray, $stringer : SPVM::Stringer) {
my $join = "";
for (my $i = 0; $i < @$objects; $i++) {
my $str = $stringer->($objects->[$i]);
$join .= $str;
if ($i != @$objects - 1) {
$join .= $sep;
}
}
return $join;
}
sub split : string[] ($sep : string, $string : string) {
my $string_length = length $string;
my $sep_length = length $sep;
if ($sep_length == 0) {
die "Separator must not be empty string";
}
my $separated_strings_list = SPVM::StringList->new_len(0);
my $match_start = 0;
my $string_base = 0;
for (my $string_index = 0; $string_index < $string_length; $string_index++) {
if ($string->[$string_index] == $sep->[0]) {
$match_start = 1;
}
if ($match_start) {
my $match = 1;
for (my $sep_index = 0; $sep_index < $sep_length; $sep_index++) {
if ($string_index + $sep_index > $string_length - 1) {
$match = 0;
last;
}
else {
unless ($string->[$string_index + $sep_index] == $sep->[$sep_index]) {
$match = 0;
last;
}
}
}
if ($match) {
my $separated_string = substr($string, $string_base, $string_index - $string_base);
$separated_strings_list->push($separated_string);
$string_base = $string_index + $sep_length;
$string_index += $sep_length - 1;
}
}
}
if ($string_base == $string_length) {
$separated_strings_list->push("");
}
else {
my $separated_string = substr($string, $string_base, $string_length - $string_base);
$separated_strings_list->push($separated_string);
}
my $separated_strings = $separated_strings_list->to_array;
return $separated_strings;
}
native sub _snsprintf_double : string ($format : string, $value : double);
sub sprintf : string ($format : string, $args : object[]...) {
my $format_length = length $format;
my $index = 0;
my $buffer = SPVM::StringBuffer->new;
my $arg_count = 0;
my $constant_string_length = 0;
while ($index + $constant_string_length < $format_length) {
if ($format->[$index + $constant_string_length] != '%') {
# Read constant string
++$constant_string_length;
}
elsif ($index + $constant_string_length + 1 < $format_length &&
$format->[$index + $constant_string_length + 1] == '%') {
# Read %%
++$constant_string_length;
# Add constant string
if ($constant_string_length > 0) {
$buffer->push_range($format, $index, $constant_string_length);
$index += $constant_string_length;
$constant_string_length = 0;
}
# Skip second %
++$index;
}
elsif ($index + $constant_string_length + 1 >= $format_length) {
die "Invalid conversion in sprintf: end of string";
}
else {
# Add constant string
if ($constant_string_length > 0) {
$buffer->push_range($format, $index, $constant_string_length);
$index += $constant_string_length;
$constant_string_length = 0;
}
# Read format string
# Check the next element of @$args corresponding to the specifier
unless ($arg_count < @$args) {
die "Missing argument in sprintf";
}
# Read specifier %[flags][width][.precision][length]type
my $specifier_base_index = $index;
++$index; # '%'
# Read `flags`
my $pad_char = ' ';
my $plus_sign = 0;
my $left_justified = 0;
while ($index < $format_length) {
my $flag = (int)($format->[$index]);
switch($flag) {
case '0': {
++$index;
$pad_char = '0';
break;
}
case '+': {
++$index;
$plus_sign = 1;
break;
}
case '-': {
++$index;
$left_justified = 1;
break;
}
default: {
last;
break;
}
}
}
# Read `width`
my $width = 0;
while ($index < $format_length) {
my $c = $format->[$index];
if ($c < '0' || '9' < $c) {
last;
}
$width = $width * 10 + $c - '0';
++$index;
}
# Skip `precision` because of using native sprintf.
if ($index < $format_length && $format->[$index] == '.') {
++$index;
while ($index < $format_length) {
my $c = $format->[$index];
if ($c < '0' || '9' < $c) {
last;
}
++$index;
}
}
unless ($index < $format_length) {
die "Invalid conversion in sprintf: \""
. substr($format, $specifier_base_index, $index - $specifier_base_index) . "\"";
}
my $specifier_char = $format->[$index];
if ($specifier_char == 'c') {
++$index;
my $arg = ((SPVM::Byte)$args->[$arg_count])->val;
if ($left_justified) {
$buffer->push_char($arg);
my $space_count = $width - 1;
if ($space_count > 0) {
for (; $space_count > 0; --$space_count) {
$buffer->push_char($pad_char);
}
}
}
else {
my $space_count = $width - 1;
if ($space_count > 0) {
for (; $space_count > 0; --$space_count) {
$buffer->push_char($pad_char);
}
}
$buffer->push_char($arg);
}
}
elsif ($specifier_char == 's') {
++$index;
my $arg = (string)$args->[$arg_count];
my $space_count = $width - length $arg;;
if ($left_justified) {
$buffer->push($arg);
for (my $i = 0; $i < $space_count; ++$i) {
$buffer->push_char($pad_char);
}
}
else {
for (my $i = 0; $i < $space_count; ++$i) {
$buffer->push_char($pad_char);
}
$buffer->push($arg);
}
}
elsif ($specifier_char == 'd') {
++$index;
my $arg = ((SPVM::Int)$args->[$arg_count])->val;
my $digits = new byte[11]; # -2147483648 has 11 digits
my $digit_count = 0;
while ($arg > 0) {
$digits->[$digit_count++] = (byte)('0' + $arg % 10);
$arg /= 10;
}
if ($left_justified) {
my $space_count = $width - $digit_count;
if ($arg < 0) {
$buffer->push_char('-');
--$space_count;
}
elsif ($plus_sign && $arg >= 0) {
$buffer->push_char('+');
--$space_count;
}
for (my $i = 0; $i < $digit_count; ++$i) {
$buffer->push_char($digits->[$digit_count - $i - 1]);
}
if ($space_count > 0) {
for (; $space_count > 0; --$space_count) {
$buffer->push_char($pad_char);
}
}
}
else {
my $space_count = $width - $digit_count;
if ($arg < 0) {
--$space_count;
}
elsif ($plus_sign && $arg >= 0) {
--$space_count;
}
if ($space_count > 0) {
for (; $space_count > 0; --$space_count) {
$buffer->push_char($pad_char);
}
}
if ($arg < 0) {
$buffer->push_char('-');
}
elsif ($plus_sign && $arg >= 0) {
$buffer->push_char('+');
}
for (my $i = 0; $i < $digit_count; ++$i) {
$buffer->push_char($digits->[$digit_count - $i - 1]);
}
}
}
elsif ($specifier_char == 'l') {
unless ($index + 1 < $format_length && $format->[$index + 1] == 'd') {
die "Invalid conversion in sprintf: \""
. substr($format, $specifier_base_index, $index - $specifier_base_index + 1) . "\"";
}
$index += 2;
my $arg = ((SPVM::Long)$args->[$arg_count])->val;
my $digits = new byte[20]; # -9223372036854775808 has 20 digits
my $digit_count = 0;
while ($arg > 0) {
$digits->[$digit_count++] = (byte)('0' + $arg % 10);
$arg /= 10;
}
if ($left_justified) {
my $space_count = $width - $digit_count;
if ($arg < 0) {
$buffer->push_char('-');
--$space_count;
}
elsif ($plus_sign && $arg >= 0) {
$buffer->push_char('+');
--$space_count;
}
for (my $i = 0; $i < $digit_count; ++$i) {
$buffer->push_char($digits->[$digit_count - $i - 1]);
}
if ($space_count > 0) {
for (; $space_count > 0; --$space_count) {
$buffer->push_char($pad_char);
}
}
}
else {
my $space_count = $width - $digit_count;
if ($arg < 0) {
--$space_count;
}
elsif ($plus_sign && $arg >= 0) {
--$space_count;
}
if ($space_count > 0) {
for (; $space_count > 0; --$space_count) {
$buffer->push_char($pad_char);
}
}
if ($arg < 0) {
$buffer->push_char('-');
}
elsif ($plus_sign && $arg >= 0) {
$buffer->push_char('+');
}
for (my $i = 0; $i < $digit_count; ++$i) {
$buffer->push_char($digits->[$digit_count - $i - 1]);
}
}
}
elsif ($specifier_char == 'f' || $specifier_char == 'g') {
++$index;
my $arg = (SPVM::Double)$args->[$arg_count];
my $specifier_str = substr($format, $specifier_base_index, $index - $specifier_base_index);
my $str = _snsprintf_double($specifier_str, $arg->val);
$buffer->push($str);
}
elsif ($specifier_char == 'U') {
++$index;
my $arg = (SPVM::Int)$args->[$arg_count];
my $utf8 = uchar_to_utf8($arg->val);
$buffer->push($utf8);
}
else {
die "Invalid conversion in sprintf: \""
. substr($format, $specifier_base_index, $index - $specifier_base_index + 1) . "\"";
}
++$arg_count;
}
}
# Add constant string
if ($constant_string_length > 0) {
$buffer->push_range($format, $index, $constant_string_length);
$index += $constant_string_length;
$constant_string_length = 0;
}
my $result = $buffer->to_string;
return $result;
}
sub chomp_lf : string ($string : string) {
unless ($string) {
return undef;
}
my $new_string : string;
my $length = length $string;
if ($length == 0) {
$new_string = copy_str($string);
}
else {
if ($string->[$length - 1] == '\n') {
$new_string = (string)sliceb((byte[])$string, 0, $length - 1);
}
else {
$new_string = copy_str($string);
}
}
return $new_string;
}
sub chomp_crlf : string ($string : string) {
unless ($string) {
return undef;
}
my $new_string : string;
my $length = length $string;
if ($length == 0 || $length == 1) {
$new_string = copy_str($string);
}
else {
if ($string->[$length - 2] == '\r' && $string->[$length - 1] == '\n') {
$new_string = (string)sliceb((byte[])$string, 0, $length - 2);
}
else {
$new_string = copy_str($string);
}
}
return $new_string;
}
sub copy_barray : byte[] ($nums : byte[]) {
my $length = @$nums;
my $new_nums = new byte[$length];
for (my $i = 0; $i < $length; $i++) {
$new_nums->[$i] = $nums->[$i];
}
return $new_nums;
}
sub copy_str : string ($string : string) {
my $bytes = (byte[])$string;
return (string)$bytes;
}
sub copy_sarray : short[] ($nums : short[]) {
my $length = @$nums;
my $new_nums = new short[$length];
for (my $i = 0; $i < $length; $i++) {
$new_nums->[$i] = $nums->[$i];
}
return $new_nums;
}
sub copy_iarray : int[] ($nums : int[]) {
my $length = @$nums;
my $new_nums = new int[$length];
for (my $i = 0; $i < $length; $i++) {
$new_nums->[$i] = $nums->[$i];
}
return $new_nums;
}
sub copy_larray : long[] ($nums : long[]) {
my $length = @$nums;
my $new_nums = new long[$length];
for (my $i = 0; $i < $length; $i++) {
$new_nums->[$i] = $nums->[$i];
}
return $new_nums;
}
sub copy_farray : float[] ($nums : float[]) {
my $length = @$nums;
my $new_nums = new float[$length];
for (my $i = 0; $i < $length; $i++) {
$new_nums->[$i] = $nums->[$i];
}
return $new_nums;
}
sub copy_darray : double[] ($nums : double[]) {
my $length = @$nums;
my $new_nums = new double[$length];
for (my $i = 0; $i < $length; $i++) {
$new_nums->[$i] = $nums->[$i];
}
return $new_nums;
}
sub copy_strarray : string[] ($strings : string[]) {
my $length = @$strings;
my $new_strings = new string[$length];
for (my $i = 0; $i < $length; $i++) {
$new_strings->[$i] = copy_str($strings->[$i]);
}
return $new_strings;
}
sub equals_barray : int ($nums1 : byte[], $nums2 : byte[]) {
my $is_equals = 1;
if (@$nums1 == @$nums2) {
for (my $i = 0; $i < @$nums1; $i++) {
if ($nums1->[$i] != $nums2->[$i]) {
$is_equals = 0;
last;
}
}
}
else {
$is_equals = 0;
}
return $is_equals;
}
sub equals_sarray : int ($nums1 : short[], $nums2 : short[]) {
my $is_equals = 1;
if (@$nums1 == @$nums2) {
for (my $i = 0; $i < @$nums1; $i++) {
if ($nums1->[$i] != $nums2->[$i]) {
$is_equals = 0;
last;
}
}
}
else {
$is_equals = 0;
}
return $is_equals;
}
sub equals_iarray : int ($nums1 : int[], $nums2 : int[]) {
my $is_equals = 1;
if (@$nums1 == @$nums2) {
for (my $i = 0; $i < @$nums1; $i++) {
if ($nums1->[$i] != $nums2->[$i]) {
$is_equals = 0;
last;
}
}
}
else {
$is_equals = 0;
}
return $is_equals;
}
sub equals_larray : int ($nums1 : long[], $nums2 : long[]) {
my $is_equals = 1;
if (@$nums1 == @$nums2) {
for (my $i = 0; $i < @$nums1; $i++) {
if ($nums1->[$i] != $nums2->[$i]) {
$is_equals = 0;
last;
}
}
}
else {
$is_equals = 0;
}
return $is_equals;
}
sub equals_farray : int ($nums1 : float[], $nums2 : float[]) {
my $is_equals = 1;
if (@$nums1 == @$nums2) {
for (my $i = 0; $i < @$nums1; $i++) {
if ($nums1->[$i] != $nums2->[$i]) {
$is_equals = 0;
last;
}
}
}
else {
$is_equals = 0;
}
return $is_equals;
}
sub equals_darray : int ($nums1 : double[], $nums2 : double[]) {
my $is_equals = 1;
if (@$nums1 == @$nums2) {
for (my $i = 0; $i < @$nums1; $i++) {
if ($nums1->[$i] != $nums2->[$i]) {
$is_equals = 0;
last;
}
}
}
else {
$is_equals = 0;
}
return $is_equals;
}
sub equals_strarray : int ($strings1 : string[], $strings2 : string[]) {
my $is_equals = 1;
if (@$strings1 == @$strings2) {
for (my $i = 0; $i < @$strings1; $i++) {
if ($strings1->[$i] ne $strings2->[$i]) {
$is_equals = 0;
last;
}
}
}
else {
$is_equals = 0;
}
return $is_equals;
}
sub E : double () { return 2.7182818284590452354; }
native sub get_type_name : string ($obj : object);
sub index : int ($str : string, $substr : string, $posision : int) {
my $strCount = length $str;
my $substrCount = length $substr;
if ($posision >= $strCount) {
my $ret : int;
if ($substrCount == 0) {
$ret = $strCount;
}
else {
$ret = -1;
}
return $ret;
}
if ($posision < 0) {
$posision = 0;
}
if ($substrCount == 0) {
return $posision;
}
my $first : byte = $substr->[0];
my $max : int = ($strCount - $substrCount);
for (my $i = $posision; $i <= $max; $i++) {
if ($str->[$i] != $first) {
while (++$i <= $max && $str->[$i] != $first) {}
}
if ($i <= $max) {
my $j = $i + 1;
my $end = $j + $substrCount - 1;
for (my $k = 01; $j < $end && $str->[$j] == $substr->[$k]; ($j++, $k++)) {}
if ($j == $end) {
return $i;
}
}
}
return -1;
}
sub INT8_MIN : byte () { return -128; }
sub INT8_MAX : byte () { return 127; }
sub INT16_MIN : short () { return -32768; }
sub INT16_MAX : short () { return 32767; }
sub INT32_MIN : int () { return -2147483648; }
sub INT32_MAX : int () { return 2147483647; }
sub UINT32_MAX : long () { return 4294967295L; }
sub INT64_MIN : long () { return -9223372036854775808L; }
sub INT64_MAX : long () { return 9223372036854775807L; }
native sub RAND_MAX : int ();
native sub DBL_MAX : double ();
native sub DBL_MIN : double ();
native sub FLT_MAX : float ();
native sub FLT_MIN : float();
sub isalnum : int ($char : int) {
if (($char >= 'A' && $char <= 'Z') || ($char >= 'a' && $char <= 'z') || ($char >= '0' && $char <= '9')) {
return 1;
}
else {
return 0;
}
}
sub isalpha : int ($char : int) {
if (($char >= 'A' && $char <= 'Z') || ($char >= 'a' && $char <= 'z')) {
return 1;
}
else {
return 0;
}
}
sub isblank : int ($char : int) {
if ($char >= ' ' || $char <= '\t') {
return 1;
}
else {
return 0;
}
}
sub iscntrl : int ($char : int) {
if (($char >= 0x00 && $char <= 0x1f) || $char == 0x7f) {
return 1;
}
else {
return 0;
}
}
sub isdigit : int ($char : int) {
if ($char >= '0' && $char <= '9') {
return 1;
}
else {
return 0;
}
}
sub isgraph : int ($char : int) {
if ($char >= 0x21 && $char <= 0x7e) {
return 1;
}
else {
return 0;
}
}
sub islower : int ($char : int) {
if ($char >= 'a' && $char <= 'z') {
return 1;
}
else {
return 0;
}
}
sub isprint : int ($char : int) {
if ($char >= 0x20 && $char <= 0x7e) {
return 1;
}
else {
return 0;
}
}
sub ispunct : int ($char : int) {
if (($char >= 0x21 && $char <= 0x2f) || ($char >= 0x3a && $char <= 0x40) || ($char >= 0x5b && $char <= 0x60) || ($char >= 0x7b && $char <= 0x7e)) {
return 1;
}
else {
return 0;
}
}
sub isspace : int ($char : int) {
if (($char >= 0x09 && $char <= 0x0d) || $char == 0x20) {
return 1;
}
else {
return 0;
}
}
sub isupper : int ($char : int) {
if ($char >= 'A' && $char <= 'Z') {
return 1;
}
else {
return 0;
}
}
sub isxdigit : int ($char : int) {
if (($char >= 'A' && $char <= 'F') || ($char >= 'a' && $char <= 'f') || ($char >= '0' && $char <= '9')) {
return 1;
}
else {
return 0;
}
}
sub tolower : int ($char : int) {
if ($char >= 'A' && $char <= 'Z') {
$char = $char + 0x20;
}
return $char;
}
sub toupper : int ($char : int) {
if ($char >= 'a' && $char <= 'z') {
$char = $char - 0x20;
}
return $char;
}
# This is same as Perl \s
sub is_perl_space : int ($char : int) {
my $ispspace = 0;
switch ($char) {
case ' ':
case '\r':
case '\n':
case '\t':
case '\f':
{
$ispspace = 1;
break;
}
}
return $ispspace;
}
sub is_perl_word : int ($char : int) {
my $ispword = 0;
if ($char >= 'a' && $char <= 'z') {
$ispword = 1;
}
elsif ($char >= 'A' && $char <= 'Z') {
$ispword = 1;
}
elsif ($char == '_') {
$ispword = 1;
}
elsif ($char >= '0' && $char <= '9') {
$ispword = 1;
}
return $ispword;
}
sub joinb : string ($sep : string, $nums : byte[]) {
my $join = "";
for (my $i = 0; $i < @$nums; $i++) {
my $string = (string)$nums->[$i];
$join .= $string;
if ($i != @$nums - 1) {
$join .= $sep;
}
}
return $join;
}
sub joins : string ($sep : string, $nums : short[]) {
my $join = "";
for (my $i = 0; $i < @$nums; $i++) {
my $string = (string)$nums->[$i];
$join .= $string;
if ($i != @$nums - 1) {
$join .= $sep;
}
}
return $join;
}
sub joini : string ($sep : string, $nums : int[]) {
my $join = "";
for (my $i = 0; $i < @$nums; $i++) {
my $string = (string)$nums->[$i];
$join .= $string;
if ($i != @$nums - 1) {
$join .= $sep;
}
}
return $join;
}
sub joinl : string ($sep : string, $nums : long[]) {
my $join = "";
for (my $i = 0; $i < @$nums; $i++) {
my $string = (string)$nums->[$i];
$join .= $string;
if ($i != @$nums - 1) {
$join .= $sep;
}
}
return $join;
}
sub joinf : string ($sep : string, $nums : float[]) {
my $join = "";
for (my $i = 0; $i < @$nums; $i++) {
my $string = (string)$nums->[$i];
$join .= $string;
if ($i != @$nums - 1) {
$join .= $sep;
}
}
return $join;
}
sub joind : string ($sep : string, $nums : double[]) {
my $join = "";
for (my $i = 0; $i < @$nums; $i++) {
my $string = (string)$nums->[$i];
$join .= $string;
if ($i != @$nums - 1) {
$join .= $sep;
}
}
return $join;
}
sub join : string ($sep : string, $strings : string[]) {
my $join = "";
for (my $i = 0; $i < @$strings; $i++) {
my $string = $strings->[$i];
$join .= $string;
if ($i != @$strings - 1) {
$join .= $sep;
}
}
return $join;
}
sub lc : string($str : string) {
unless ($str) { die "String must be defined"; }
my $length = length $str;
my $new_string = new byte [$length];
for (my $i = 0; $i < $length; $i++) {
my $char = $str->[$i];
if ($char >= 'A' && $char <= 'Z') {
$new_string->[$i] = (byte)($str->[$i] + 32);
}
else {
$new_string->[$i] = $str->[$i];
}
}
return (string)$new_string;
}
sub lcfirst : string($str : string) {
unless ($str) { die "String must be defined"; }
my $length = length $str;
my $new_string = new byte [$length];
if ($length > 0) {
my $char = $str->[0];
if ($char >= 'A' && $char <= 'Z') {
$new_string->[0] = (byte)($char + 32);
}
else {
$new_string->[0] = $char;
}
}
for (my $i = 1; $i < $length; ++$i) {
$new_string->[$i] = $str->[$i];
}
return (string)$new_string;
}
native sub memcpyb : void ($dest_data : byte[], $dest_offset : int, $src_data : byte[], $src_offset : int, $length : int);
native sub memcpys : void ($dest_data : short[], $dest_offset : int, $src_data : short[], $src_offset : int, $length : int);
native sub memcpyi : void ($dest_data : int[], $dest_offset : int, $src_data : int[], $src_offset : int, $length : int);
native sub memcpyl : void ($dest_data : long[], $dest_offset : int, $src_data : long[], $src_offset : int, $length : int);
native sub memcpyf : void ($dest_data : float[], $dest_offset : int, $src_data : float[], $src_offset : int, $length : int);
native sub memcpyd : void ($dest_data : double[], $dest_offset : int, $src_data : double[], $src_offset : int, $length : int);
native sub memmoveb : void ($dest_data : byte[], $dest_offset : int, $src_data : byte[], $src_offset : int, $length : int);
native sub memmoves : void ($dest_data : short[], $dest_offset : int, $src_data : short[], $src_offset : int, $length : int);
native sub memmovei : void ($dest_data : int[], $dest_offset : int, $src_data : int[], $src_offset : int, $length : int);
native sub memmovel : void ($dest_data : long[], $dest_offset : int, $src_data : long[], $src_offset : int, $length : int);
native sub memmovef : void ($dest_data : float[], $dest_offset : int, $src_data : float[], $src_offset : int, $length : int);
native sub memmoved : void ($dest_data : double[], $dest_offset : int, $src_data : double[], $src_offset : int, $length : int);
native sub new_object_array_proto : oarray ($proto_array : oarray, $length : int);
sub PI : double () { return 3.14159265358979323846; }
native sub srand : void ($seed : long);
native sub crand : int ();
sub rand : double () {
# 0 <= random_number < 1
my $random_number = (double)crand() / ((double)RAND_MAX() + 1);
return $random_number;
}
sub replace : string ($str : string, $substr : string, $replace : string, $start_offset : int, $found_offset_ref : int&) {
unless ($substr && length $substr > 0) {
die "Sub string must have length";
}
my $found_offset = index($str, $substr, $start_offset);
$$found_offset_ref = $found_offset;
if ($found_offset >= 0) {
my $str_len = length $str;
my $substr_len = length $substr;
my $replace_len = length $replace;
my $result_str_len = $str_len + $replace_len - $substr_len;
my $result_str = new byte[$result_str_len];
if ($found_offset > 0) {
memmoveb((byte[])$result_str, 0, (byte[])$str, 0, $found_offset);
}
memmoveb((byte[])$result_str, $found_offset, (byte[])$replace, 0, $replace_len);
my $str_rest_offset = $found_offset + $substr_len;
my $str_rest_length = $str_len - $str_rest_offset;
my $result_rest_offset = $found_offset + $replace_len;
my $result_rest_length = $result_str_len - $result_rest_offset;
memmoveb((byte[])$result_str, $result_rest_offset, (byte[])$str, $str_rest_offset, $str_rest_length);
return (string)$result_str;
}
else {
my $copy_str = copy_str($str);
return $copy_str;
}
}
sub replace_all : string ($str : string, $substr : string, $replace : string) {
unless ($str) { die "String must be defined"; }
my $offset = 0;
my $found_offset : int;
my $substr_len = length $substr;
my $result_str = $str;
while (1) {
$result_str = replace($result_str, $substr, $replace, $offset, \$found_offset);
if ($found_offset >= 0) {
$offset = $found_offset + $substr_len;
}
else {
return $result_str;
}
}
}
native sub strtoi : int ($string : string, $digit : int);
native sub strtol : long ($string : string, $digit : int);
native sub strtof : float ($string : string);
native sub strtod : double ($string : string);
sub uc : string($str : string) {
unless ($str) { die "String must be defined"; }
my $length = length $str;
my $new_string = new byte [$length];
for (my $i = 0; $i < $length; $i++) {
my $char = $str->[$i];
if ($char >= 'a' && $char <= 'z') {
$new_string->[$i] = (byte)($str->[$i] - 32);
}
else {
$new_string->[$i] = $str->[$i];
}
}
return (string)$new_string;
}
sub ucfirst : string($str : string) {
unless ($str) { die "String must be defined"; }
my $length = length $str;
my $new_string = new byte [$length];
if ($length > 0) {
my $char = $str->[0];
if ($char >= 'a' && $char <= 'z') {
$new_string->[0] = (byte)($char - 32);
}
else {
$new_string->[0] = $char;
}
}
for (my $i = 1; $i < $length; ++$i) {
$new_string->[$i] = $str->[$i];
}
return (string)$new_string;
}
sub rindex : int ($str : string, $substr : string, $offset : int) {
my $str_len = length $str;
my $substr_len = length $substr;
if ($offset > $str_len - $substr_len) {
$offset = $str_len - $substr_len;
}
for (my $i = $offset; $i >= 0; --$i) {
my $match = 1;
for (my $j = 0; $j < $substr_len; ++$j) {
if ($str->[$i + $j] != $substr->[$j]) {
$match = 0;
last;
}
}
if ($match) {
return $i;
}
}
return -1;
}
sub contains : int ($str : string, $substr : string) {
if (!$str) {
die "Target string must be defined";
}
if (!$substr) {
die "Search string must be defined";
}
my $pat_len = length $substr;
my $str_len = length $str;
my $i = 0;
my $j = 0;
while ($i < $str_len && $j < $pat_len) {
if ($str->[$i] == $substr->[$j]) {
$i++;
$j++;
} else {
$i = $i - $j + 1;
$j = 0;
}
}
if ($j == $pat_len) {
return 1;
}
else {
return 0;
}
}
native sub abs : int ($x : int);
native sub labs : long ($x : long);
native sub reverseb : void ($nums : byte[]);
native sub reverses : void ($nums : short[]);
native sub reversei : void ($nums : int[]);
native sub reversel : void ($nums : long[]);
native sub reversef : void ($nums : float[]);
native sub reversed : void ($nums : double[]);
native sub reverseo : void ($objs : oarray);
sub substr : string ($string : string, $offset : int, $length : int) {
if ($string == undef) {
die "String must be defined";
}
my $string_length = length $string;
if ($offset < 0 || $offset > $string_length - 1) {
die "Invalid offset $offset";
}
if ($length < 0) {
die "Length must be non-zero value";
}
if ($offset + $length > $string_length) {
die "Offset + length must not be over array length";
}
my $slice = new byte[$length];
my $pos = 0;
for (my $i = $offset; $i < $offset + $length; $i++) {
$slice->[$pos] = $string->[$i];
$pos++;
}
return (string)$slice;
}
sub sliceb : byte[] ($nums : byte[], $offset : int, $length : int) {
if ($nums == undef) {
die "Array must be defined";
}
my $array_length = @$nums;
if ($offset < 0 || $offset > $array_length - 1) {
die "Invalid offset $offset";
}
if ($length < 0) {
die "Length must be non-zero value";
}
if ($offset + $length > $array_length) {
die "Offset + length must not be over array length";
}
my $slice = new byte[$length];
my $pos = 0;
for (my $i = $offset; $i < $offset + $length; $i++) {
$slice->[$pos] = $nums->[$i];
$pos++;
}
return $slice;
}
sub slices : short[] ($nums : short[], $offset : int, $length : int) {
if ($nums == undef) {
die "Array must be defined";
}
my $array_length = @$nums;
if ($offset < 0 || $offset > $array_length - 1) {
die "Invalid offset $offset";
}
if ($length < 0) {
die "Length must be non-zero value";
}
if ($offset + $length > $array_length) {
die "Offset + length must not be over array length";
}
my $slice = new short[$length];
my $pos = 0;
for (my $i = $offset; $i < $offset + $length; $i++) {
$slice->[$pos] = $nums->[$i];
$pos++;
}
return $slice;
}
sub slicei : int[] ($nums : int[], $offset : int, $length : int) {
if ($nums == undef) {
die "Array must be defined";
}
my $array_length = @$nums;
if ($offset < 0 || $offset > $array_length - 1) {
die "Invalid offset $offset";
}
if ($length < 0) {
die "Length must be non-zero value";
}
if ($offset + $length > $array_length) {
die "Offset + length must not be over array length";
}
my $slice = new int[$length];
my $pos = 0;
for (my $i = $offset; $i < $offset + $length; $i++) {
$slice->[$pos] = $nums->[$i];
$pos++;
}
return $slice;
}
sub slicel : long[] ($nums : long[], $offset : int, $length : int) {
if ($nums == undef) {
die "Array must be defined";
}
my $array_length = @$nums;
if ($offset < 0 || $offset > $array_length - 1) {
die "Invalid offset $offset";
}
if ($length < 0) {
die "Length must be non-zero value";
}
if ($offset + $length > $array_length) {
die "Offset + length must not be over array length";
}
my $slice = new long[$length];
my $pos = 0;
for (my $i = $offset; $i < $offset + $length; $i++) {
$slice->[$pos] = $nums->[$i];
$pos++;
}
return $slice;
}
sub slicef : float[] ($nums : float[], $offset : int, $length : int) {
if ($nums == undef) {
die "Array must be defined";
}
my $array_length = @$nums;
if ($offset < 0 || $offset > $array_length - 1) {
die "Invalid offset $offset";
}
if ($length < 0) {
die "Length must be non-zero value";
}
if ($offset + $length > $array_length) {
die "Offset + length must not be over array length";
}
my $slice = new float[$length];
my $pos = 0;
for (my $i = $offset; $i < $offset + $length; $i++) {
$slice->[$pos] = $nums->[$i];
$pos++;
}
return $slice;
}
sub sliced : double[] ($nums : double[], $offset : int, $length : int) {
if ($nums == undef) {
die "Array must be defined";
}
my $array_length = @$nums;
if ($offset < 0 || $offset > $array_length - 1) {
die "Invalid offset $offset";
}
if ($length < 0) {
die "Length must be non-zero value";
}
if ($offset + $length > $array_length) {
die "Offset + length must not be over array length";
}
my $slice = new double[$length];
my $pos = 0;
for (my $i = $offset; $i < $offset + $length; $i++) {
$slice->[$pos] = $nums->[$i];
$pos++;
}
return $slice;
}
sub sliceo : oarray ($elems : oarray, $offset : int, $length : int) {
if ($elems == undef) {
die "Array must be defined";
}
my $array_length = @$elems;
if ($offset < 0 || $offset > $array_length - 1) {
die "Invalid offset $offset";
}
if ($length < 0) {
die "Length must be non-zero value";
}
if ($offset + $length > $array_length) {
die "Offset + length must not be over array length";
}
my $slice = new_object_array_proto($elems, $length);
my $pos = 0;
for (my $i = $offset; $i < $offset + $length; $i++) {
$slice->[$pos] = $elems->[$i];
$pos++;
}
return $slice;
}
}