Skip to content

Commit

Permalink
Finish unordered map std (#495)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer committed Mar 7, 2024
1 parent cc19010 commit 7b6f49f
Show file tree
Hide file tree
Showing 8 changed files with 361 additions and 98 deletions.
2 changes: 1 addition & 1 deletion .run/spice.run.xml
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="run -O0 -d ../../media/test-project/test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spice" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spice">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="run -O3 -d ../../media/test-project/test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spice" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spice">
<envs>
<env name="LLVM_BUILD_INCLUDE_DIR" value="D:/LLVM/build-release/include" />
<env name="LLVM_INCLUDE_DIR" value="D:/LLVM/llvm/include" />
Expand Down
112 changes: 40 additions & 72 deletions media/test-project/test.spice
@@ -1,77 +1,45 @@
type Speak interface {
p sayHello(string);
}

type MakeSound interface {
p makeSound();
}

type Human struct : MakeSound, Speak {
string firstName
string lastName
unsigned int age
}

p Human.ctor(string firstName, string lastName, unsigned int age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}

p Human.makeSound() {
printf("Sigh...\n");
}

p Human.sayHello(string name) {
printf("Hi, %s!\n", name);
}

type Car struct : MakeSound {
string brand
string model
unsigned int seats
}

p Car.ctor(string brand, string model, unsigned int seats) {
this.brand = brand;
this.model = model;
this.seats = seats;
}

p Car.makeSound() {
printf("Wroom, wroom!\n");
}

type Parrot struct : MakeSound, Speak {
string name
unsigned int age
}

p Parrot.ctor(string name, unsigned int age) {
this.name = name;
this.age = age;
}

p Parrot.makeSound() {
printf("Sqawk!\n");
}

p Parrot.sayHello(string name) {
printf("Hello %s, squawk!\n", name);
}
import "std/data/unordered-map";
import "std/time/timer";

f<int> main() {
Human human = Human("John", "Doe", 25);
Car car = Car("Toyota", "Corolla", 5);
Parrot parrot = Parrot("Polly", 3);

human.makeSound();
car.makeSound();
parrot.makeSound();

human.sayHello("Jane");
parrot.sayHello("Jane");
return 0;
Timer timer = Timer();
timer.start();

UnorderedMap<int, string> map = UnorderedMap<int, string>(3l);
assert map.getSize() == 0;
assert map.isEmpty();
map.upsert(1, "one");
map.upsert(2, "two");
map.upsert(3, "three");
map.upsert(4, "four");
assert map.getSize() == 4;
assert !map.isEmpty();
assert map.contains(1);
assert map.contains(2);
assert map.contains(3);
assert map.contains(4);
assert !map.contains(5);
assert map.get(1) == "one";
assert map.get(2) == "two";
assert map.get(3) == "three";
assert map.get(4) == "four";
const Result<string> item5 = map.getSafe(5);
assert item5.isErr();
map.remove(2);
assert !map.contains(2);
assert map.getSize() == 3;
map.clear();
assert map.getSize() == 0;
assert map.isEmpty();
map.upsert(1, "one");
map.upsert(1, "one new");
assert map.getSize() == 1;
assert map.get(1) == "one new";
map.remove(1);
assert map.isEmpty();

timer.stop();
printf("All assertions passed in %d microseconds!\n", timer.getDurationInMicros());
}

/*import "bootstrap/util/block-allocator";
Expand Down
121 changes: 104 additions & 17 deletions std/data/hash-table.spice
@@ -1,6 +1,7 @@
import "std/data/vector";
import "std/data/linked-list";
import "std/data/optional";
import "std/type/result";
import "std/type/error";
import "std/math/hash";

// Generic types for key and value
Expand All @@ -13,50 +14,136 @@ type HashEntry<K, V> struct {
}

public type HashTable<K, V> struct {
Vector<LinkedList<HashEntry<K, V>>> table
Vector<LinkedList<HashEntry<K, V>>> buckets
}

public p HashTable.ctor(unsigned long bucketCount = 100l) {
this.table = Vector<LinkedList<HashEntry<K, V>>>(bucketCount);
this.buckets = Vector<LinkedList<HashEntry<K, V>>>(bucketCount);
for unsigned long i = 0l; i < bucketCount; i++ {
this.table.pushBack(LinkedList<HashEntry<K, V>>());
this.buckets.pushBack(LinkedList<HashEntry<K, V>>());
}
}

/**
* Insert a key-value pair into the hash table.
* If the key already exists, the value is updated.
*
* @param key The key to insert
* @param value The value to insert
*/
public p HashTable.upsert(const K& key, const V& value) {
const unsigned long index = this.hash(key);
const LinkedList<HashEntry<K, V>>& list = this.table.get(index);
foreach const HashEntry<K, V>& entry : list {
const LinkedList<HashEntry<K, V>>& bucket = this.buckets.get(index);
foreach const HashEntry<K, V>& entry : bucket {
if (entry.key == key) {
entry.value = value;
return;
}
}
bucket.pushBack(HashEntry<K, V>{key, value});
}

public f<Optional<V>> HashTable.get(const K& key) {
/**
* Retrieve the value associated with the given key.
* If the key is not found, panic.
*
* @param key The key to look up
* @return The value associated with the key
*/
public f<V&> HashTable.get(const K& key) {
const unsigned long index = this.hash(key);
const LinkedList<HashEntry<K, V>>& list = this.table.get(index);
foreach const HashEntry<K, V>& entry : list {
const LinkedList<HashEntry<K, V>>& bucket = this.buckets.get(index);
foreach const HashEntry<K, V>& entry : bucket {
if (entry.key == key) {
return Optional<V>(entry.value);
return entry.value;
}
}
return Optional<V>();
panic(Error("The provided key was not found"));
}

/**
* Retrieve the value associated with the given key as Optional<T>.
* If the key is not found, return an empty optional.
*
* @param key The key to look up
* @return Optional<T>, containing the value associated with the key or empty if the key is not found
*/
public f<Result<V>> HashTable.getSafe(const K& key) {
const unsigned long index = this.hash(key);
const LinkedList<HashEntry<K, V>>& bucket = this.buckets.get(index);
foreach const HashEntry<K, V>& entry : bucket {
if (entry.key == key) {
return ok(entry.value);
}
}
return err<V>(Error("The provided key was not found"));
}

/**
* Remove the key-value pair associated with the given key.
* If the key is not found, do nothing.
*
* @param key The key to remove
*/
public p HashTable.remove(const K& key) {
const unsigned long index = this.hash(key);
LinkedList<HashEntry<K, V>>& list = this.table.get(index);
for (unsigned long i = 0l; i < list.getSize(); i++) {
if (list.get(i).key == key) {
list.remove(i);
LinkedList<HashEntry<K, V>>& bucket = this.buckets.get(index);
for unsigned long i = 0l; i < bucket.getSize(); i++ {
if (bucket.get(i).key == key) {
bucket.removeAt(i);
return;
}
}
}

/**
* Check if the hash table contains the given key.
*
* @param key The key to check for
* @return True if the key is found, false otherwise
*/
public f<bool> HashTable.contains(const K& key) {
const unsigned long index = this.hash(key);
const LinkedList<HashEntry<K, V>>& bucket = this.buckets.get(index);
foreach const HashEntry<K, V>& entry : bucket {
if (entry.key == key) {
return true;
}
}
return false;
}

/**
* Get the size of the hash table.
*
* @return The number of key-value pairs in the hash table
*/
public inline f<unsigned long> HashTable.getSize() {
result = 0l;
foreach LinkedList<HashEntry<K, V>>& bucket : this.buckets {
result += bucket.getSize();
}
}

/**
* Checks if the hash table is empty.
*
* @return True if empty, false otherwise.
*/
public inline f<bool> HashTable.isEmpty() {
return this.getSize() == 0l;
}

/**
* Clear the hash table, removing all key-value pairs.
*/
public inline p HashTable.clear() {
foreach LinkedList<HashEntry<K, V>>& bucket : this.buckets {
bucket.clear();
}
}

inline f<unsigned long> HashTable.hash(const K& key) {
K keyCopy = key;
return hash(keyCopy) % this.table.getSize();
const K keyCopy = key;
return hash(keyCopy) % this.buckets.getSize();
}

0 comments on commit 7b6f49f

Please sign in to comment.