package SPVM::LongList : precompile { use SPVM::ArrayUtil (memcpy_long, memmove_long); has values : long[]; has capacity : int; has length : ro int; private enum { DEFAULT_CAPACITY = 16, } sub new : SPVM::LongList ($array : long[]) { my $self = new SPVM::LongList; my $length : int; if ($array) { $length = @$array; } else { $length = 0; } my $capacity = 0; if ($length < DEFAULT_CAPACITY()) { $capacity = DEFAULT_CAPACITY(); } else { $capacity = $length; } $self->{capacity} = $capacity; my $values = new long[$capacity]; $self->{length} = $length; if ($array) { memcpy_long($values, 0, $array, 0, $length); } $self->{values} = $values; return $self; } sub new_len : SPVM::LongList ($length : int) { my $self = new SPVM::LongList; unless ($length >= 0) { die "length must be more than or equals to zero"; } my $capacity = 0; if ($length < DEFAULT_CAPACITY()) { $capacity = DEFAULT_CAPACITY(); } else { $capacity = $length; } $self->{capacity} = $capacity; $self->{length} = $length; $self->{values} = new long[$capacity]; return $self; } private sub _extend_with_capacity : void ($self : self, $new_capacity : int) { my $new_values = new long [$new_capacity]; for (my $i = 0; $i < $self->{length}; ++$i) { my $target = $i; if ($target < 0) { $target += $self->{capacity}; }; $new_values->[$i] = $self->{values}[$target]; } $self->{capacity} = $new_capacity; $self->{values} = $new_values; } private sub _extend : void ($self : self) { my $capacity = $self->{capacity}; my $length = $self->{length}; my $values = $self->{values}; my $new_capacity = $capacity * 2; my $new_values = new long[$new_capacity]; memcpy_long($new_values, 0, $values, 0, $length); $self->{values} = $new_values; $self->{capacity} = $new_capacity; } sub insert : void ($self : self, $index : int, $value : long) { my $length = $self->{length}; my $capacity = $self->{capacity}; unless ($index >= 0 && $index <= $length) { die "Out of range"; } if ($length >= $capacity) { $self->_extend; } my $values = $self->{values}; if ($index != $length) { my $dist_index = $index + 1; my $move_length = $length - $index; memmove_long($values, $dist_index, $values, $index, $move_length); } $values->[$index] = $value; $self->{length}++; } sub remove : long ($self : self, $index : int) { my $length = $self->{length}; my $capacity = $self->{capacity}; unless ($index >= 0 && $index < $length) { die "Out of range"; } my $values = $self->{values}; my $remove_value = $values->[$index]; my $dist_index = $index; my $src_index = $index + 1; my $move_length = $length - $index - 1; memmove_long($values, $dist_index, $values, $src_index, $move_length); $self->{length}--; return $remove_value; } sub push : void ($self : self, $value : long) { my $length = $self->{length}; my $capacity = $self->{capacity}; if ($length >= $capacity) { $self->_extend; } $self->{values}[$length] = $value; $self->{length}++; } sub pop : long ($self : self) { my $length = $self->length; if ($length == 0) { die "Can't pop"; } my $value = $self->{values}[$length - 1]; $self->{values}[$length - 1] = 0; $self->{length}--; return $value; } sub unshift : void ($self : self, $value : long) { my $length = $self->{length}; my $capacity = $self->{capacity}; if ($length >= $capacity) { $self->_extend; } my $values = $self->{values}; memmove_long($values, 1, $values, 0, $length); $values->[0] = $value; $self->{length}++; } sub shift : long ($self : self) { my $length = $self->{length}; my $capacity = $self->{capacity}; if ($length == 0) { die "Can't shift"; } my $values = $self->{values}; my $value = $values->[0]; memmove_long($values, 0, $values, 1, $length - 1); $values->[$length - 1] = 0; $self->{length}--; return $value; } sub set : void ($self : self, $index : int, $value : long) { my $length = $self->length; if ($index < 0 || $index > $length - 1) { die "Out of range"; } $self->{values}[$index] = $value; } sub set_array : void ($self : self, $array : long[]) { unless ($array) { die "Array must be defined"; } my $cur_length = $self->length; my $set_length = @$array; unless ($set_length == $cur_length) { die "The length of argument array must be same as the length of current list array"; } SPVM::ArrayUtil->memcpy_long($self->{values}, 0, $array, 0, $cur_length); } sub get : long ($self : self, $index : int) { my $length = $self->length; if ($index < 0 || $index > $length - 1) { die "Out of range"; } my $value = $self->{values}[$index]; return $value; } sub to_array : long[] ($self : self) { my $length = $self->length; my $array = new long[$length]; my $values = $self->{values}; memcpy_long($array, 0, $values, 0, $length); return $array; } sub resize : void ($self : self, $new_length : int) { if ($new_length < 0) { die "New length must be more than or equals to 0"; } my $length = $self->{length}; my $capacity = $self->{capacity}; if ($new_length > $length) { if ($new_length > $capacity) { $self->_extend_with_capacity($new_length); } for (my $i = $length; $i < $new_length; $i++) { $self->{values}[$i] = 0; } } elsif ($new_length < $length) { for (my $i = $new_length; $i < $length; $i++) { $self->{values}[$i] = 0; } } $self->{length} = $new_length; } }