diff --git a/src/Blob.mo b/src/Blob.mo index e9318e72c..a78baeca0 100644 --- a/src/Blob.mo +++ b/src/Blob.mo @@ -133,7 +133,7 @@ module { /// let result = Blob.compare(blob1, blob2); /// assert result == #less; /// ``` - public func compare(b1 : Blob, b2 : Blob) : Order.Order { + public persistent func compare(b1 : Blob, b2 : Blob) : Order.Order { let c = Prim.blobCompare(b1, b2); if (c < 0) #less else if (c == 0) #equal else #greater }; diff --git a/src/Bool.mo b/src/Bool.mo index 45b0cee78..d8e8cf2f0 100644 --- a/src/Bool.mo +++ b/src/Bool.mo @@ -88,7 +88,7 @@ module { /// assert Bool.compare(true, true) == #equal; /// assert Bool.compare(false, true) == #less; /// ``` - public func compare(a : Bool, b : Bool) : Order.Order { + public persistent func compare(a : Bool, b : Bool) : Order.Order { if (a == b) #equal else if a #greater else #less }; diff --git a/src/Char.mo b/src/Char.mo index c81ed9f91..15bc20e5e 100644 --- a/src/Char.mo +++ b/src/Char.mo @@ -207,7 +207,7 @@ module { /// assert Char.compare('B', 'A') == #greater; /// assert Char.compare('A', 'A') == #equal; /// ``` - public func compare(a : Char, b : Char) : { #less; #equal; #greater } { + public persistent func compare(a : Char, b : Char) : { #less; #equal; #greater } { if (a < b) { #less } else if (a == b) { #equal } else { #greater } }; diff --git a/src/Float.mo b/src/Float.mo index 7d79489d5..7af5d44f7 100644 --- a/src/Float.mo +++ b/src/Float.mo @@ -73,7 +73,7 @@ module { /// ```motoko include=import /// assert Float.isNaN(0.0/0.0); /// ``` - public func isNaN(number : Float) : Bool { + public persistent func isNaN(number : Float) : Bool { number != number }; @@ -194,7 +194,9 @@ module { /// let epsilon = 1e-6; /// assert Float.equal(Float.copySign(1.2, -2.3), -1.2, epsilon); /// ``` - public let copySign : (x : Float, y : Float) -> Float = Prim.floatCopySign; + public persistent func copySign(x : Float, y : Float): Float { + Prim.floatCopySign(x, y) + }; /// Returns the smaller value of `x` and `y`. /// @@ -608,7 +610,7 @@ module { /// ```motoko include=import /// assert Float.compare(0.123, 0.1234) == #less; /// ``` - public func compare(x : Float, y : Float) : Order.Order { + public persistent func compare(x : Float, y : Float) : Order.Order { if (isNaN(x)) { if (isNegative(x)) { if (isNaN(y) and isNegative(y)) { #equal } else { #less } @@ -626,7 +628,7 @@ module { } }; - func isNegative(number : Float) : Bool { + persistent func isNegative(number : Float) : Bool { copySign(1.0, number) < 0.0 }; diff --git a/src/Int.mo b/src/Int.mo index e0aabb60c..c9d2f9252 100644 --- a/src/Int.mo +++ b/src/Int.mo @@ -259,7 +259,7 @@ module { /// import Array "mo:core/Array"; /// assert Array.sort([1, -2, -3], Int.compare) == [-3, -2, 1]; /// ``` - public func compare(x : Int, y : Int) : Order.Order { + public persistent func compare(x : Int, y : Int) : Order.Order { if (x < y) { #less } else if (x == y) { #equal } else { #greater } }; diff --git a/src/Int16.mo b/src/Int16.mo index b423a56c5..d5453e26e 100644 --- a/src/Int16.mo +++ b/src/Int16.mo @@ -256,7 +256,7 @@ module { /// import Array "mo:core/Array"; /// assert Array.sort([1, -2, -3] : [Int16], Int16.compare) == [-3, -2, 1]; /// ``` - public func compare(x : Int16, y : Int16) : Order.Order { + public persistent func compare(x : Int16, y : Int16) : Order.Order { if (x < y) { #less } else if (x == y) { #equal } else { #greater } }; diff --git a/src/Int32.mo b/src/Int32.mo index c9a4a122d..e6bfafc4e 100644 --- a/src/Int32.mo +++ b/src/Int32.mo @@ -265,7 +265,7 @@ module { /// import Array "mo:core/Array"; /// assert Array.sort([1, -2, -3] : [Int32], Int32.compare) == [-3, -2, 1]; /// ``` - public func compare(x : Int32, y : Int32) : Order.Order { + public persistent func compare(x : Int32, y : Int32) : Order.Order { if (x < y) { #less } else if (x == y) { #equal } else { #greater } }; diff --git a/src/Int64.mo b/src/Int64.mo index 9744fba9f..813344ea5 100644 --- a/src/Int64.mo +++ b/src/Int64.mo @@ -251,7 +251,7 @@ module { /// import Array "mo:core/Array"; /// assert Array.sort([1, -2, -3] : [Int64], Int64.compare) == [-3, -2, 1]; /// ``` - public func compare(x : Int64, y : Int64) : Order.Order { + public persistent func compare(x : Int64, y : Int64) : Order.Order { if (x < y) { #less } else if (x == y) { #equal } else { #greater } }; diff --git a/src/Int8.mo b/src/Int8.mo index 70519972f..81e805dd9 100644 --- a/src/Int8.mo +++ b/src/Int8.mo @@ -246,7 +246,7 @@ module { /// import Array "mo:core/Array"; /// assert Array.sort([1, -2, -3] : [Int8], Int8.compare) == [-3, -2, 1]; /// ``` - public func compare(x : Int8, y : Int8) : Order.Order { + public persistent func compare(x : Int8, y : Int8) : Order.Order { if (x < y) { #less } else if (x == y) { #equal } else { #greater } }; diff --git a/src/Nat.mo b/src/Nat.mo index 560aba056..9ea084037 100644 --- a/src/Nat.mo +++ b/src/Nat.mo @@ -210,7 +210,7 @@ module { /// import Array "mo:core/Array"; /// assert Array.sort([2, 3, 1], Nat.compare) == [1, 2, 3]; /// ``` - public func compare(x : Nat, y : Nat) : Order.Order { + public persistent func compare(x : Nat, y : Nat) : Order.Order { if (x < y) { #less } else if (x == y) { #equal } else { #greater } }; diff --git a/src/Nat16.mo b/src/Nat16.mo index ecd8b600f..fe177ed1d 100644 --- a/src/Nat16.mo +++ b/src/Nat16.mo @@ -239,7 +239,7 @@ module { /// import Array "mo:core/Array"; /// assert Array.sort([2, 3, 1] : [Nat16], Nat16.compare) == [1, 2, 3]; /// ``` - public func compare(x : Nat16, y : Nat16) : Order.Order { + public persistent func compare(x : Nat16, y : Nat16) : Order.Order { if (x < y) { #less } else if (x == y) { #equal } else { #greater } }; diff --git a/src/Nat32.mo b/src/Nat32.mo index 05bac731b..a9997e839 100644 --- a/src/Nat32.mo +++ b/src/Nat32.mo @@ -239,7 +239,7 @@ module { /// import Array "mo:core/Array"; /// assert Array.sort([2, 3, 1] : [Nat32], Nat32.compare) == [1, 2, 3]; /// ``` - public func compare(x : Nat32, y : Nat32) : Order.Order { + public persistent func compare(x : Nat32, y : Nat32) : Order.Order { if (x < y) { #less } else if (x == y) { #equal } else { #greater } }; diff --git a/src/Nat64.mo b/src/Nat64.mo index 3539b2743..42e596747 100644 --- a/src/Nat64.mo +++ b/src/Nat64.mo @@ -217,7 +217,7 @@ module { /// import Array "mo:core/Array"; /// assert Array.sort([2, 3, 1] : [Nat64], Nat64.compare) == [1, 2, 3]; /// ``` - public func compare(x : Nat64, y : Nat64) : Order.Order { + public persistent func compare(x : Nat64, y : Nat64) : Order.Order { if (x < y) { #less } else if (x == y) { #equal } else { #greater } }; diff --git a/src/Nat8.mo b/src/Nat8.mo index bb0dc4f83..e9a2a49d4 100644 --- a/src/Nat8.mo +++ b/src/Nat8.mo @@ -212,7 +212,7 @@ module { /// import Array "mo:core/Array"; /// assert Array.sort([2, 3, 1] : [Nat8], Nat8.compare) == [1, 2, 3]; /// ``` - public func compare(x : Nat8, y : Nat8) : Order.Order { + public persistent func compare(x : Nat8, y : Nat8) : Order.Order { if (x < y) { #less } else if (x == y) { #equal } else { #greater } }; diff --git a/src/Option.mo b/src/Option.mo index def91a027..9f7f8a92a 100644 --- a/src/Option.mo +++ b/src/Option.mo @@ -130,7 +130,7 @@ module { /// - `#less` if the first value is `null` and the second is not, /// - `#greater` if the first value is not `null` and the second is, /// - the result of the comparison function when both values are not `null`. - public func compare(x : ?A, y : ?A, cmp : (A, A) -> Types.Order) : Types.Order = switch (x, y) { + public persistent func compare(x : ?A, y : ?A, cmp : (A, A) -> Types.Order) : Types.Order = switch (x, y) { case (null, null) #equal; case (null, _) #less; case (_, null) #greater; diff --git a/src/Principal.mo b/src/Principal.mo index 5bf76b99c..b07204c9f 100644 --- a/src/Principal.mo +++ b/src/Principal.mo @@ -213,7 +213,7 @@ module { /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); /// assert Principal.compare(principal1, principal2) == #equal; /// ``` - public func compare(principal1 : Principal, principal2 : Principal) : { + public persistent func compare(principal1 : Principal, principal2 : Principal) : { #less; #equal; #greater diff --git a/src/Queue.mo b/src/Queue.mo index 8e61fff06..393376887 100644 --- a/src/Queue.mo +++ b/src/Queue.mo @@ -526,6 +526,40 @@ module { } }; + /// Returns an iterator over the elements in the queue, in reverse order. + /// Iterates from back to front. + /// + /// Example: + /// ```motoko + /// import Queue "mo:core/Queue"; + /// persistent actor { + /// let queue = Queue.fromIter(["A", "B", "C"].values()); + /// transient let iter = Queue.reverseValues(queue); + /// assert iter.next() == ?"C"; + /// assert iter.next() == ?"B"; + /// assert iter.next() == ?"A"; + /// assert iter.next() == null; + /// } + /// ``` + /// + /// Runtime: O(1) for iterator creation, O(n) for full iteration + /// Space: O(1) + public func reverseValues(queue : Queue) : Iter.Iter { + object { + var current = queue.back; + + public func next() : ?T { + switch (current) { + case null null; + case (?node) { + current := node.previous; + ?node.value + } + } + } + } + }; + /// Tests whether all elements in the queue satisfy the given predicate. /// /// Example: diff --git a/src/Text.mo b/src/Text.mo index 864b7284e..429b3dfc8 100644 --- a/src/Text.mo +++ b/src/Text.mo @@ -300,7 +300,7 @@ module { /// assert Text.compare("abc", "def") == #less; /// assert Text.compare("abc", "ABC") == #greater; /// ``` - public func compare(t1 : Text, t2 : Text) : Order.Order { + public persistent func compare(t1 : Text, t2 : Text) : Order.Order { let c = Prim.textCompare(t1, t2); if (c < 0) #less else if (c == 0) #equal else #greater }; diff --git a/src/object-oriented/List.mo b/src/object-oriented/List.mo new file mode 100644 index 000000000..068d13f19 --- /dev/null +++ b/src/object-oriented/List.mo @@ -0,0 +1,205 @@ +import ImperativeList "../List"; +import PureList "../pure/List"; +import Iter "../Iter"; +import Order "../Order"; + +module { + public persistent class List() { + let inner = ImperativeList.empty(); + + public func toPure() : PureList.List { + PureList.fromIter(ImperativeList.values(inner)) + }; + + public func toImperative() : ImperativeList.List { + ImperativeList.clone(inner) + }; + + public func toArray() : [T] { + ImperativeList.toArray(inner) + }; + + public func isEmpty() : Bool { + ImperativeList.isEmpty(inner) + }; + + public func size() : Nat { + ImperativeList.size(inner) + }; + + public func add(element : T) { + ImperativeList.add(inner, element) + }; + + public func get(index : Nat) : T { + ImperativeList.at(inner, index) + }; + + public func set(index : Nat, value : T) { + ImperativeList.put(inner, index, value) + }; + + public func removeLast() : ?T { + ImperativeList.removeLast(inner) + }; + + public func sort(compare : (T, T) -> Order.Order) { + ImperativeList.sort(inner, compare) + }; + + public func addAll(iter : Iter.Iter) { + ImperativeList.addAll(inner, iter) + }; + + public func addRepeat(initValue : T, count : Nat) { + ImperativeList.addRepeat(inner, initValue, count) + }; + + public func contains(equal : (T, T) -> Bool, element : T) : Bool { + ImperativeList.contains(inner, equal, element) + }; + + public func indexOf(equal : (T, T) -> Bool, element : T) : ?Nat { + ImperativeList.indexOf(inner, equal, element) + }; + + public func lastIndexOf(equal : (T, T) -> Bool, element : T) : ?Nat { + ImperativeList.lastIndexOf(inner, equal, element) + }; + + public func findIndex(predicate : T -> Bool) : ?Nat { + ImperativeList.findIndex(inner, predicate) + }; + + public func findLastIndex(predicate : T -> Bool) : ?Nat { + ImperativeList.findLastIndex(inner, predicate) + }; + + public func binarySearch(compare : (T, T) -> Order.Order, element : T) : { + #found : Nat; + #insertionIndex : Nat + } { + ImperativeList.binarySearch(inner, compare, element) + }; + + public func clone() : List { + fromImperative(inner) + }; + + public func clear() { + ImperativeList.clear(inner) + }; + + public func equal(other : List, equal : (T, T) -> Bool) : Bool { + ImperativeList.equal(inner, other.internal(), equal) + }; + + public func compare(other : List, compare : (T, T) -> Order.Order) : Order.Order { + ImperativeList.compare(inner, other.internal(), compare) + }; + + public func values() : Iter.Iter { + ImperativeList.values(inner) + }; + + public func enumerate() : Iter.Iter<(Nat, T)> { + ImperativeList.enumerate(inner) + }; + + public func reverseValues() : Iter.Iter { + ImperativeList.reverseValues(inner) + }; + + public func reverseEnumerate() : Iter.Iter<(Nat, T)> { + ImperativeList.reverseEnumerate(inner) + }; + + public func reverse() : List { + fromImperative(ImperativeList.reverse(inner)) + }; + + public func first() : ?T { + ImperativeList.first(inner) + }; + + public func last() : ?T { + ImperativeList.last(inner) + }; + + public func max(compare : (T, T) -> Order.Order) : ?T { + ImperativeList.max(inner, compare) + }; + + public func min(compare : (T, T) -> Order.Order) : ?T { + ImperativeList.min(inner, compare) + }; + + public func forEach(operation : T -> ()) { + for (entry in values()) { + operation(entry) + } + }; + + public func filter(criterion : T -> Bool) : List { + fromImperative(ImperativeList.filter(inner, criterion)) + }; + + // type error [M0200], cannot decide type constructor equality + // TODO: Enable when this issue has been fixed: https://github.com/dfinity/motoko/issues/5446 + // public func map(project : T -> R) : List { + // fromImperative(ImperativeList.map(inner, project)) + // }; + + public func all(predicate : T -> Bool) : Bool { + ImperativeList.all(inner, predicate) + }; + + public func any(predicate : T -> Bool) : Bool { + ImperativeList.any(inner, predicate) + }; + + public func toText(elementFormat : T -> Text) : Text { + ImperativeList.toText(inner, elementFormat) + }; + + public func internal() : ImperativeList.List { + inner + } + }; + + public persistent func fromImperative(list : ImperativeList.List) : List { + fromIter(ImperativeList.values(list)) + }; + + public func fromPure(pure : PureList.List) : List { + fromIter(PureList.values(PureList.reverse(pure))) + }; + + public func fromArray(array : [T]) : List { + fromIter(array.values()) + }; + + public persistent func fromIter(iter : Iter.Iter) : List { + let result = List(); + for (element in iter) { + result.add(element) + }; + result + }; + + public func empty() : List { + List() + }; + + public func singleton(element : T) : List { + let result = List(); + result.add(element); + result + }; + + public func repeat(initValue : T, size : Nat) : List { + let result = List(); + result.addRepeat(initValue, size); + result + } +} diff --git a/src/object-oriented/Map.mo b/src/object-oriented/Map.mo new file mode 100644 index 000000000..d02a7a9c5 --- /dev/null +++ b/src/object-oriented/Map.mo @@ -0,0 +1,152 @@ +import Order "../Order"; +import Iter "../Iter"; +import ImperativeMap "../Map"; +import PureMap "../pure/Map"; +import Runtime "../Runtime"; + +module { + public type PersistentCompare = persistent(K, K) -> Order.Order; + type TransientCompare = (K, K) -> Order.Order; + + public persistent class Map(comparison : PersistentCompare) { + let inner = ImperativeMap.empty(); + + public func toPure() : PureMap.Map { + PureMap.fromIter(ImperativeMap.entries(inner), comparison : TransientCompare) + }; + + public func toImperative() : ImperativeMap.Map { + ImperativeMap.clone(inner) + }; + + public func toArray() : [(K, V)] { + Iter.toArray(entries()) + }; + + public func isEmpty() : Bool { + ImperativeMap.isEmpty(inner) + }; + + public func size() : Nat { + ImperativeMap.size(inner) + }; + + public func add(key : K, value : V) { + ImperativeMap.add(inner, comparison : TransientCompare, key, value) + }; + + public func containsKey(key : K) : Bool { + ImperativeMap.containsKey(inner, comparison : TransientCompare, key) + }; + + public func get(key : K) : ?V { + ImperativeMap.get(inner, comparison : TransientCompare, key) + }; + + public func remove(key : K) { + ImperativeMap.remove(inner, comparison : TransientCompare, key) + }; + + public func clone() : Map { + fromImperative(inner, comparison) + }; + + public func clear() { + ImperativeMap.clear(inner) + }; + + public func equal(other : Map, equalValue : (V, V) -> Bool) : Bool { + ImperativeMap.equal(inner, other.internal(), comparison : TransientCompare, equalValue) + }; + + public func compare(other : Map, compareValue : (V, V) -> Order.Order) : Order.Order { + ImperativeMap.compare(inner, other.internal(), comparison : TransientCompare, compareValue) + }; + + public func maxEntry() : ?(K, V) { + ImperativeMap.maxEntry(inner) + }; + + public func minEntry() : ?(K, V) { + ImperativeMap.minEntry(inner) + }; + + public func entries() : Iter.Iter<(K, V)> { + ImperativeMap.entries(inner) + }; + + public func reverseEntries() : Iter.Iter<(K, V)> { + ImperativeMap.reverseEntries(inner) + }; + + public func keys() : Iter.Iter { + ImperativeMap.keys(inner) + }; + + public func values() : Iter.Iter { + ImperativeMap.values(inner) + }; + + public func forEach(operation : (K, V) -> ()) { + for (entry in entries()) { + operation(entry) + } + }; + + public func filter(criterion : (K, V) -> Bool) : Map { + fromImperative(ImperativeMap.filter(inner, comparison : TransientCompare, criterion), comparison) + }; + + // type error [M0200], cannot decide type constructor equality + // TODO: Enable when this issue has been fixed: https://github.com/dfinity/motoko/issues/5446 + // public func map(project : (K, V) -> R) : Map { + // fromImperative(ImperativeMap.map(inner, project), compare) + // }; + + public func all(predicate : (K, V) -> Bool) : Bool { + ImperativeMap.all(inner, predicate) + }; + + public func any(predicate : (K, V) -> Bool) : Bool { + ImperativeMap.any(inner, predicate) + }; + + public func toText(keyFormat : K -> Text, valueFormat : V -> Text) : Text { + ImperativeMap.toText(inner, keyFormat, valueFormat) + }; + + public func internal() : ImperativeMap.Map { + inner + } + }; + + public persistent func fromImperative(map : ImperativeMap.Map, compare : PersistentCompare) : Map { + fromIter(ImperativeMap.entries(map), compare) + }; + + public func fromPure(pure : PureMap.Map, compare: PersistentCompare) : Map { + fromIter(PureMap.entries(pure), compare) + }; + + public func fromArray(array: [(K, V)], compare: PersistentCompare): Map { + fromIter(array.values(), compare) + }; + + public persistent func fromIter(iter : Iter.Iter<(K, V)>, compare : PersistentCompare) : Map { + let result = Map(compare); + for ((key, value) in iter) { + result.add(key, value) + }; + result + }; + + public func empty(compare : PersistentCompare) : Map { + Map(compare) + }; + + public func singleton(compare : PersistentCompare, key : K, value : V) : Map { + let result = Map(compare); + result.add(key, value); + result + } +} diff --git a/src/object-oriented/Queue.mo b/src/object-oriented/Queue.mo new file mode 100644 index 000000000..dd63e157f --- /dev/null +++ b/src/object-oriented/Queue.mo @@ -0,0 +1,116 @@ +import ImperativeQueue "../Queue"; +import PureQueue "../pure/Queue"; +import Iter "../Iter"; +import Order "../Order"; + +module { + public persistent class Queue() { + let inner = ImperativeQueue.empty(); + + public func toPure() : PureQueue.Queue { + PureQueue.fromIter(ImperativeQueue.values(inner)) + }; + + public func toImperative() : ImperativeQueue.Queue { + ImperativeQueue.clone(inner) + }; + + public func toArray() : [T] { + ImperativeQueue.toArray(inner) + }; + + public func isEmpty() : Bool { + ImperativeQueue.isEmpty(inner) + }; + + public func size() : Nat { + ImperativeQueue.size(inner) + }; + + public func pushFront(element : T) { + ImperativeQueue.pushFront(inner, element) + }; + + public func pushBack(element : T) { + ImperativeQueue.pushBack(inner, element) + }; + + public func popFront() : ?T { + ImperativeQueue.popFront(inner) + }; + + public func popBack() : ?T { + ImperativeQueue.popBack(inner) + }; + + public func peekFront() : ?T { + ImperativeQueue.peekFront(inner) + }; + + public func peekBack() : ?T { + ImperativeQueue.peekBack(inner) + }; + + public func contains(equal : (T, T) -> Bool, element : T) : Bool { + ImperativeQueue.contains(inner, equal, element) + }; + + public func clone() : Queue { + fromImperative(inner) + }; + + public func clear() { + ImperativeQueue.clear(inner) + }; + + public func values() : Iter.Iter { + ImperativeQueue.values(inner) + }; + + public func reverseValues() : Iter.Iter { + ImperativeQueue.reverseValues(inner) + }; + + public func equal(other : Queue, equal : (T, T) -> Bool) : Bool { + ImperativeQueue.equal(inner, other.internal(), equal) + }; + + public func compare(other : Queue, compare : (T, T) -> Order.Order) : Order.Order { + ImperativeQueue.compare(inner, other.internal(), compare) + }; + + public func internal() : ImperativeQueue.Queue { + inner + } + }; + + public persistent func fromImperative(queue : ImperativeQueue.Queue) : Queue { + fromIter(ImperativeQueue.values(queue)) + }; + + public func fromPure(pure : PureQueue.Queue) : Queue { + fromIter(PureQueue.values(pure)) + }; + + public func fromArray(array : [T]) : Queue { + fromIter(array.values()) + }; + + public persistent func fromIter(iter : Iter.Iter) : Queue { + let result = Queue(); + for (element in iter) { + result.pushBack(element) + }; + result + }; + + public func empty() : Queue { + Queue() + }; + + public func singleton(element : T) : Queue { + let result = Queue(); + result.pushBack(element); + result + } +} diff --git a/src/object-oriented/Set.mo b/src/object-oriented/Set.mo new file mode 100644 index 000000000..a04dd927e --- /dev/null +++ b/src/object-oriented/Set.mo @@ -0,0 +1,140 @@ +import Order "../Order"; +import Iter "../Iter"; +import ImperativeSet "../Set"; +import PureSet "../pure/Set"; +import Runtime "../Runtime"; + +module { + public type PersistentCompare = persistent(T, T) -> Order.Order; + type TransientCompare = (T, T) -> Order.Order; + + public persistent class Set(comparison : PersistentCompare) { + let inner = ImperativeSet.empty(); + + public func toPure() : PureSet.Set { + PureSet.fromIter(ImperativeSet.values(inner), comparison : TransientCompare) + }; + + public func toImperative() : ImperativeSet.Set { + ImperativeSet.clone(inner) + }; + + public func toArray() : [T] { + Iter.toArray(values()) + }; + + public func isEmpty() : Bool { + ImperativeSet.isEmpty(inner) + }; + + public func size() : Nat { + ImperativeSet.size(inner) + }; + + public func add(element : T) { + ImperativeSet.add(inner, comparison : TransientCompare, element) + }; + + public func contains(element : T) : Bool { + ImperativeSet.contains(inner, comparison : TransientCompare, element) + }; + + public func remove(element : T) { + ImperativeSet.remove(inner, comparison : TransientCompare, element) + }; + + public func clone() : Set { + fromImperative(inner, comparison) + }; + + public func clear() { + ImperativeSet.clear(inner) + }; + + public func equal(other : Set) : Bool { + ImperativeSet.equal(inner, other.internal(), comparison : TransientCompare) + }; + + public func compare(other : Set) : Order.Order { + ImperativeSet.compare(inner, other.internal(), comparison : TransientCompare) + }; + + public func max() : ?T { + ImperativeSet.max(inner) + }; + + public func min() : ?T { + ImperativeSet.min(inner) + }; + + public func values() : Iter.Iter { + ImperativeSet.values(inner) + }; + + public func reverseValues() : Iter.Iter { + ImperativeSet.reverseValues(inner) + }; + + public func forEach(operation : T -> ()) { + for (entry in values()) { + operation(entry) + } + }; + + public func filter(criterion : T -> Bool) : Set { + fromImperative(ImperativeSet.filter(inner, comparison : TransientCompare, criterion), comparison) + }; + + // type error [M0200], cannot decide type constructor equality + // TODO: Enable when this issue has been fixed: https://github.com/dfinity/motoko/issues/5446 + // public func map(project : T -> R) : Set { + // fromImperative(ImperativeSet.map(inner, project), compare) + // }; + + public func all(predicate : T -> Bool) : Bool { + ImperativeSet.all(inner, predicate) + }; + + public func any(predicate : T -> Bool) : Bool { + ImperativeSet.any(inner, predicate) + }; + + public func toText(elementFormat : T -> Text) : Text { + ImperativeSet.toText(inner, elementFormat) + }; + + public func internal() : ImperativeSet.Set { + inner + } + }; + + public persistent func fromImperative(set : ImperativeSet.Set, compare : PersistentCompare) : Set { + fromIter(ImperativeSet.values(set), compare) + }; + + public func fromPure(pure : PureSet.Set, compare: PersistentCompare) : Set { + fromIter(PureSet.values(pure), compare) + }; + + public func fromArray(array: [T], compare: PersistentCompare): Set { + fromIter(array.values(), compare) + }; + + public persistent func fromIter(iter : Iter.Iter, compare : PersistentCompare) : Set { + let result = Set(compare); + for (element in iter) { + result.add(element) + }; + result + }; + + public func empty(compare : PersistentCompare) : Set { + Set(compare) + }; + + public func singleton(compare : PersistentCompare, element : T) : Set { + let result = Set(compare); + result.add(element); + result + } +} diff --git a/src/object-oriented/Stack.mo b/src/object-oriented/Stack.mo new file mode 100644 index 000000000..f2f23417c --- /dev/null +++ b/src/object-oriented/Stack.mo @@ -0,0 +1,104 @@ +import ImperativeStack "../Stack"; +import PureList "../pure/List"; +import Iter "../Iter"; +import Order "../Order"; + +module { + persistent class Stack() { + let inner = ImperativeStack.empty(); + + public func toPure() : PureList.List { + PureList.fromIter(ImperativeStack.values(inner)) + }; + + public func toImperative() : ImperativeStack.Stack { + ImperativeStack.clone(inner) + }; + + public func toArray() : [T] { + Iter.toArray(values()); + }; + + public func isEmpty() : Bool { + ImperativeStack.isEmpty(inner) + }; + + public func size() : Nat { + ImperativeStack.size(inner) + }; + + public func push(element : T) { + ImperativeStack.push(inner, element) + }; + + public func pop() : ?T { + ImperativeStack.pop(inner) + }; + + public func peek() : ?T { + ImperativeStack.peek(inner) + }; + + public func contains(equal : (T, T) -> Bool, element : T) : Bool { + ImperativeStack.contains(inner, equal, element) + }; + + public func clone() : Stack { + fromImperative(inner) + }; + + public func clear() { + ImperativeStack.clear(inner) + }; + + public func values() : Iter.Iter { + ImperativeStack.values(inner) + }; + + public func reverseValues() : Iter.Iter { + Iter.reverse(values()); + }; + + public func equal(other : Stack, equal : (T, T) -> Bool) : Bool { + ImperativeStack.equal(inner, other.internal(), equal) + }; + + public func compare(other : Stack, compare : (T, T) -> Order.Order) : Order.Order { + ImperativeStack.compare(inner, other.internal(), compare) + }; + + public func internal() : ImperativeStack.Stack { + inner + } + }; + + public persistent func fromImperative(Stack : ImperativeStack.Stack) : Stack { + fromIter(ImperativeStack.values(Stack)) + }; + + public func fromPure(pure : PureList.List) : Stack { + fromIter(PureList.values(pure)) + }; + + public func fromArray(array : [T]) : Stack { + fromIter(array.values()) + }; + + public persistent func fromIter(iter : Iter.Iter) : Stack { + let result = Stack(); + for (element in iter) { + result.push(element) + }; + result + }; + + public func empty() : Stack { + Stack() + }; + + public func singleton(element : T) : Stack { + let result = Stack(); + result.push(element); + result + } +} diff --git a/test/Queue.test.mo b/test/Queue.test.mo index 92b360a16..dd277cf09 100644 --- a/test/Queue.test.mo +++ b/test/Queue.test.mo @@ -87,6 +87,13 @@ suite( } ); + test( + "reverseValues", + func() { + assert Iter.toArray(Queue.reverseValues(Queue.empty())) == [] + } + ); + test( "equal", func() { @@ -606,6 +613,21 @@ suite( assert counter == numberOfSteps; expect.nat(Queue.size(queue)).equal((numberOfSteps + 1) / 2) } + ); + + test( + "reverseValues", + func() { + let queue = Queue.empty(); + for (number in Nat.range(0, numberOfSteps)) { + Queue.pushBack(queue, number) + }; + var index = 0; + for (number in Queue.reverseValues(queue)) { + index += 1; + assert number == numberOfSteps - index; + } + } ) } ); diff --git a/test/ts/importAll.ts b/test/ts/importAll.ts index 185ec4572..0de9eaa94 100644 --- a/test/ts/importAll.ts +++ b/test/ts/importAll.ts @@ -20,7 +20,7 @@ if (moFiles.length === 0) { const source = moFiles .map((f) => { const name = f.replace(/\.mo$/, ""); - return `import _${name.replace("/", "_")} "../../src/${name}";\n`; + return `import _${name.replace(/[\/\-]/g, "_")} "../../src/${name}";\n`; }) .join(""); diff --git a/test/ts/validate/version.ts b/test/ts/validate/version.ts index 7c4263de0..bbfbf33f0 100644 --- a/test/ts/validate/version.ts +++ b/test/ts/validate/version.ts @@ -39,7 +39,7 @@ async function getReadmeVersions(): Promise<{ async function main() { try { - const [mopsVersion, mocVersion, readmeVersions] = await Promise.all([ + const [mopsVersion, _mocVersion, readmeVersions] = await Promise.all([ getMopsVersion(), getMocVersion(), getReadmeVersions(),