package SPVM::StringBuffer : precompile {
use SPVM::Hash;
use SPVM::Util (sliceb);
has value : byte[];
has length : ro int;
private enum {
DEFAULT_CAPACITY = 16,
}
sub capacity : int ($self : self) {
return @$self->{value};
}
# O($new_capacity)
private sub _reallocate : void ($self : self, $new_capacity : int) {
my $new_string = new byte [$new_capacity];
for (my $i = 0; $i < $self->{length}; ++$i) {
$new_string->[$i] = $self->{value}[$i];
}
$self->{value} = $new_string;
}
sub new : SPVM::StringBuffer () {
my $self = new SPVM::StringBuffer;
my $default_capacity = DEFAULT_CAPACITY();
$self->{value} = new byte [$default_capacity];
$self->{length} = 0;
return $self;
}
sub push : void ($self : self, $string : string) {
my $length = length($string);
my $capacity = @$self->{value};
if ($self->{length} + $length > $capacity) {
my $new_capacity : int;
if ($self->{length} + $length > $capacity * 2) {
$new_capacity = $self->{length} + $length;
} else {
$new_capacity = $capacity * 2;
}
$self->_reallocate($new_capacity);
}
for (my $i = 0; $i < $length; ++$i) {
$self->{value}[$self->{length} + $i] = $string->[$i];
}
$self->{length} += $length;
}
sub push_char : void ($self : self, $char : byte) {
my $capacity = @$self->{value};
if ($self->{length} + 1 > $capacity) {
my $new_capacity = $capacity * 2;
$self->_reallocate($new_capacity);
}
$self->{value}[$self->{length}++] = $char;
}
sub push_range : void ($self : self, $string : string, $offset : int, $length : int) {
my $capacity = @$self->{value};
if ($self->{length} + $length > $capacity) {
my $new_capacity : int;
if ($self->{length} + $length > $capacity * 2) {
$new_capacity = $self->{length} + $length;
} else {
$new_capacity = $capacity * 2;
}
$self->_reallocate($new_capacity);
}
for (my $i = 0; $i < $length; ++$i) {
$self->{value}[$self->{length} + $i] = $string->[$offset + $i];
}
$self->{length} += $length;
}
sub to_string : string ($self : self) {
return (string)(sliceb($self->{value}, 0, $self->{length}));
}
sub substr : string ($self : self, $offset : int, $length : int) {
if ($offset >= $self->{length}) {
die("substr offset is greater or equal than string length");
}
my $new_text = new byte[$length];
for (my $i = 0; $i < $length; $i++) {
$new_text->[$i] = $self->{value}[$offset + $i];
}
return (string)$new_text;
}
sub index : int ($self : self, $search : string, $offset : int) {
my $slen = length $search;
for (my $i = $offset; $i < $self->{length} - $slen + 1; ++$i) {
my $found = 1;
for (my $j = 0; $j < $slen; ++$j) {
if ($self->{value}[$i + $j] != $search->[$j]) {
$found = 0;
last;
}
}
if ($found) {
return $i;
}
}
return -1;
}
sub clear : void ($self : self) {
$self->{length} = 0;
}
sub new_opt : SPVM::StringBuffer ($opt : SPVM::Hash) {
my $self = new SPVM::StringBuffer;
my $default_capacity : int;
if ($opt->exists("capacity")) {
$default_capacity = (int)$opt->delete("capacity");
}
else {
$default_capacity = DEFAULT_CAPACITY();
}
# Minimal capacity is 1
if ($default_capacity < 1) {
die "Invalid capacity";
}
$self->{value} = new byte [$default_capacity];
$self->{length} = 0;
return $self;
}
}