class TestCase::Module::Hash {
use Int;
use Hash;
use Comparator;
use List;
use Fn;
use Array;
use Fn;
use Array;
use Comparator;
use Comparator::Int;
use Sort;
use Point;
our $HASH_OF_INT : cache Hash of Int;
our $HASH_OF_INT_ARRAY : cache Hash of Int[];
static method new : int () {
# Without arguments
{
my $hash = Hash->new;
my $keys = $hash->keys;
unless (@$keys == 0) {
return 0;
}
}
# undef
{
my $hash = Hash->new((object[])undef);
my $keys = $hash->keys;
unless (@$keys == 0) {
return 0;
}
}
# Empty array
{
my $hash = Hash->new({});
my $keys = $hash->keys;
unless (@$keys == 0) {
return 0;
}
}
# int values
{
my $hash = Hash->new({foo => 1, bar => 3L});
my $keys = $hash->keys;
unless (@$keys == 2) {
return 0;
}
{
my $foo = (Int)$hash->get("foo");
unless ($foo->value == 1) {
return 0;
}
my $bar = (Long)$hash->get("bar");
unless ($bar->value == 3) {
return 0;
}
}
{
my $foo = (int)$hash->get("foo");
unless ($foo == 1) {
return 0;
}
}
}
# string values
{
my $hash = Hash->new({foo => "4px", bar => "5px"});
my $keys = $hash->keys;
unless (@$keys == 2) {
return 0;
}
{
my $foo = (string)$hash->get("foo");
unless ($foo && $foo eq "4px") {
return 0;
}
my $bar = (string)$hash->get("bar");
unless ($bar && $bar eq "5px") {
return 0;
}
}
}
# string and int values
{
my $hash = Hash->new({foo => "4px", bar => 3});
my $keys = $hash->keys;
unless (@$keys == 2) {
return 0;
}
{
my $foo = $hash->{"foo"}->(string);
unless ($foo && $foo eq "4px") {
return 0;
}
my $bar = $hash->{"bar"}->(int);
unless ($bar && $bar == 3) {
return 0;
}
}
}
# Key is numeric object
{
my $hash = Hash->new({1 => "4px"});
unless ($hash->{"1"}->(string) eq "4px") {
return 0;
}
}
# Exception
{
# odd number array
{
eval { Hash->new([(object)foo => "4px", "bar"]); };
unless ($@) {
return 0;
}
}
}
# Hash access
{
{
my $hash = (Hash of string)Hash->new({foo => "4px", bar => "3", baz => "4"});
my $value = $hash->{"foo"};
unless ($value eq "4px") {
return 0;
}
$hash->{"foo"} = "2";
unless ($hash->{"foo"} eq "2") {
return 0;
}
$hash->{"bar"} = $hash->{"bar"} . "a";
unless ($hash->{"bar"} eq "3a") {
return 0;
}
$hash->{"baz"} .= "a";
unless ($hash->{"baz"} eq "4a") {
return 0;
}
}
{
my $hash = (Hash of List of string)Hash->new({foo => List->new(["a", "b"]), bar => List->new(["c", "d"])});
unless ($hash->{"foo"}[0] eq "a") {
return 0;
}
}
{
my $hash = (Hash of string[])Hash->new({foo => ["a", "b"], bar => ["c", "d"]});
unless ($hash->{"foo"}[0] eq "a") {
return 0;
}
}
{
my $list = (List of Hash of string)List->new([Hash->new({foo => "a"}), Hash->new({bar => "b"})]);
unless ($list->[1]{"bar"} eq "b") {
return 0;
}
}
}
return 1;
}
static method set : int () {
my $keys = ["alice", "bob", "carol", "1234567890-="];
my $vals = [Int->new(1), Int->new(2), undef, Int->new(3)];
my $hash = Hash->new;
for (my $i = 0; $i < @$keys; ++$i) {
$hash->set($keys->[$i], $vals->[$i]);
}
unless ($hash->keys_length == @$keys) {
return 0;
}
for (my $i = 0; $i < @$keys; ++$i) {
unless ($hash->get($keys->[$i]) == $vals->[$i]) {
return 0;
}
}
return 1;
}
static method set_do_not_refer_caller_key : int () {
my $hash = Hash->new;
my $key = "a";
$hash->set($key, Int->new(1));
$key = "b";
unless ($hash->exists("a")) {
return 0;
}
unless ($hash->exists("b") == 0) {
return 0;
}
return 1;
}
static method get : int () {
my $hash = Hash->new;
$hash->set("a" => 1);
$hash->set("b" => undef);
$hash->set("c" => "str");
unless (((Int)($hash->get("a")))->value == 1) {
return 0;
}
unless ($hash->get("b") == undef) {
return 0;
}
unless (((string)$hash->get("c")) eq "str") {
return 0;
}
unless ($hash->get("no_key") == undef) {
return 0;
}
# Exceptions
{
my $hash = Hash->new;
eval { $hash->get(undef); }
unless (Fn->contains($@, "The key \$key must be defined.")) {
return 0;
}
}
# Generics
{
my $hash = (Hash of Int)Hash->new;
$hash->set("a" => 1);
unless ($hash->get("a")->value == 1) {
return 0;
}
}
return 1;
}
static method exists : int () {
my $keys = ["alice", "bob"];
my $vals = [Int->new(1), Int->new(2)];
my $hash = Hash->new;
for (my $i = 0; $i < @$keys; ++$i) {
$hash->set($keys->[$i], $vals->[$i]);
}
for (my $i = 0; $i < @$keys; ++$i) {
unless ($hash->exists($keys->[$i])) {
return 0;
}
}
unless ($hash->exists("carol") == 0) {
return 0;
}
# Exceptions
{
my $hash = Hash->new;
eval { $hash->exists(undef); }
unless (Fn->contains($@, "The key \$key must be defined.")) {
return 0;
}
}
return 1;
}
static method delete : int () {
{
my $success = &delete_with_no_hash_collision;
unless ($success) {
return 0;
}
}
{
my $success = &delete_with_hash_collision;
unless ($success) {
return 0;
}
}
# Exceptions
{
my $hash = Hash->new;
eval { $hash->delete(undef); }
unless (Fn->contains($@, "The key \$key must be defined.")) {
return 0;
}
}
# Generics
{
my $hash = (Hash of Int)Hash->new;
$hash->set("a" => 1);
unless ($hash->delete("a")->value == 1) {
return 0;
}
}
return 1;
}
static method delete_with_no_hash_collision : int () {
my $hash = Hash->new;
$hash->set("alice", Int->new(1));
$hash->set("bob", Int->new(2));
unless (((Int)($hash->delete("alice")))->value == 1) {
return 0;
}
unless ($hash->exists("alice") == 0) {
return 0;
}
unless ($hash->keys_length == 1) {
return 0;
}
unless ($hash->delete("alice") == undef) {
return 0;
}
unless ($hash->delete("carol") == undef) {
return 0;
}
unless ($hash->keys_length == 1) {
return 0;
}
unless ($hash->exists("bob") == 1) {
return 0;
}
return 1;
}
static method delete_with_hash_collision : int () {
my $hash = Hash->new;
$hash->set("alice", Int->new(1));
$hash->set("bob", Int->new(2));
unless (((Int)$hash->delete("alice"))->value == 1) {
return 0;
}
unless ($hash->exists("alice") == 0) {
return 0;
}
unless ($hash->keys_length == 1) {
return 0;
}
unless ($hash->delete("alice") == undef) {
return 0;
}
unless ($hash->keys_length == 1) {
return 0;
}
unless ($hash->exists("bob") == 1) {
return 0;
}
unless (((Int)($hash->delete("bob")))->value == 2) {
return 0;
}
unless ($hash->keys_length == 0) {
return 0;
}
unless ($hash->exists("bob") == 0) {
return 0;
}
return 1;
}
static method rehash : int () {
my $initial_capacity = 16;
my $hash = Hash->new;
for (my $i = 0; $i < 14; ++$i) {
my $key = "key" . $i;
$hash->set($key => $i);
}
unless (@{$hash->_entries} == $initial_capacity * 2) {
return 0;
}
unless ($hash->{"key12"}->(int) == 12) {
return 0;
}
return 1;
}
static method keys : int () {
my $hash = Hash->new;
my $key0 = "a";
my $key1 = "b";
my $key2 = (mutable string)new_string_len(1);
$key2->[0] = 'c';
$hash->set($key0 => 1);
$hash->set($key1 => 2);
$hash->set($key2 => 3);
my $keys = $hash->keys;
unless (@$keys == 3) {
return 0;
}
Sort->sort_string_asc($keys);
unless ($keys->[0] == $key0) {
return 0;
}
unless ($keys->[1] == $key1) {
return 0;
}
unless ($keys->[2] eq $key2) {
return 0;
}
unless ($keys->[2] != $key2) {
return 0;
}
return 1;
}
static method has_keys : int () {
my $hash = Hash->new;
if ($hash->has_keys) {
return 0;
}
$hash->set("key0" => 1);
unless ($hash->has_keys) {
return 0;
}
return 1;
}
static method values : int () {
my $hash = Hash->new;
my $key0 = "a";
my $key1 = "b";
my $key2 = "c";
$hash->set($key0 => 1);
$hash->set($key1 => 2);
$hash->set($key2 => 3);
my $values = $hash->values;
unless (@$values == 3) {
return 0;
}
my $int_values = new int[3];
$int_values->[0] = (int)$values->[0];
$int_values->[1] = (int)$values->[1];
$int_values->[2] = (int)$values->[2];
Sort->sort_int_asc($int_values);
unless ($int_values->[0] == 1) {
return 0;
}
unless ($int_values->[1] == 2) {
return 0;
}
unless ($int_values->[2] == 3) {
return 0;
}
return 1;
}
static method copy : int () {
my $hash = Hash->new;
for (my $i = 0; $i < 3; ++$i) {
$hash->set("key$i", $i);
}
my $copied = $hash->copy;
for (my $i = 0; $i < 3; ++$i) {
unless (((Int)$copied->get("key$i"))->value == $i) {
return 0;
}
}
$copied->set("extra_key", 123);
if ($hash->exists("extra_keys")) {
return 0;
}
unless ($copied->exists("extra_key")) {
return 0;
}
return 1;
}
static method clone : int () {
my $hash = Hash->new;
for (my $i = 0; $i < 3; ++$i) {
$hash->set("key$i", $i);
}
my $clone = (Hash)$hash->(Cloneable)->clone;
for (my $i = 0; $i < 3; ++$i) {
unless (((Int)$clone->get("key$i"))->value == $i) {
return 0;
}
}
$clone->set("extra_key", 123);
if ($hash->exists("extra_keys")) {
return 0;
}
unless ($clone->exists("extra_key")) {
return 0;
}
return 1;
}
static method to_array : int () {
{
my $hash = Hash->new;
for (my $i = 0; $i < 3; ++$i) {
$hash->set("key$i", $i);
}
my $array = $hash->to_array;
my $new_hash = Hash->new($array);
my $keys_new_hash = $new_hash->keys;
unless (@$keys_new_hash == 3) {
return 0;
}
unless ($new_hash->{"key0"}->(int) == 0) {
return 0;
}
unless ($new_hash->{"key1"}->(int) == 1) {
return 0;
}
unless ($new_hash->{"key2"}->(int) == 2) {
return 0;
}
}
{
my $hash = Hash->new;
for (my $i = 0; $i < 3; ++$i) {
$hash->set("key$i", $i);
}
{
my $sort = 1;
my $array = $hash->to_array($sort);
unless ($array->[0]->(string) eq "key0") {
return 0;
}
unless ($array->[1]->(int) == 0) {
return 0;
}
unless ($array->[2]->(string) eq "key1") {
return 0;
}
unless ($array->[3]->(int) == 1) {
return 0;
}
unless ($array->[4]->(string) eq "key2") {
return 0;
}
unless ($array->[5]->(int) == 2) {
return 0;
}
}
{
my $sort = -1;
my $array = $hash->to_array($sort);
unless ($array->[4]->(string) eq "key0") {
return 0;
}
unless ($array->[5]->(int) == 0) {
return 0;
}
unless ($array->[2]->(string) eq "key1") {
return 0;
}
unless ($array->[3]->(int) == 1) {
return 0;
}
unless ($array->[0]->(string) eq "key2") {
return 0;
}
unless ($array->[1]->(int) == 2) {
return 0;
}
}
}
{
my $hash = Hash->new;
my $array = $hash->to_array;
if (is_options $array) {
return 0;
}
}
return 1;
}
static method to_options : int () {
{
my $hash = Hash->new;
for (my $i = 0; $i < 3; ++$i) {
$hash->set("key$i", $i);
}
my $array = $hash->to_options;
my $new_hash = Hash->new($array);
my $keys_new_hash = $new_hash->keys;
unless (@$keys_new_hash == 3) {
return 0;
}
unless ($new_hash->{"key0"}->(int) == 0) {
return 0;
}
unless ($new_hash->{"key1"}->(int) == 1) {
return 0;
}
unless ($new_hash->{"key2"}->(int) == 2) {
return 0;
}
}
{
my $hash = Hash->new;
my $array = $hash->to_options;
unless (is_options $array) {
return 0;
}
}
return 1;
}
static method get_or_default : int () {
my $hash = Hash->new;
{
my $str = "bar";
$hash->set(foo => $str);
my $default = "abc";
my $value = $hash->get_or_default("foo", $default);
unless ($value == $str) {
return 0;
}
$hash->delete("foo");
unless ($hash->get_or_default("foo", $default) == $default) {
return 0;
}
}
# Generics
{
my $hash = (Hash of Int)Hash->new;
$hash->set("a" => 1);
unless ($hash->get_or_default("a", 2)->value == 1) {
return 0;
}
}
return 1;
}
static method weaken : int () {
{
my $hash = Hash->new;
my $key = "key";
my $value = Int->new(1);
$hash->set($key, $value);
$hash->weaken($key);
unless ($hash->isweak($key)) {
return 0;
}
$hash->unweaken($key);
if ($hash->isweak($key)) {
return 0;
}
}
{
my $hash = Hash->new;
my $key = "key";
$hash->weaken($key);
if ($hash->isweak($key)) {
return 0;
}
$hash->unweaken($key);
if ($hash->isweak($key)) {
return 0;
}
}
# Exceptions
{
my $hash = Hash->new;
eval { $hash->weaken(undef); }
unless (Fn->contains($@, "The key \$key must be defined.")) {
return 0;
}
}
return 1;
}
static method unweaken : int () {
{
my $hash = Hash->new;
my $key = "key";
my $value = Int->new(1);
$hash->set($key, $value);
$hash->weaken($key);
unless ($hash->isweak($key)) {
return 0;
}
$hash->unweaken($key);
if ($hash->isweak($key)) {
return 0;
}
}
{
my $hash = Hash->new;
my $key = "key";
$hash->weaken($key);
if ($hash->isweak($key)) {
return 0;
}
$hash->unweaken($key);
if ($hash->isweak($key)) {
return 0;
}
}
# Exceptions
{
my $hash = Hash->new;
eval { $hash->unweaken(undef); }
unless (Fn->contains($@, "The key \$key must be defined.")) {
return 0;
}
}
return 1;
}
static method isweak : int () {
{
my $hash = Hash->new;
my $key = "key";
my $value = Int->new(1);
$hash->set($key, $value);
$hash->weaken($key);
unless ($hash->isweak($key)) {
return 0;
}
$hash->unweaken($key);
if ($hash->isweak($key)) {
return 0;
}
}
{
my $hash = Hash->new;
my $key = "key";
$hash->weaken($key);
if ($hash->isweak($key)) {
return 0;
}
$hash->unweaken($key);
if ($hash->isweak($key)) {
return 0;
}
}
# Exceptions
{
my $hash = Hash->new;
eval { $hash->isweak(undef); }
unless (Fn->contains($@, "The key \$key must be defined.")) {
return 0;
}
}
return 1;
}
static method extra : int () {
# The type of a key is int type
{
my $hash = Hash->new([(string)
100 => "a",
200 => "b",
]);
unless ($hash->{"100"}->(string) eq "a") {
return 0;
}
}
# Generics
{
my $hash = (Hash of List of Callback)Hash->new({foo => List->new([method : void () {}])});
my $list = $hash->get("foo");
unless ($list is_compile_type List) {
return 0;
}
my $value = $list->get(0);
unless ($value is_compile_type Callback) {
return 0;
}
}
# With ternary operator
# https://github.com/yuki-kimoto/SPVM/issues/821
{
my $hash = Hash->new({expiration => 1});
my $expiration = $hash->exists("expiration") ? $hash->{"expiration"} : (object)undef;
unless ($expiration->(int) == 1) {
return 0;
}
}
# Hash access with defined-or operator
{
my $hash = Hash->new;
$hash->{"foo"} //= Int->new(1);
unless ($hash->{"foo"}->(int) == 1) {
return 0;
}
}
# Hash access with defined-or operator for class variable
{
{
$HASH_OF_INT = Hash->new;
$HASH_OF_INT->{"foo"} //= Int->new(1);
unless ($HASH_OF_INT->{"foo"}->(int) == 1) {
return 0;
}
}
{
$HASH_OF_INT_ARRAY = Hash->new;
$HASH_OF_INT_ARRAY->{"foo"} //= new Int[1];
unless ($HASH_OF_INT_ARRAY->{"foo"}[0]->(int) == 0) {
return 0;
}
}
}
return 1;
}
static method new_from_keys : int () {
{
my $keys = ["a", "b"];
my $hash = Hash->new_from_keys($keys, 1);
unless (@{$hash->keys} == 2) {
return 0;
}
unless ($hash->{"a"}->(int) == 1) {
return 0;
}
unless ($hash->{"b"}->(int) == 1) {
return 0;
}
}
return 1;
}
static method merge : int () {
{
my $hash = Hash->new({a => 1});
$hash->merge(Hash->new({a => 2, b => 3, c => 4}));
unless (@{$hash->keys} == 3) {
return 0;
}
unless ($hash->{"a"}->(int) == 2) {
return 0;
}
unless ($hash->{"b"}->(int) == 3) {
return 0;
}
unless ($hash->{"c"}->(int) == 4) {
return 0;
}
}
return 1;
}
static method merge_options : int () {
{
my $hash = Hash->new({a => 1});
$hash->merge_options({a => 2, b => 3, c => 4});
unless (@{$hash->keys} == 3) {
return 0;
}
unless ($hash->{"a"}->(int) == 2) {
return 0;
}
unless ($hash->{"b"}->(int) == 3) {
return 0;
}
unless ($hash->{"c"}->(int) == 4) {
return 0;
}
}
return 1;
}
}