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

[DMS-68] Inline internal functions into MapOps object #21

Open
wants to merge 4 commits into
base: wip/s-and-witch/filer-via-fold
Choose a base branch
from
Open
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
217 changes: 160 additions & 57 deletions src/PersistentOrderedMap.mo
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,13 @@ module {
/// assuming that the `compare` function implements an `O(1)` comparison.
///
/// Note: Creates `O(n * log(n))` temporary objects that will be collected as garbage.
public func fromIter<V>(i : I.Iter<(K,V)>) : Map<K, V>
= Internal.fromIter(i, compare);
public func fromIter<V>(i : I.Iter<(K,V)>) : Map<K, V> {
var map = #leaf : Map<K,V>;
for(val in i) {
map := put(map, val.0, val.1);
};
map
};

/// Insert the value `value` with key `key` into map `rbMap`. Overwrites any existing entry with key `key`.
/// Returns a modified map.
Expand Down Expand Up @@ -112,7 +117,7 @@ module {
///
/// Note: Creates `O(log(n))` temporary objects that will be collected as garbage.
public func put<V>(rbMap : Map<K, V>, key : K, value : V) : Map<K, V>
= Internal.put(rbMap, compare, key, value);
= replace(rbMap, key, value).0;

/// Insert the value `value` with key `key` into `rbMap`. Returns modified map and
/// the previous value associated with key `key` or `null` if no such value exists.
Expand Down Expand Up @@ -147,8 +152,16 @@ module {
/// assuming that the `compare` function implements an `O(1)` comparison.
///
/// Note: Creates `O(log(n))` temporary objects that will be collected as garbage.
public func replace<V>(rbMap : Map<K, V>, key : K, value : V) : (Map<K,V>, ?V)
= Internal.replace(rbMap, compare, key, value);
public func replace<V>(rbMap : Map<K, V>, key : K, value : V) : (Map<K,V>, ?V) {
var oldVal : ?V = null;
func onClash( clash : { old : V; new : V } ) : V
{
oldVal := ?clash.old;
clash.new
};
let res = Internal.insertWith(rbMap, compare, key, value, onClash);
(res, oldVal)
};

/// Creates a new map by applying `f` to each entry in `rbMap`. For each entry
/// `(k, v)` in the old map, if `f` evaluates to `null`, the entry is discarded.
Expand Down Expand Up @@ -182,8 +195,17 @@ module {
/// assuming that the `compare` function implements an `O(1)` comparison.
///
/// Note: Creates `O(log(n))` temporary objects that will be collected as garbage.
public func mapFilter<V1, V2>(rbMap : Map<K, V1>, f : (K, V1) -> ?V2) : Map<K, V2>
= Internal.mapFilter(rbMap, compare, f);
public func mapFilter<V1, V2>(rbMap : Map<K, V1>, f : (K, V1) -> ?V2) : Map<K, V2> {
func combine(key : K, value1 : V1, acc : Map<K, V2>) : Map<K, V2> {
switch (f(key, value1)){
case null { acc };
case (?value2) {
put(acc, key, value2)
}
}
};
foldLeft(rbMap, #leaf, combine)
};

/// Get the value associated with key `key` in the given `rbMap` if present and `null` otherwise.
///
Expand All @@ -208,8 +230,18 @@ module {
/// assuming that the `compare` function implements an `O(1)` comparison.
///
/// Note: Creates `O(log(n))` temporary objects that will be collected as garbage.
public func get<V>(rbMap : Map<K, V>, key : K) : ?V
= Internal.get(rbMap, compare, key);
public func get<V>(rbMap : Map<K, V>, key : K) : ?V {
switch rbMap {
case (#leaf) { null };
case (#node(_c, l, xy, r)) {
switch (compare(key, xy.0)) {
case (#less) { get(l, key) };
case (#equal) { ?xy.1 };
case (#greater) { get(r, key) }
}
}
}
};

/// Deletes the entry with the key `key` from the `rbMap`. Has no effect if `key` is not
/// present in the map. Returns modified map.
Expand All @@ -236,7 +268,7 @@ module {
///
/// Note: Creates `O(log(n))` temporary objects that will be collected as garbage.
public func delete<V>(rbMap : Map<K, V>, key : K) : Map<K, V>
= Internal.delete(rbMap, compare, key);
= remove(rbMap, key).0;

/// Deletes the entry with the key `key`. Returns modified map and the
/// previous value associated with key `key` or `null` if no such value exists.
Expand Down Expand Up @@ -271,8 +303,55 @@ module {
/// assuming that the `compare` function implements an `O(1)` comparison.
///
/// Note: Creates `O(log(n))` temporary objects that will be collected as garbage.
public func remove<V>(rbMap : Map<K, V>, key : K) : (Map<K,V>, ?V)
= Internal.remove(rbMap, compare, key);
public func remove<V>(rbMap : Map<K, V>, key : K) : (Map<K,V>, ?V){
var y0 : ?V = null;
func delNode(left : Map<K,V>, xy : (K, V), right : Map<K,V>) : Map<K,V> {
switch (compare (key, xy.0)) {
case (#less) {
let newLeft = del left;
switch left {
case (#node(#B, _, _, _)) {
Internal.balLeft(newLeft, xy, right)
};
case _ {
#node(#R, newLeft, xy, right)
}
}
};
case (#greater) {
let newRight = del right;
switch right {
case (#node(#B, _, _, _)) {
Internal.balRight(left, xy, newRight)
};
case _ {
#node(#R, left, xy, newRight)
}
}
};
case (#equal) {
y0 := ?xy.1;
Internal.append(left, right)
};
}
};
func del(tree : Map<K,V>) : Map<K,V> {
switch tree {
case (#leaf) {
tree
};
case (#node(_, left, xy, right)) {
delNode(left, xy, right)
}
};
};
switch (del(rbMap)) {
case (#node(#R, left, xy, right)) {
(#node(#B, left, xy, right), y0);
};
case other { (other, y0) };
};
};

};

Expand Down Expand Up @@ -324,27 +403,49 @@ module {
///
/// Note: Full map iteration creates `O(n)` temporary objects that will be collected as garbage.
public func iter<K, V>(rbMap : Map<K, V>, direction : Direction) : I.Iter<(K, V)> {
object {
var trees : IterRep<K, V> = ?(#tr(rbMap), null);
public func next() : ?(K, V) {
switch (direction, trees) {
case (_, null) { null };
case (_, ?(#tr(#leaf), ts)) {
trees := ts;
next()
};
case (_, ?(#xy(xy), ts)) {
trees := ts;
?xy
}; // TODO: Let's float-out case on direction
case (#fwd, ?(#tr(#node(_, l, xy, r)), ts)) {
trees := ?(#tr(l), ?(#xy(xy), ?(#tr(r), ts)));
next()
};
case (#bwd, ?(#tr(#node(_, l, xy, r)), ts)) {
trees := ?(#tr(r), ?(#xy(xy), ?(#tr(l), ts)));
next()
}
switch direction {
case (#fwd) { iterForward(rbMap) };
case (#bwd) { iterBackward(rbMap) }
}
};

func iterForward<K, V>(rbMap : Map<K, V>) : I.Iter<(K, V)> = object {
var trees : IterRep<K, V> = ?(#tr(rbMap), null);
public func next() : ?(K, V) {
switch (trees) {
case (null) { null };
case (?(#tr(#leaf), ts)) {
trees := ts;
next()
};
case (?(#xy(xy), ts)) {
trees := ts;
?xy
};
case (?(#tr(#node(_, l, xy, r)), ts)) {
trees := ?(#tr(l), ?(#xy(xy), ?(#tr(r), ts)));
next()
}
}
}
};

func iterBackward<K, V>(rbMap : Map<K, V>) : I.Iter<(K, V)> = object {
var trees : IterRep<K, V> = ?(#tr(rbMap), null);
public func next() : ?(K, V) {
switch (trees) {
case (null) { null };
case (?(#tr(#leaf), ts)) {
trees := ts;
next()
};
case (?(#xy(xy), ts)) {
trees := ts;
?xy
};
case (?(#tr(#node(_, l, xy, r)), ts)) {
trees := ?(#tr(r), ?(#xy(xy), ?(#tr(l), ts)));
next()
}
}
}
Expand Down Expand Up @@ -527,11 +628,14 @@ module {
combine : (Key, Value, Accum) -> Accum
) : Accum
{
var acc = base;
for(val in iter(rbMap, #fwd)){
acc := combine(val.0, val.1, acc);
};
acc
switch (rbMap) {
case (#leaf) { base };
case (#node(_, l, (k, v), r)) {
let left = foldLeft(l, base, combine);
let middle = combine(k, v, left);
foldLeft(r, middle, combine)
}
}
};

/// Collapses the elements in `rbMap` into a single value by starting with `base`
Expand Down Expand Up @@ -567,11 +671,14 @@ module {
combine : (Key, Value, Accum) -> Accum
) : Accum
{
var acc = base;
for(val in iter(rbMap, #bwd)){
acc := combine(val.0, val.1, acc);
};
acc
switch (rbMap) {
case (#leaf) { base };
case (#node(_, l, (k, v), r)) {
let right = foldRight(r, base, combine);
let middle = combine(k, v, right);
foldRight(l, middle, combine)
}
}
};


Expand All @@ -587,19 +694,15 @@ module {
};

public func mapFilter<K, V1, V2>(t : Map<K, V1>, compare : (K, K) -> O.Order, f : (K, V1) -> ?V2) : Map<K, V2>{
var map = #leaf : Map<K, V2>;
for(kv in iter(t, #fwd))
{
switch(f kv){
case null {};
case (?v1) {
// The keys still are monotonic, so we can
// merge trees using `append` and avoid compare here
map := put(map, compare, kv.0, v1);
func combine(key : K, value1 : V1, acc : Map<K, V2>) : Map<K, V2> {
switch (f(key, value1)){
case null { acc };
case (?value2) {
put(acc, compare, key, value2)
}
}
};
map
foldLeft(t, #leaf, combine)
};

public func get<K, V>(t : Map<K, V>, compare : (K, K) -> O.Order, x : K) : ?V {
Expand Down Expand Up @@ -672,7 +775,7 @@ module {

type ClashResolver<A> = { old : A; new : A } -> A;

func insertWith<K, V> (
public func insertWith<K, V> (
m : Map<K, V>,
compare : (K, K) -> O.Order,
key : K,
Expand Down Expand Up @@ -748,7 +851,7 @@ module {
) : Map<K, V> = replace(m, compare, key, val).0;


func balLeft<K,V>(left : Map<K, V>, xy : (K,V), right : Map<K, V>) : Map<K,V> {
public func balLeft<K,V>(left : Map<K, V>, xy : (K,V), right : Map<K, V>) : Map<K,V> {
switch (left, right) {
case (#node(#R, l1, xy1, r1), r) {
#node(
Expand All @@ -770,7 +873,7 @@ module {
}
};

func balRight<K,V>(left : Map<K, V>, xy : (K,V), right : Map<K, V>) : Map<K,V> {
public func balRight<K,V>(left : Map<K, V>, xy : (K,V), right : Map<K, V>) : Map<K,V> {
switch (left, right) {
case (l, #node(#R, l1, xy1, r1)) {
#node(#R,
Expand All @@ -791,7 +894,7 @@ module {
}
};

func append<K,V>(left : Map<K, V>, right: Map<K, V>) : Map<K, V> {
public func append<K,V>(left : Map<K, V>, right: Map<K, V>) : Map<K, V> {
switch (left, right) {
case (#leaf, _) { right };
case (_, #leaf) { left };
Expand Down