From 0d2db659cac210e4d1610263dffd58a7fd453e1a Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Wed, 24 Sep 2025 12:33:48 -0500 Subject: [PATCH] Work on Map sketching and related. --- sketching/september_2025/map/Map.dm | 166 +++++++++++++++++++++++++--- 1 file changed, 153 insertions(+), 13 deletions(-) diff --git a/sketching/september_2025/map/Map.dm b/sketching/september_2025/map/Map.dm index b25577b..da18ca5 100644 --- a/sketching/september_2025/map/Map.dm +++ b/sketching/september_2025/map/Map.dm @@ -1,3 +1,120 @@ +pub trait Functor[Self] + fn map(mapper: fn (t: &T) -> U) -> Self +end + +pub trait Sum + fn sum() -> T +end + +pub trait Default + fn default() -> Self +end + +pub trait Iter + ref fn iter() -> Iterator<&T> +end + +pub trait ConsIter + cons fn consIter() -> Iterator +end + +pub int Iterator + fn next() -> Option +end + +pub int List impl Functor, Iter, ConsIter + fn add(t: T) -> Void +end + +pub class ArrayList : List + let mut currentIndex = 0 + let mut inner: Array + + ctor(capacity: Int) where T impl Default + inner = Array(capacity, Default[T]) + end + + ctor(capacity: Int, init: fn () -> T) + inner = Array(capacity, init) + end + + impl fn add(t: T) -> Void + inner[currentIndex] = t + let currentCapacity = inner.capacity() + currentIndex++ + if currentIndex == currentCapacity then + let oldInner = std::mem::take(inner, Array(currentCapacity * 2)) + arrays::copy(oldInner, inner) + end + end +end + +impl Functor[ArrayList<*>] + fn map(mapper: fn (t: &T) -> U) -> Self + let mut result: Array = Array(inner.capacity) + for (i, t) in inner.iterWithIndex() do + result[i] = mapper(t) + end + result + end +end + +impl Sum[Self = List, T = Int] + fn sum() -> Int + let mut result = 0 + for value in self do + result += value + end + result + end +end + +impl Default[ArrayList] + const DEFAULT_SIZE = 10 + + static fn default() -> Self = ArrayList(DEFAULT_SIZE, Default[T]::default) +end + +impl Iter[ArrayList] + ref fn iter() -> Iterator<&T> + let mut currentIndex = 0 + return { + if currentIndex < inner.count() then + let item = inner[currentIndex] + currentIndex++ + Some(item) + else + None + end + } + end +end + +impl ConsIter[ArrayList] + cons fn consIter() -> Iterator + let mut currentIndex = 0 + let inner = std::mem::take(inner, std::arrays::empty()) + return |inner| { + if currentIndex < inner.count() then + let item = inner.take(currentIndex, Default[T]::default) + currentIndex++ + Some(item) + else + None + end + } + end +end + +pub enum Option + Some(t: T), + None +end + +impl Default[Option<*>] + static fn default() -> Self = None +end + pub trait HashCode fn hash() -> USize end @@ -8,37 +125,60 @@ pub int Map fn take(key: K) -> Option end -pub class HashMap(hasher: impl HashCode[K]) : Map - +pub class HashMap : Map + where K impl HashCode + + const LOAD_FACTOR = 0.8 + class Entry(pub key: K, pub value: V) end - - let mut buckets: List>> = ArrayList(size: 10, init: { [] }) - + + let mut buckets: List>>> = ArrayList(10) + fn getBucketIndex(key: K) -> Int - hasher.hash(key) & buckets.size() + HashCode[K].hash(key) % buckets.size() end - + + fn getCount() -> Int = buckets.map { it.count() }.sum::() + + fn getCapacity() -> Int = buckets.map { it.capacity() }.sum::() + + fn redistribute() + use std::mem::take + let oldBucketCapacity = buckets.first().unwrap().capacity() + let oldBuckets = take(buckets, ArrayList(oldBucketCapacity * 2)) + for bucket in oldBuckets.consIter() do + for entry in bucket.consIter() do + let newIndex = getBucketIndex(entry.key) + let newBucket = buckets[newIndex] + newBucket.add(Entry(entry.key, entry.value)) + end + end + end + impl fn put(key: K, value: V) -> Void let bucket = buckets[getBucketIndex(key)] bucket.add(Entry(key, value)) + if getCount() / getCapacity() > LOAD_FACTOR then + redistribute() + end end - + impl fn get(key: K) -> Option<&V> let bucket = buckets[getBucketIndex(key)] // bucket: &List> bucket.find { it.key == key } // it: &Entry .map { it.value } // it.value: &V end - + impl fn take(key: K) -> Option - let mut bucket = buckets.take(getBucketIndex(key), []) // bucket: List> + let mut bucket = buckets.take(getBucketIndex(key)) // bucket: List> if bucket.findIndex { it.key == key } is Some(index) then - let entry = bucket.remove(index) // entry: Entry + let entry = bucket.take(index) // entry: Entry Some(entry.value) // moved out of Entry else None end end - + end impl HashCode for String @@ -48,7 +188,7 @@ end class Greeter(pub greeting: String) end fn main() - let greeterMap: Map = HashMap(HashCode[]) // Short for HashCode[String] + let greeterMap: Map = HashMap() greeterMap.put("friendly", Greeter("Friendly hello!")) greeterMap.put("nasty", Greeter("Nasty hello!")) let friendlyGreeter: &Greeter = greeterMap.get("friendly").unwrap()