-
Notifications
You must be signed in to change notification settings - Fork 323
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
Map Implementation #1222
Map Implementation #1222
Changes from all commits
f94d8f9
60847ca
d073110
3d78a94
fa9ac54
0c95b79
06041d8
ac21ca8
a77b20c
05f69b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
COMP_PATH=$(dirname "$0")/../component | ||
exec java -jar -Dtruffle.class.path.append="$COMP_PATH/runtime.jar" -Dpolyglot.engine.IterativePartialEscape=true $JAVA_OPTS $COMP_PATH/runner.jar "$@" | ||
exec java -jar -Dtruffle.class.path.append="$COMP_PATH/runtime.jar" $JAVA_OPTS $COMP_PATH/runner.jar "$@" | ||
exit |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
from Base import all | ||
import Base.Data.Map.Internal | ||
|
||
## An error for getting a missing value from a map. | ||
type No_Value_For_Key key | ||
|
||
## A key-value store. This type assumes all keys are pairwise comparable, | ||
using the `<`, `>` and `==` operators. | ||
type Map | ||
type Tip | ||
type Bin s key value left right | ||
|
||
## Checks if the map is empty. | ||
is_empty : Boolean | ||
is_empty = case this of | ||
Bin _ _ _ _ _ -> False | ||
Tip -> True | ||
|
||
## Returns the number of entries in this map. | ||
size : Integer | ||
size = case this of | ||
Bin s _ _ _ _ -> s | ||
Tip -> 0 | ||
|
||
## Converts the map into a vector of `[key, value]` pairs. | ||
The returned vector is sorted in the increasing order of keys. | ||
to_vector : Vector | ||
to_vector = | ||
builder = Vector.new_builder | ||
to_vector_with_builder m = case m of | ||
Bin _ k v l r -> | ||
to_vector_with_builder l | ||
builder.append [k, v] | ||
to_vector_with_builder r | ||
Unit | ||
Tip -> Unit | ||
to_vector_with_builder this | ||
result = builder.to_vector | ||
result | ||
|
||
## Returns a text representation of this map. | ||
to_text : Text | ||
to_text = this.to_vector.to_text | ||
|
||
## Checks if this map is equal to another map. | ||
|
||
Maps are equal when they contained the same keys and the values | ||
associated with each key are pairwise equal. | ||
== : Map -> Boolean | ||
== that = this.to_vector == that.to_vector | ||
|
||
## Maps a function over each value in this map. | ||
map : (Any -> Any) -> Map | ||
map function = case this of | ||
Bin s k v l r -> | ||
Bin s k (function v) (l.map function) (r.map function) | ||
Tip -> Tip | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to see a |
||
## Gets the value associated with `key` in this map, or returns a | ||
`No_Value_For_Key` error, if `key` is not present. | ||
get : Any -> Any ! No_Value_For_Key | ||
get key = | ||
Comment on lines
+61
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we not want a more general |
||
go map = case map of | ||
Tip -> Error.throw (No_Value_For_Key key) | ||
Bin _ k v l r -> | ||
if k == key then v else | ||
if k > key then @Tail_Call go l else @Tail_Call go r | ||
result = go this | ||
result | ||
|
||
## Inserts a key-value mapping into this map. If `key` is already present, | ||
it will be overriden with the new `value`. | ||
insert : Any -> Any -> Map | ||
insert key value = Internal.insert this key value | ||
|
||
## Returns an empty map. | ||
empty : Map | ||
empty = Tip | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
from Base import all | ||
from Base.Data.Map import all | ||
|
||
## PRIVATE | ||
|
||
Helper used in the insert operation. | ||
insert_l key value k v l r = | ||
new_left = here.insert l key value | ||
here.balance_left k v new_left r | ||
|
||
## PRIVATE | ||
|
||
Helper used in the insert operation. | ||
insert_r key value k v l r = | ||
new_right = here.insert r key value | ||
here.balance_right k v l new_right | ||
|
||
## PRIVATE | ||
|
||
Helper for inserting a new key-value pair into a map. | ||
|
||
The algorithm used here is based on the paper "Implementing Sets Efficiently | ||
in a Functional Language" by Stephen Adams. | ||
Implementation is based on Haskell's `Data.Map.Strict` implemented in the | ||
`containers` package. | ||
insert map key value = case map of | ||
Bin s k v l r -> | ||
if key > k then @Tail_Call here.insert_r key value k v l r else | ||
if key == k then @Tail_Call Bin s k value l r else | ||
@Tail_Call here.insert_l key value k v l r | ||
_ -> Bin 1 key value Tip Tip | ||
|
||
## PRIVATE | ||
|
||
Rebalances the map after the left subtree grows. | ||
balance_left k x l r = case r of | ||
Bin rs _ _ _ _ -> case l of | ||
Bin ls lk lx ll lr -> | ||
if ls <= Delta*rs then Bin 1+ls+rs k x l r else | ||
lls = here.size ll | ||
case lr of | ||
Bin lrs lrk lrx lrl lrr -> | ||
if lrs < Ratio*lls then Bin 1+ls+rs lk lx ll (Bin 1+rs+lrs k x lr r) else | ||
lrls = here.size lrl | ||
lrrs = here.size lrr | ||
Bin 1+ls+rs lrk lrx (Bin 1+lls+lrls lk lx ll lrl) (Bin 1+rs+lrrs k x lrr r) | ||
_ -> Bin 1+rs k x Tip r | ||
_ -> case l of | ||
Tip -> Bin 1 k x Tip Tip | ||
Bin _ _ _ Tip Tip -> Bin 2 k x l Tip | ||
Bin _ lk lx Tip (Bin _ lrk lrx _ _) -> Bin 3 lrk lrx (Bin 1 lk lx Tip Tip) (Bin 1 k x Tip Tip) | ||
Bin _ lk lx ll Tip -> Bin 3 lk lx ll (Bin 1 k x Tip Tip) | ||
Bin ls lk lx ll lr -> case lr of | ||
Bin lrs lrk lrx lrl lrr -> | ||
lls = here.size ll | ||
if lrs < Ratio*lls then Bin 1+ls lk lx ll (Bin 1+lrs k x lr Tip) else | ||
lrls = here.size lrl | ||
lrrs = here.size lrr | ||
Bin 1+ls lrk lrx (Bin 1+lls+lrls lk lx ll lrl) (Bin 1+lrrs k x lrr Tip) | ||
|
||
## PRIVATE | ||
|
||
Rebalances the map after the right subtree grows. | ||
balance_right k x l r = case l of | ||
Bin ls _ _ _ _ -> case r of | ||
Bin rs rk rx rl rr -> | ||
if rs <= Delta*ls then Bin 1+ls+rs k x l r else | ||
case rl of | ||
Bin rls rlk rlx rll rlr -> | ||
rrs = here.size rr | ||
if rls < Ratio*rrs then Bin 1+ls+rs rk rx (Bin 1+ls+rls k x l rl) rr else | ||
rlls = here.size rll | ||
rlrs = here.size rlr | ||
Bin 1+ls+rs rlk rlx (Bin 1+ls+rlls k x l rll) (Bin 1+rrs+rlrs rk rx rlr rr) | ||
_ -> Bin 1+ls k x l Tip | ||
_ -> case r of | ||
Tip -> Bin 1 k x Tip Tip | ||
Bin _ _ _ Tip Tip -> Bin 2 k x Tip r | ||
Bin _ rk rx Tip rr -> Bin 3 rk rx (Bin 1 k x Tip Tip) rr | ||
Bin _ rk rx (Bin _ rlk rlx _ _) Tip -> Bin 3 rlk rlx (Bin 1 k x Tip Tip) (Bin 1 rk rx Tip Tip) | ||
Bin rs rk rx (Bin rls rlk rlx rll rlr) rr -> case rr of | ||
Bin rrs _ _ _ _ -> | ||
if rls < Ratio*rrs then Bin 1+rs rk rx (Bin 1+rls k x Tip rl) rr else | ||
srll = here.size rll | ||
srlr = here.size rlr | ||
Bin 1+rs rlk rlx (Bin 1+srll k x Tip rll) (Bin 1+rrs+srlr rk rx rlr rr) | ||
|
||
## PRIVATE | ||
|
||
Controls the difference between inner and outer siblings of a heavy subtree. | ||
Used to decide between a double and a single rotation. | ||
|
||
The choice of values for `ratio` and `delta` is taken from the Haskell | ||
implementation. | ||
ratio : Integer | ||
ratio = 2 | ||
|
||
## PRIVATE | ||
|
||
Controls the maximum size difference between subtrees. | ||
|
||
The choice of values for `ratio` and `delta` is taken from the Haskell | ||
implementation. | ||
delta : Integer | ||
delta = 3 | ||
|
||
## PRIVATE | ||
|
||
Gets the size of a map. | ||
size m = case m of | ||
Bin s _ _ _ _ -> s | ||
_ -> 0 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,6 +69,14 @@ Text.split_at separator = | |
Text.== : Text -> Boolean | ||
Text.== that = Text_Utils.equals [this, that] | ||
|
||
## Checks if `this` is lexicographically before `that`. | ||
Text.< : Text -> Boolean | ||
Text.< that = Text_Utils.lt [this, that] | ||
|
||
## Checks if `this` is lexicographically after `that`. | ||
Text.> : Text -> Boolean | ||
Text.> that = Text_Utils.lt [that, this] | ||
Comment on lines
+72
to
+78
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure lexicographic order is particularly intuitive to a non-programmer. It produces counterintuitive orderings such as |
||
|
||
## Returns a vector containing bytes representing the UTF-8 encoding of the | ||
input text. | ||
|
||
|
@@ -103,4 +111,5 @@ Text.from_codepoints : Vector -> Text | |
Text.from_codepoints codepoints = Text_Utils.from_codepoints [codepoints.to_array] | ||
|
||
## Checks whether `this` starts with `prefix`. | ||
Text.starts_with : Text -> Boolean | ||
Text.starts_with prefix = Text_Utils.starts_with [this, prefix] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a fan of where this file is. I think we should unify the collections under
Base.Collection
(includingList
andVector
). Can we talk about stdlib structure?