Carp/core/Map.carp

247 lines
7.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(definterface hash (Fn [(Ref a)] Int))
(defmodule String
(defn rehash [k l]
(let-do [a 31415
b 27183
vh 0]
(for [x 0 (length k)]
(do
(set! vh (+ (* a (* vh l)) (Char.to-int (char-at k x))))
(set! a (* a b))
(set! x (Int.inc x))))
(Int.abs vh)))
(defn hash [k]
(rehash k 1))
)
(defmodule Int
(defn hash [k] (the Int @k))
)
(defmodule Long
(defn hash [k] (to-int (the Long @k)))
)
(defmodule Bool
(defn hash [k] (if (the Bool @k) 1 0))
)
(defmodule Char
(defn hash [k] (to-int (the Char @k)))
)
(defmodule Float
(defn hash [k] (to-bytes @k))
)
(defmodule Double
(defn hash [k] (Long.to-int (to-bytes @k)))
)
(deftype (Entry a b) [key a value b])
(deftype (Bucket a b) [entries (Array (Entry a b))])
(defmodule Bucket
(defn empty []
(Bucket.init []))
(defn grow [b e]
(set-entries @b (Array.push-back @(entries b) e)))
(defn get [b k]
(let-do [e &(zero)
l (Array.length (Bucket.entries b))
es (entries b)]
(for [i 0 l]
(when (= (Entry.key (Array.nth es i)) k)
(do
(set! e (Entry.value (Array.nth es i)))
(break))))
@e))
(defn contains? [b k]
(let-do [e false
l (Array.length (Bucket.entries b))
es (entries b)]
(for [i 0 l]
(when (= (Entry.key (Array.nth es i)) k)
(do
(set! e true)
(break))))
e))
(defn remove [entries k]
(let-do [nentries (the (Array (Entry a b)) [])]
(for [i 0 (Array.length entries)]
(let [e (Array.nth entries i)]
(unless (= (Entry.key e) k)
(set! nentries (Array.push-back nentries @e)))))
nentries))
(defn shrink [b k]
(if (contains? b k)
(set-entries @b (remove (entries b) k))
@b))
)
(deftype (Map a b) [n-buckets Int buckets (Array (Bucket a b))])
(defmodule Map
(hidden dflt-len)
(def dflt-len 256)
(doc create "Create an empty hashmap.")
(defn create []
(init dflt-len (Array.repeat dflt-len Bucket.empty)))
(doc create-with-len "Create an empty hashmap with a given minimum size.")
(defn create-with-len [len]
(init len (Array.repeat len Bucket.empty)))
(doc put "Put a a value v into map m, using the key k.")
(defn put [m k v]
(let [idx (Int.mod (hash k) @(n-buckets m))
b (buckets m)]
(set-buckets @m (Array.aset @b
idx
(Bucket.grow (Array.nth b idx) (Entry.init @k @v))))))
(doc get "Get the value for the key k from map m. If it isnt found, a zero element is returned.")
(defn get [m k]
(let [idx (Int.mod (hash k) @(n-buckets m))]
(Bucket.get (Array.nth (buckets m) idx) k)))
(doc length "Get the length of the map m.")
(defn length [m]
(let-do [c 0]
(for [i 0 @(n-buckets m)]
(set! c (+ c (Array.length (Bucket.entries (Array.nth (buckets m) i))))))
c))
(doc length "Check whether the map m is empty.")
(defn empty? [m]
(= (length m) 0))
(doc contains? "Check whether the map m contains the key k.")
(defn contains? [m k]
(let [idx (Int.mod (hash k) @(n-buckets m))]
(Bucket.contains? (Array.nth (buckets m) idx) k)))
(doc remove "Remove the value under the key k from the map m.")
(defn remove [m k]
(let [idx (Int.mod (hash k) @(n-buckets &m))
b (buckets &m)]
(set-buckets m (Array.aset @b
idx
(Bucket.shrink (Array.nth b idx) k)))))
(doc for-each "Execute the binary function f for all keys and value in map m.")
(defn for-each [m f]
(for [i 0 @(n-buckets m)]
(let [bucket (Array.nth (buckets m) i)
len (Array.length (Bucket.entries bucket))
entries (Bucket.entries bucket)]
(for [j 0 len]
(let [e (Array.nth entries j)]
(f (Entry.key e) (Entry.value e)))))))
(doc from-array "Create a map from the array a containing key-value pairs.")
(defn from-array [a]
(let-do [m (create)]
(for [i 0 (Array.length a)]
(let [e (Array.nth a i)
k (Pair.a e)
v (Pair.b e)]
(set! m (put &m k v))))
m))
(defn str [m]
(let-do [res @"{"]
(for [i 0 @(n-buckets m)]
(let [bucket (Array.nth (buckets m) i)
len (Array.length (Bucket.entries bucket))
entries (Bucket.entries bucket)]
(for [j 0 len]
(let [e (Array.nth entries j)]
(set! res (String.join @"" &[res @" " (prn @(Entry.key e)) @" " (prn @(Entry.value e))]))))))
(String.append &res " }")))
)
(deftype (Set a) [n-buckets Int buckets (Array (Bucket a Bool))])
(defmodule Set
(def dflt-len 256)
(doc create "Create an empty hashset.")
(defn create []
(init dflt-len (Array.repeat dflt-len Bucket.empty)))
(doc create-with-len "Create an empty hashset with a given minimum size.")
(defn create-with-len [len]
(init len (Array.repeat len Bucket.empty)))
(doc put "Put a a value v into set m, using the key k.")
(defn put [m k]
(let [idx (Int.mod (hash k) @(n-buckets m))
b (buckets m)]
(set-buckets @m (Array.aset @b
idx
(Bucket.grow (Array.nth b idx) (Entry.init @k true))))))
(doc length "Get the length of set m.")
(defn length [m]
(let-do [c 0]
(for [i 0 @(n-buckets m)]
(set! c (+ c (Array.length (Bucket.entries (Array.nth (buckets m) i))))))
c))
(doc empty? "Check whether the set m is empty.")
(defn empty? [m]
(= (length m) 0))
(doc contains? "Check whether the set m contains a value associated with key k.")
(defn contains? [m k]
(let [idx (Int.mod (hash k) @(n-buckets m))]
(Bucket.contains? (Array.nth (buckets m) idx) k)))
(doc remove "Remove the value associated with key k from set m.")
(defn remove [m k]
(let [idx (Int.mod (hash k) @(n-buckets &m))
b (buckets &m)]
(set-buckets m (Array.aset @b
idx
(Bucket.shrink (Array.nth b idx) k)))))
(doc for-each "Execute the unary function f for each element in set m.")
(defn for-each [m f]
(for [i 0 @(n-buckets m)]
(let [bucket (Array.nth (buckets m) i)
len (Array.length (Bucket.entries bucket))
entries (Bucket.entries bucket)]
(for [j 0 len]
(let [e (Array.nth entries j)]
(f (Entry.key e)))))))
(doc from-array "Create a set from the values in array a.")
(defn from-array [a]
(let-do [m (create)]
(for [i 0 (Array.length a)]
(let [e (Array.nth a i)]
(set! m (put &m e))))
m))
(defn str [m]
(let-do [res @"{"]
(for [i 0 @(n-buckets m)]
(let [bucket (Array.nth (buckets m) i)
len (Array.length (Bucket.entries bucket))
entries (Bucket.entries bucket)]
(for [j 0 len]
(let [e (Array.nth entries j)]
(set! res (String.join @"" &[res @" " (prn @(Entry.key e))]))))))
(String.append &res " }")))
)