diff --git a/projects/compiler/example.abra b/projects/compiler/example.abra index d6d124cc..d109fda3 100644 --- a/projects/compiler/example.abra +++ b/projects/compiler/example.abra @@ -4,37 +4,9 @@ val m = { c: 3, s: 4 } +println(m.size) println(m) -// println("a", m._getKeyHash("a", m._entries._capacity)) -// println("b", m._getKeyHash("b", m._entries._capacity)) -// println("c", m._getKeyHash("c", m._entries._capacity)) -// println("d", m._getKeyHash("d", m._entries._capacity)) -// println("e", m._getKeyHash("e", m._entries._capacity)) -// println("f", m._getKeyHash("f", m._entries._capacity)) -// println("g", m._getKeyHash("g", m._entries._capacity)) -// println("h", m._getKeyHash("h", m._entries._capacity)) -// println("i", m._getKeyHash("i", m._entries._capacity)) -// println("j", m._getKeyHash("j", m._entries._capacity)) -// println("k", m._getKeyHash("k", m._entries._capacity)) -// println("l", m._getKeyHash("l", m._entries._capacity)) -// println("m", m._getKeyHash("m", m._entries._capacity)) -// println("n", m._getKeyHash("n", m._entries._capacity)) -// println("o", m._getKeyHash("o", m._entries._capacity)) -// println("p", m._getKeyHash("p", m._entries._capacity)) -// println("q", m._getKeyHash("q", m._entries._capacity)) -// println("r", m._getKeyHash("r", m._entries._capacity)) -// println("s", m._getKeyHash("s", m._entries._capacity)) -// println("t", m._getKeyHash("t", m._entries._capacity)) -// println("u", m._getKeyHash("u", m._entries._capacity)) -// println("v", m._getKeyHash("v", m._entries._capacity)) -// println("w", m._getKeyHash("w", m._entries._capacity)) -// println("x", m._getKeyHash("x", m._entries._capacity)) -// println("y", m._getKeyHash("y", m._entries._capacity)) -// println("z", m._getKeyHash("z", m._entries._capacity)) - -println(m.remove("d")) -println(m) - -println(m.remove("s")) -println(m) +for (k, v) in m { + println(k, v) +} diff --git a/projects/compiler/test/compiler/process_callstack.abra b/projects/compiler/test/compiler/process_callstack.abra index bfda563a..a4e492a0 100644 --- a/projects/compiler/test/compiler/process_callstack.abra +++ b/projects/compiler/test/compiler/process_callstack.abra @@ -26,7 +26,7 @@ val arr = [1].map((i, _) => { /// Expect: at baz (%TEST_DIR%/compiler/process_callstack.abra:10) /// Expect: at bar (%TEST_DIR%/compiler/process_callstack.abra:5) /// Expect: at foo (%TEST_DIR%/compiler/process_callstack.abra:19) -/// Expect: at (%STD_DIR%/prelude.abra:782) +/// Expect: at (%STD_DIR%/prelude.abra:780) /// Expect: at Array.map (%TEST_DIR%/compiler/process_callstack.abra:18) type OneTwoThreeIterator { diff --git a/projects/std/src/prelude.abra b/projects/std/src/prelude.abra index 3bee04b3..13cd72d0 100644 --- a/projects/std/src/prelude.abra +++ b/projects/std/src/prelude.abra @@ -64,8 +64,6 @@ type RangeIterator { func range(start: Int, end: Int, stepBy = 1): RangeIterator = RangeIterator(start: start, end: end, stepBy: stepBy) -func flattenOption(value: T??): T? = if value |v| v else None - type Int { func asByte(self): Byte = Byte.fromInt(self) @@ -1181,23 +1179,37 @@ type Set { } } -// @Intrinsic("uninitialized") -// func uninitialized(): T - type MapEntry { key: K value: V next: MapEntry? = None - // _empty: Bool = false - - // func empty(): MapEntry { - // MapEntry( - // key: intrinsics.uninitialized(), - // value: intrinsics.uninitialized(), - // next: None - // _empty: true - // ) - // } + _empty: Bool = false + + func empty(): MapEntry { + MapEntry( + key: intrinsics.uninitialized(), + value: intrinsics.uninitialized(), + _empty: true, + ) + } + + func toString(self): String { + if self._empty return "MapEntry(key: , value: , next: ${self.next}, _empty: true)" + + "MapEntry(key: ${self.key}, value: ${self.value}, next: ${self.next}, _empty: false)" + } + + func eq(self, other: MapEntry): Bool { + if self._empty return other._empty + + self.key == other.key && self.value == other.value && self.next == other.next + } + + func hash(self): Int { + if self._empty return self._empty.hash() + + self.key.hash() + self.value.hash() + } } type MapIterator { @@ -1208,7 +1220,11 @@ type MapIterator { func next(self): (K, V)? { while self._i < self.map._entries.length && !self._cursor { self._i += 1 - self._cursor = flattenOption(self.map._entries[self._i]) + if self.map._entries[self._i] |entry| { + if entry._empty continue + + self._cursor = self.map._entries[self._i] + } } if self._cursor |cur| { @@ -1222,7 +1238,7 @@ type MapIterator { type Map { size: Int - _entries: MapEntry?[] = [] + _entries: MapEntry[] = [] _capacity: Int = 16 _loadFactor: Float = 0.75 @@ -1234,7 +1250,11 @@ type Map { initialCapacity } - val entries: MapEntry?[] = Array.fill(capacity, None) + val entries: MapEntry[] = Array.withCapacity(capacity) + for _ in range(0, capacity) { + entries.push(MapEntry.empty()) + } + Map(size: 0, _capacity: capacity, _entries: entries) } @@ -1252,7 +1272,9 @@ type Map { val reprs: String[] = Array.withCapacity(self.size) for i in range(0, self._entries.length) { if self._entries[i] |bucket| { - var cursor: MapEntry? = bucket + if bucket._empty continue + + var cursor: MapEntry? = Some(bucket) while cursor |cur| { reprs.push("${cur.key}: ${cur.value}") cursor = cur.next @@ -1269,7 +1291,9 @@ type Map { for i in range(0, self._entries.length) { if self._entries[i] |bucket| { - var cursor: MapEntry? = bucket + if bucket._empty continue + + var cursor: MapEntry? = Some(bucket) while cursor |cur| { if other.get(cur.key) |otherValue| { @@ -1290,7 +1314,9 @@ type Map { func forEach(self, fn: (K, V) => Unit) { for i in range(0, self._entries.length) { if self._entries[i] |bucket| { - var cursor: MapEntry? = bucket + if bucket._empty continue + + var cursor: MapEntry? = Some(bucket) while cursor |cur| { fn(cur.key, cur.value) cursor = cur.next @@ -1338,7 +1364,9 @@ type Map { val newMap: Map = Map.new() for i in range(0, self._entries.length) { if self._entries[i] |bucket| { - var cursor: MapEntry? = bucket + if bucket._empty continue + + var cursor: MapEntry? = Some(bucket) while cursor |cur| { newMap.insert(cur.key, fn(cur.key, cur.value)) cursor = cur.next @@ -1350,20 +1378,28 @@ type Map { } func insert(self, key: K, value: V): V? { - val res = self._insertInto(key, value, self._entries) - if res[1] { self.size += 1 } + val (oldValue, valueAdded) = self._insertInto(key, value, self._entries) + if valueAdded { self.size += 1 } if self._needsResize() self._resize() - res[0] + oldValue } func _needsResize(self): Bool = self.size > self._capacity * self._loadFactor - func _insertInto(self, key: K, value: V, entries: MapEntry?[]): (V?, Bool) { + func _insertInto(self, key: K, value: V, entries: MapEntry[]): (V?, Bool) { val hash = self._getKeyHash(key, entries._capacity) - if flattenOption(entries[hash]) |bucket| { + if entries[hash] |bucket| { + if bucket._empty { + bucket._empty = false + bucket.key = key + bucket.value = value + + return (None, true) + } + var cursor: MapEntry? = Some(bucket) while cursor |cur| { if cur.key == key { @@ -1381,7 +1417,7 @@ type Map { // Should be unreachable since loop will always eventually result in a return (None, false) } else { - entries[hash] = Some(MapEntry(key: key, value: value)) + entries[hash] = MapEntry(key: key, value: value) (None, true) } } @@ -1389,7 +1425,11 @@ type Map { func _resize(self) { val newCapacity = self._capacity * 2 - val newEntries: MapEntry?[] = Array.fill(newCapacity, None) + val newEntries: MapEntry[] = Array.withCapacity(newCapacity) + for _ in range(0, newCapacity) { + newEntries.push(MapEntry.empty()) + } + for entry in self { val key = entry[0] val value = entry[1] @@ -1403,7 +1443,9 @@ type Map { func _getEntry(self, key: K): MapEntry? { val hash = self._getKeyHash(key, self._entries._capacity) - val bucketRootEntry = if flattenOption(self._entries[hash]) |b| b else return None + val bucketRootEntry = if self._entries[hash] |b| b else return None + if bucketRootEntry._empty return None + var cursor = Some(bucketRootEntry) while cursor |entry| { if entry.key == key { @@ -1445,9 +1487,11 @@ type Map { func remove(self, key: K): V? { val hash = self._getKeyHash(key, self._entries._capacity) - val bucketRootEntry = if flattenOption(self._entries[hash]) |e| e else return None + val bucketRootEntry = if self._entries[hash] |e| e else return None + if bucketRootEntry._empty return None + if bucketRootEntry.key == key { - self._entries[hash] = bucketRootEntry.next + self._entries[hash] = if bucketRootEntry.next |next| next else MapEntry.empty() self.size -= 1 return Some(bucketRootEntry.value) }