Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prelude: Map improvements #523

Merged
merged 2 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 4 additions & 32 deletions projects/compiler/example.abra
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
2 changes: 1 addition & 1 deletion projects/compiler/test/compiler/process_callstack.abra
Original file line number Diff line number Diff line change
Expand Up @@ -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 <expression> (%STD_DIR%/prelude.abra:782)
/// Expect: at <expression> (%STD_DIR%/prelude.abra:780)
/// Expect: at Array.map (%TEST_DIR%/compiler/process_callstack.abra:18)

type OneTwoThreeIterator {
Expand Down
108 changes: 76 additions & 32 deletions projects/std/src/prelude.abra
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ type RangeIterator {

func range(start: Int, end: Int, stepBy = 1): RangeIterator = RangeIterator(start: start, end: end, stepBy: stepBy)

func flattenOption<T>(value: T??): T? = if value |v| v else None

type Int {
func asByte(self): Byte = Byte.fromInt(self)

Expand Down Expand Up @@ -1181,23 +1179,37 @@ type Set<T> {
}
}

// @Intrinsic("uninitialized")
// func uninitialized<T>(): T

type MapEntry<K, V> {
key: K
value: V
next: MapEntry<K, V>? = None
// _empty: Bool = false

// func empty<K, V>(): MapEntry<K, V> {
// MapEntry(
// key: intrinsics.uninitialized(),
// value: intrinsics.uninitialized(),
// next: None
// _empty: true
// )
// }
_empty: Bool = false

func empty<K, V>(): MapEntry<K, V> {
MapEntry(
key: intrinsics.uninitialized(),
value: intrinsics.uninitialized(),
_empty: true,
)
}

func toString(self): String {
if self._empty return "MapEntry(key: <uninitialized>, value: <uninitialized>, next: ${self.next}, _empty: true)"

"MapEntry(key: ${self.key}, value: ${self.value}, next: ${self.next}, _empty: false)"
}

func eq(self, other: MapEntry<K, V>): 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<K, V> {
Expand All @@ -1208,7 +1220,11 @@ type MapIterator<K, V> {
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| {
Expand All @@ -1222,7 +1238,7 @@ type MapIterator<K, V> {

type Map<K, V> {
size: Int
_entries: MapEntry<K, V>?[] = []
_entries: MapEntry<K, V>[] = []
_capacity: Int = 16
_loadFactor: Float = 0.75

Expand All @@ -1234,7 +1250,11 @@ type Map<K, V> {
initialCapacity
}

val entries: MapEntry<K, V>?[] = Array.fill(capacity, None)
val entries: MapEntry<K, V>[] = Array.withCapacity(capacity)
for _ in range(0, capacity) {
entries.push(MapEntry.empty())
}

Map(size: 0, _capacity: capacity, _entries: entries)
}

Expand All @@ -1252,7 +1272,9 @@ type Map<K, V> {
val reprs: String[] = Array.withCapacity(self.size)
for i in range(0, self._entries.length) {
if self._entries[i] |bucket| {
var cursor: MapEntry<K, V>? = bucket
if bucket._empty continue

var cursor: MapEntry<K, V>? = Some(bucket)
while cursor |cur| {
reprs.push("${cur.key}: ${cur.value}")
cursor = cur.next
Expand All @@ -1269,7 +1291,9 @@ type Map<K, V> {

for i in range(0, self._entries.length) {
if self._entries[i] |bucket| {
var cursor: MapEntry<K, V>? = bucket
if bucket._empty continue

var cursor: MapEntry<K, V>? = Some(bucket)

while cursor |cur| {
if other.get(cur.key) |otherValue| {
Expand All @@ -1290,7 +1314,9 @@ type Map<K, V> {
func forEach(self, fn: (K, V) => Unit) {
for i in range(0, self._entries.length) {
if self._entries[i] |bucket| {
var cursor: MapEntry<K, V>? = bucket
if bucket._empty continue

var cursor: MapEntry<K, V>? = Some(bucket)
while cursor |cur| {
fn(cur.key, cur.value)
cursor = cur.next
Expand Down Expand Up @@ -1338,7 +1364,9 @@ type Map<K, V> {
val newMap: Map<K, U> = Map.new()
for i in range(0, self._entries.length) {
if self._entries[i] |bucket| {
var cursor: MapEntry<K, V>? = bucket
if bucket._empty continue

var cursor: MapEntry<K, V>? = Some(bucket)
while cursor |cur| {
newMap.insert(cur.key, fn(cur.key, cur.value))
cursor = cur.next
Expand All @@ -1350,20 +1378,28 @@ type Map<K, V> {
}

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<K, V>?[]): (V?, Bool) {
func _insertInto(self, key: K, value: V, entries: MapEntry<K, V>[]): (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<K, V>? = Some(bucket)
while cursor |cur| {
if cur.key == key {
Expand All @@ -1381,15 +1417,19 @@ type Map<K, V> {
// 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)
}
}

func _resize(self) {
val newCapacity = self._capacity * 2

val newEntries: MapEntry<K, V>?[] = Array.fill(newCapacity, None)
val newEntries: MapEntry<K, V>[] = Array.withCapacity(newCapacity)
for _ in range(0, newCapacity) {
newEntries.push(MapEntry.empty())
}

for entry in self {
val key = entry[0]
val value = entry[1]
Expand All @@ -1403,7 +1443,9 @@ type Map<K, V> {
func _getEntry(self, key: K): MapEntry<K, V>? {
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 {
Expand Down Expand Up @@ -1445,9 +1487,11 @@ type Map<K, V> {
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)
}
Expand Down
Loading