Skip to content

Commit

Permalink
Overload subscript operator for Vector, Map and UnorderedMap (#706)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer authored Jan 12, 2025
1 parent 75d3241 commit 524e910
Show file tree
Hide file tree
Showing 12 changed files with 132 additions and 107 deletions.
132 changes: 47 additions & 85 deletions media/test-project/test.spice
Original file line number Diff line number Diff line change
@@ -1,88 +1,50 @@
type Size alias long;

type Counter struct {
Size value
}

p Counter.ctor(long initialValue = 0l) {
this.value = initialValue;
}

f<Size> Counter.getValue() {
return this.value;
}

f<Counter> operator+(const Counter c1, const Counter c2) {
return Counter(c1.value + c2.value);
}

f<Counter> operator-(const Counter c1, const Counter c2) {
return Counter(c1.value - c2.value);
}

f<Counter> operator*(const Counter c1, const Counter c2) {
return Counter(c1.value * c2.value);
}

f<Counter> operator/(const Counter c1, const Counter c2) {
return Counter(c1.value / c2.value);
}

f<Counter> operator<<(const Counter c1, const Counter c2) {
return Counter(c1.value << c2.value);
}

f<Counter> operator>>(const Counter c1, const Counter c2) {
return Counter(c1.value >> c2.value);
}

p operator+=(Counter& c1, const Counter c2) {
c1.value += c2.value;
}

p operator-=(Counter& c1, const Counter c2) {
c1.value -= c2.value;
}

p operator*=(Counter& c1, const Counter c2) {
c1.value *= c2.value;
}

p operator/=(Counter& c1, const Counter c2) {
c1.value /= c2.value;
}

f<Size&> operator[](Counter& c, unsigned int summand) {
c.value += summand;
return c.value;
}
import "std/data/map";

f<int> main() {
Counter counter1 = Counter(2l);
Counter counter2 = Counter(3l);
printf("Counter1 value: %d\n", counter1.getValue());
printf("Counter2 value: %d\n", counter2.getValue());
Counter counter3 = counter1 + counter2; // Here we call the overloaded operator
printf("Counter3 value: %d\n", counter3.getValue());
Counter counter4 = counter3 - counter2; // Here we call the overloaded operator
printf("Counter4 value: %d\n", counter4.getValue());
Counter counter5 = counter4 * counter2; // Here we call the overloaded operator
printf("Counter5 value: %d\n", counter5.getValue());
Counter counter6 = counter5 / counter2; // Here we call the overloaded operator
printf("Counter6 value: %d\n", counter6.getValue());
Counter counter7 = counter6 << counter2; // Here we call the overloaded operator
printf("Counter7 value: %d\n", counter7.getValue());
Counter counter8 = counter7 >> counter2; // Here we call the overloaded operator
printf("Counter8 value: %d\n", counter8.getValue());
counter8 += counter2; // Here we call the overloaded operator
printf("Counter8 value: %d\n", counter8.getValue());
counter8 -= counter2; // Here we call the overloaded operator
printf("Counter8 value: %d\n", counter8.getValue());
counter8 *= counter2; // Here we call the overloaded operator
printf("Counter8 value: %d\n", counter8.getValue());
counter8 /= counter2; // Here we call the overloaded operator
printf("Counter8 value: %d\n", counter8.getValue());
Size res = counter8[12];
assert res == 14;
printf("Counter8 value: %d\n", counter8.getValue());
Map<int, string> map;
assert map.getSize() == 0l;
assert map.isEmpty();
map.insert(1, "Hello");
assert map.getSize() == 1l;
assert !map.isEmpty();
map.insert(2, "World");
assert map.getSize() == 2l;
map.insert(3, "Foo");
assert map.getSize() == 3l;
map.insert(4, "Bar");
assert map.getSize() == 4l;
assert map.contains(1);
assert map.contains(2);
assert map.contains(3);
assert map.contains(4);
assert map.get(1) == "Hello";
assert map[2] == "World";
assert map.get(3) == "Foo";
assert map.get(4) == "Bar";
map.remove(2);
assert map.getSize() == 3l;
assert !map.contains(2);
assert !map.isEmpty();
map.remove(1);
assert map.getSize() == 2l;
assert !map.contains(1);
assert !map.isEmpty();
string& foo = map.get(3);
assert foo == "Foo";
foo = "Baz";
assert map[3] == "Baz";
Result<string> bar = map.getSafe(4);
assert bar.isOk();
assert bar.unwrap() == "Bar";
Result<string> baz = map.getSafe(5);
assert baz.isErr();
map.remove(3);
assert map.getSize() == 1l;
assert !map.contains(3);
assert !map.isEmpty();
map.remove(4);
assert map.getSize() == 0l;
assert !map.contains(4);
assert map.isEmpty();
printf("All assertions passed!\n");
}
2 changes: 1 addition & 1 deletion src/irgenerator/GenExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ std::any IRGenerator::visitPostfixUnaryExpr(const PostfixUnaryExprNode *node) {
ResolverFct lhsV = [&] { return resolveValue(lhsSTy, lhs); };
ResolverFct lhsP = [&] { return resolveAddress(lhs); };
ResolverFct idxV = [&] { return resolveValue(indexExpr); };
ResolverFct idxP = [&] { return nullptr; };
ResolverFct idxP = [&] { return resolveAddress(indexExpr); };
lhs = conversionManager.callOperatorOverloadFct<2>(node, {lhsV, lhsP, idxV, idxP}, 0);
break;
}
Expand Down
18 changes: 15 additions & 3 deletions std/data/map.spice
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public p Map.remove(const K& key) {
}

/**
* Gets a value from the map.
* Retrieve the value associated with the given key.
* Note: If the key is not found in the map, this function will panic. To avoid this, use getSafe instead.
*
* @param key The key to get.
Expand All @@ -50,10 +50,22 @@ public f<V&> Map.get(const K& key) {
}

/**
* Gets a value from the map, returning a result.
* Retrieve the value associated with the given key.
* Note: If the key is not found in the map, this function will panic. To avoid this, use getSafe instead.
*
* @param key The key to get.
* @return The value associated with the key, or an error if the key does not exist.
* @return The value associated with the key.
*/
public f<V&> operator[]<K, V>(Map<K, V>& map, const K& key) {
return map.get(key);
}

/**
* Retrieve the value associated with the given key as Result<V>.
* If the key is not found, the result contains an error.
*
* @param key The key to look up
* @return Result<V>, containing the value associated with the key or an error if the key is not found
*/
public f<Result<V>> Map.getSafe(const K& key) {
return this.tree.findSafe(key);
Expand Down
17 changes: 14 additions & 3 deletions std/data/unordered-map.spice
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,22 @@ public f<V&> UnorderedMap.get(const K& key) {
}

/**
* Retrieve the value associated with the given key as Optional<T>.
* If the key is not found, return an empty optional.
* 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&> operator[]<K, V>(UnorderedMap<K, V>& map, const K& key) {
return map.get(key);
}

/**
* Retrieve the value associated with the given key as Result<V>.
* If the key is not found, the result contains an error.
*
* @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
* @return Result<V>, containing the value associated with the key or an error if the key is not found
*/
public f<Result<V>> UnorderedMap.getSafe(const K& key) {
return this.hashTable.getSafe(key);
Expand Down
21 changes: 19 additions & 2 deletions std/data/vector.spice
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,7 @@ public f<T&> Vector.get(unsigned long index) {
panic(Error("Access index out of bounds"));
}
unsafe {
T& t = this.contents[index];
return t;
return this.contents[index];
}
}

Expand All @@ -120,6 +119,24 @@ public f<T&> Vector.get(unsigned int index) {
return this.get((unsigned long) index);
}

/**
* Get an item at a certain index
*
* @return item at index
*/
public f<T&> operator[]<T>(Vector<T>& v, unsigned long index) {
return v.get(index);
}

/**
* Get an item at a certain index
*
* @return item at index
*/
public f<T&> operator[]<T>(Vector<T>& v, unsigned int index) {
return v.get((unsigned long) index);
}

/**
* Remove an item at a certain index
*
Expand Down
4 changes: 3 additions & 1 deletion std/runtime/string_rt.spice
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,9 @@ public f<bool> operator!=(const string& a, const String& b) {
* @return Character at the given index
*/
public f<char&> operator[](String& str, unsigned long idx) {
assert idx < str.length;
if idx >= str.length {
panic(Error("Access index out of bounds"));
}
unsafe {
return str.contents[idx];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -534,11 +534,11 @@ attributes #2 = { cold noreturn nounwind }
!42 = !{!"branch_weights", i32 2000, i32 1}
!43 = !DILocation(line: 13, column: 14, scope: !15)
!44 = !DILocalVariable(name: "it", scope: !15, file: !5, line: 13, type: !45)
!45 = !DICompositeType(tag: DW_TAG_structure_type, name: "VectorIterator", scope: !5, file: !5, line: 263, size: 192, align: 8, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !46, identifier: "struct.VectorIterator")
!45 = !DICompositeType(tag: DW_TAG_structure_type, name: "VectorIterator", scope: !5, file: !5, line: 280, size: 192, align: 8, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !46, identifier: "struct.VectorIterator")
!46 = !{!47, !49}
!47 = !DIDerivedType(tag: DW_TAG_member, name: "vector", scope: !45, file: !5, line: 264, baseType: !48, size: 64, offset: 64)
!47 = !DIDerivedType(tag: DW_TAG_member, name: "vector", scope: !45, file: !5, line: 281, baseType: !48, size: 64, offset: 64)
!48 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !28, size: 64)
!49 = !DIDerivedType(tag: DW_TAG_member, name: "cursor", scope: !45, file: !5, line: 265, baseType: !33, size: 64, offset: 128)
!49 = !DIDerivedType(tag: DW_TAG_member, name: "cursor", scope: !45, file: !5, line: 282, baseType: !33, size: 64, offset: 128)
!50 = !DILocation(line: 13, column: 5, scope: !15)
!51 = !DILocation(line: 14, column: 12, scope: !15)
!52 = !DILocation(line: 15, column: 12, scope: !15)
Expand Down
3 changes: 3 additions & 0 deletions test/test-files/std/data/combined-test-2/cout.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Hexxo
Depr
World
18 changes: 18 additions & 0 deletions test/test-files/std/data/combined-test-2/source.spice
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import "std/data/vector";

f<int> main() {
Vector<String> vec;
vec.pushBack(String("Hello"));
vec.pushBack(String("Dear"));
vec.pushBack(String("\n World"));

vec[1][2] = 'p';
String& item0 = vec[0];
item0.replaceAll("l", "x");
String& item2 = vec.get(2);
item2 = item2.trim();

foreach String s : vec {
printf("%s\n", s);
}
}
4 changes: 2 additions & 2 deletions test/test-files/std/data/map-normal-usecase/source.spice
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ f<int> main() {
assert map.contains(3);
assert map.contains(4);
assert map.get(1) == "Hello";
assert map.get(2) == "World";
assert map[2] == "World";
assert map.get(3) == "Foo";
assert map.get(4) == "Bar";
map.remove(2);
Expand All @@ -32,7 +32,7 @@ f<int> main() {
string& foo = map.get(3);
assert foo == "Foo";
foo = "Baz";
assert map.get(3) == "Baz";
assert map[3] == "Baz";
Result<string> bar = map.getSafe(4);
assert bar.isOk();
assert bar.unwrap() == "Bar";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ f<int> main() {
assert map.contains(4);
assert !map.contains(5);
assert map.get(1) == "one";
assert map.get(2) == "two";
assert map[2] == "two";
assert map.get(3) == "three";
assert map.get(4) == "four";
const Result<string> item5 = map.getSafe(5);
Expand All @@ -30,7 +30,7 @@ f<int> main() {
map.upsert(1, "one");
map.upsert(1, "one new");
assert map.getSize() == 1;
assert map.get(1) == "one new";
assert map[1] == "one new";
map.remove(1);
assert map.isEmpty();

Expand Down
10 changes: 5 additions & 5 deletions test/test-files/std/data/vector-normal-usecase/source.spice
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ f<int> main() {
v1.removeAt(0);
assert v1.getSize() == 5;
assert v1.getCapacity() == 12;
assert v1.get(0) == 7.4964598;
assert v1.get(1) == 5.3;
assert v1.get(2) == -238974.23;
assert v1.get(3) == -1234.9;
assert v1.get(4) == 0.0;
assert v1[0] == 7.4964598;
assert v1[1] == 5.3;
assert v1[2] == -238974.23;
assert v1[3] == -1234.9;
assert v1[4] == 0.0;

printf("All assertions passed!\n");
}

0 comments on commit 524e910

Please sign in to comment.