From 662dc42dc020cc01eb527e336e4ac3ae3213ca1c Mon Sep 17 00:00:00 2001 From: ziltoid1991 Date: Thu, 28 May 2020 12:56:54 +0200 Subject: [PATCH] Set operators fixed --- source/collections/hashset.d | 62 ++++++++++++++++++++++----- source/collections/linkedlist.d | 31 +++++++++++++- source/collections/sortedlist.d | 32 +++++++++++++- source/collections/treemap.d | 74 ++++++++++++++++++++++++++++----- 4 files changed, 177 insertions(+), 22 deletions(-) diff --git a/source/collections/hashset.d b/source/collections/hashset.d index 3a5bbc7..6ff4ec7 100644 --- a/source/collections/hashset.d +++ b/source/collections/hashset.d @@ -23,44 +23,66 @@ public struct HashSet(K, alias hashFunc = defaultHash!K) { * Puts an item into the hash set, then returns the generated hashcode. * Returns uint.init if there's a hashcode match. */ - uint put(K key) @safe pure nothrow { + HashType put(K key) @safe pure nothrow { return backend.put(hashFunc(key)); } + /** + * Puts a hashcode into the hash set. + */ + private HashType put(HashType key) @safe pure nothrow { + return backend.put(key); + } /** * Returns true if the element exists within the set, false otherwise. */ bool has(K key) @safe pure nothrow { return backend.has(hashFunc(key)); } + /** + * Returns the amount of elements found in the set. + */ + size_t hasRange(R)(R range) @safe pure nothrow { + size_t result; + foreach (key; range) { + if(has(key)) result++; + } + return result; + } /** * Removes an element by match. * Returns the hashcode if found, or uint.init if not. */ - uint removeByElem(K key) @safe pure nothrow { + HashType removeByElem(K key) @safe pure nothrow { return backend.removeByElem(hashFunc(key)); } + /** + * Removes an element by hashcode. + */ + HashType removeByElem(HashType key) @safe pure nothrow { + return backend.removeByElem(key); + } alias remove = removeByElem; /** * Set operators. * Enables math operations on sets, like unions and intersections. * Could work on ranges in general as long as they implement some basic functions, like iteration. */ - HashSet!(K, hashFunc, Backend) opBinary(string op, R)(R rhs) { + HashSet!(K, hashFunc) opBinary(string op, R)(R rhs) { static if(op == "|" || op == "~") {//Union - HashSet!(K, hashFunc, Backend) result; + HashSet!(K, hashFunc) result; foreach(e ; backend) result.put(e); foreach(e ; rhs) result.put(e); return result; } else static if(op == "&" || op == "*") {//Intersection - HashSet!(K, hashFunc, Backend); + HashSet!(K, hashFunc) result; foreach(e ; rhs){ if(backend.has(e)) result.put(e); } return result; } else static if(op == "-" || op == "/") {//Complement - HashSet!(K, hashFunc, Backend) result; + HashSet!(K, hashFunc) result; foreach(e ; backend) result.put(e); foreach(e ; rhs){ @@ -68,8 +90,8 @@ public struct HashSet(K, alias hashFunc = defaultHash!K) { } return result; } else static if(op == "^"){//Difference - HashSet!(K, hashFunc, Backend) result = this | rhs; - HashSet!(K, hashFunc, Backend) common = this & rhs; + HashSet!(K, hashFunc) result = this | rhs; + HashSet!(K, hashFunc) common = this & rhs; foreach(e ; common){ result.removeByElem(e); } @@ -79,7 +101,7 @@ public struct HashSet(K, alias hashFunc = defaultHash!K) { /** * Set operators. */ - HashSet!(K, hashFunc, Backend) opOpAssign(string op)(E value) { + HashSet!(K, hashFunc) opOpAssign(string op)(E value) { static if(op == "~=") {//Append put(value); } else static if(op == "-=" || op == "/=") { @@ -90,7 +112,7 @@ public struct HashSet(K, alias hashFunc = defaultHash!K) { /** * Set operators. */ - HashSet!(K, hashFunc, Backend) opOpAssign(string op, R)(R range) { + HashSet!(K, hashFunc) opOpAssign(string op, R)(R range) { static if(op == "~=" || op == "|=") {//Append foreach(val; range) put(val); @@ -100,6 +122,9 @@ public struct HashSet(K, alias hashFunc = defaultHash!K) { } else static assert(0, "Operator " ~ op ~ "not supported"); return this; } + private int opApply(scope int delegate(HashType) dg) { + return backend.opApply(dg); + } } unittest { @@ -110,4 +135,21 @@ unittest { assert(set.has("CCCCCC")); assert(set.has("DDDDDD")); assert(!set.has("000000")); +} + +unittest { ///Test set operators + alias MatchFinder = HashSet!(string); + MatchFinder a = MatchFinder(["AAAA", "BBBB", "CCCC", "DDDD", "EEEE"]), b = MatchFinder(["DDDD", "EEEE", "FFFF", "GGGG"]); + MatchFinder c = MatchFinder(["BBBB", "CCCC", "EEEE", "GGGG"]), d = MatchFinder(["AAAA", "EEEE", "BBBB", "GGGG"]); + MatchFinder union_ab = a | b, union_ad = a | d; + assert(union_ab.hasRange(["AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG"]) == 7); + assert(union_ad.hasRange(["AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "GGGG"]) == 6); + MatchFinder intrsctn_ab = a & b, intrsctn_cd = c & d, intrsctn_ac = a & c; + MatchFinder diff_ab = a ^ b; + MatchFinder comp_ab = a - b; + assert(intrsctn_ab.hasRange(["DDDD", "EEEE"]) == 2); + assert(intrsctn_ac.hasRange(["BBBB", "CCCC", "EEEE"]) == 3); + assert(intrsctn_cd.hasRange(["BBBB", "GGGG"]) == 2); + assert(diff_ab.hasRange(["AAAA", "BBBB", "CCCC", "FFFF", "GGGG"]) == 5); + assert(comp_ab.hasRange(["AAAA", "BBBB", "CCCC"]) == 3); } \ No newline at end of file diff --git a/source/collections/linkedlist.d b/source/collections/linkedlist.d index 68dd1f0..151bfa2 100644 --- a/source/collections/linkedlist.d +++ b/source/collections/linkedlist.d @@ -323,6 +323,16 @@ public struct LinkedList(E, bool allowDuplicates = true, alias equal = "a == b") if (root !is null) return root.has(value); else return false; } + /** + * Returns the amount of elements found in the set. + */ + public size_t hasRange(R)(R range) @nogc @safe pure nothrow { + size_t result; + foreach (key; range) { + if(has(key)) result++; + } + return result; + } /** * Set operators. * Enables math operations on sets, like unions and intersections. @@ -343,7 +353,7 @@ public struct LinkedList(E, bool allowDuplicates = true, alias equal = "a == b") } return result; } else static if(op == "-" || op == "/") {//Complement - LinkedList!(E, allowDuplicates, equal) result; + LinkedList!(E, allowDuplicates, equal) result = LinkedList!(E, allowDuplicates, equal)(this); foreach(e ; rhs){ result.removeByElem(e); } @@ -496,4 +506,23 @@ unittest { assert(sc.has(10), sc.toString()); assert(sd.has(-1), sd.toString()); assert(!se.has(-1), se.toString()); +} + +unittest { //test set operators + alias IntSet = LinkedList!(int, false); + IntSet a = IntSet([1, 3, 5, 7, 9]), b = IntSet([1, 5, 9]), c = IntSet([3, 7]); + IntSet union_ab = a | b, union_ac = a | c, union_bc = b | c; + IntSet intrsctn_ab = a & b, intrsctn_ac = a & c; + IntSet cmplmnt_ab = a - b, cmplmnt_ac = a - c; + IntSet diff_ab = a ^ b, diff_ac = a ^ c, diff_bc = b ^ c; + assert(union_ab.hasRange([1, 3, 5, 7, 9]) == 5); + assert(union_ac.hasRange([1, 3, 5, 7, 9]) == 5); + assert(union_bc.hasRange([1, 3, 5, 7, 9]) == 5); + assert(intrsctn_ab.hasRange([1, 5, 9]) == 3); + assert(intrsctn_ac.hasRange([3, 7]) == 2); + assert(cmplmnt_ab.hasRange([3, 7]) == 2); + assert(cmplmnt_ac.hasRange([1, 5, 9]) == 3); + assert(diff_ab.hasRange([3, 7]) == 2); + assert(diff_ac.hasRange([1, 5, 9]) == 3); + assert(diff_bc.hasRange([1, 3, 5, 7, 9]) == 5); } \ No newline at end of file diff --git a/source/collections/sortedlist.d b/source/collections/sortedlist.d index a5e21d2..5f0245a 100644 --- a/source/collections/sortedlist.d +++ b/source/collections/sortedlist.d @@ -97,6 +97,16 @@ public struct SortedList(E, alias cmp = "a < b", bool allowDuplicates = true, al } return false; } + /** + * Returns the amount of elements found in the set. + */ + size_t hasRange(R)(R range) @nogc @safe pure nothrow { + size_t result; + foreach (key; range) { + if(has(key)) result++; + } + return result; + } /** * Returns the index of the given element, or throws an ElementNotFoundException if not found. */ @@ -151,7 +161,7 @@ public struct SortedList(E, alias cmp = "a < b", bool allowDuplicates = true, al } return result; } else static if(op == "-" || op == "/") {//Complement - SortedList!(E, cmp, allowDuplicates, equal) result; + SortedList!(E, cmp, allowDuplicates, equal) result = SortedList!(E, cmp, allowDuplicates, equal)(this); foreach(e ; rhs){ result.removeByElem(e); } @@ -390,4 +400,24 @@ public struct SortedList(E, alias cmp = "a < b", bool allowDuplicates = true, al foreach(e; sis) { writeln(e); } +} + +unittest { + //test set operators + alias IntSet = SortedList!(int, "a > b", false, "a == b"); + IntSet a = IntSet([1, 3, 5, 7, 9]), b = IntSet([1, 5, 9]), c = IntSet([3, 7]); + IntSet union_ab = a | b, union_ac = a | c, union_bc = b | c; + IntSet intrsctn_ab = a & b, intrsctn_ac = a & c; + IntSet cmplmnt_ab = a - b, cmplmnt_ac = a - c; + IntSet diff_ab = a ^ b, diff_ac = a ^ c, diff_bc = b ^ c; + assert(union_ab.hasRange([1, 3, 5, 7, 9]) == 5); + assert(union_ac.hasRange([1, 3, 5, 7, 9]) == 5); + assert(union_bc.hasRange([1, 3, 5, 7, 9]) == 5); + assert(intrsctn_ab.hasRange([1, 5, 9]) == 3); + assert(intrsctn_ac.hasRange([3, 7]) == 2); + assert(cmplmnt_ab.hasRange([3, 7]) == 2); + assert(cmplmnt_ac.hasRange([1, 5, 9]) == 3); + assert(diff_ab.hasRange([3, 7]) == 2); + assert(diff_ac.hasRange([1, 5, 9]) == 3); + assert(diff_bc.hasRange([1, 3, 5, 7, 9]) == 5); } \ No newline at end of file diff --git a/source/collections/treemap.d b/source/collections/treemap.d index 5354d71..4e0b0d3 100644 --- a/source/collections/treemap.d +++ b/source/collections/treemap.d @@ -132,7 +132,7 @@ public struct TreeMap(K, E, bool nogcIndexing = true, alias less = "a < b") { private size_t nOfElements;///Current number of elements in this collection private Node* root; ///The root element of the tree - static if (E.stringof != "void"){ + static if (E.stringof != "void") { static if (nogcIndexing) { /** * @nogc capable indexing. @@ -191,10 +191,16 @@ public struct TreeMap(K, E, bool nogcIndexing = true, alias less = "a < b") { } } } else { + /** + * Creates a treeset from a preexisting range. + */ + public this(R)(R src) @safe pure nothrow { + foreach (key; src) put(key); + } /** * Returns true if the element exists within the set, false otherwise. */ - bool has(T)(T key)@nogc @safe pure nothrow{ + public bool has(T)(T key) @nogc @safe pure nothrow { Node* crnt = root; while(crnt) { if(binaryFun!less(key, crnt.key)) { //key is smaller than current element's, look at lesser elements @@ -207,6 +213,16 @@ public struct TreeMap(K, E, bool nogcIndexing = true, alias less = "a < b") { } return false; } + /** + * Returns the amount of elements found in the set. + */ + public size_t hasRange(R)(R range) @nogc @safe pure nothrow { + size_t result; + foreach (key; range) { + if(has(key)) result++; + } + return result; + } /** * Set operators. * Enables math operations on sets, like unions and intersections. @@ -215,7 +231,7 @@ public struct TreeMap(K, E, bool nogcIndexing = true, alias less = "a < b") { TreeMap!(K, E, nogcIndexing, less) opBinary(string op, R)(R rhs) { static if(op == "|" || op == "~") {//Union TreeMap!(K, E, nogcIndexing, less) result; - foreach(e ; root) + foreach(e ; this) result.put(e); foreach(e ; rhs) result.put(e); @@ -228,7 +244,7 @@ public struct TreeMap(K, E, bool nogcIndexing = true, alias less = "a < b") { return result; } else static if(op == "-" || op == "/") {//Complement TreeMap!(K, E, nogcIndexing, less) result; - foreach(e ; root) + foreach(e ; this) result.put(e); foreach(e ; rhs){ result.removeByElem(e); @@ -438,6 +454,7 @@ public struct TreeMap(K, E, bool nogcIndexing = true, alias less = "a < b") { else crnt = crnt.right; } else { //Kaymatch found crnt.key = key; + crnt = null; } } rebalance(); @@ -546,38 +563,57 @@ public struct TreeMap(K, E, bool nogcIndexing = true, alias less = "a < b") { * Implements a simple left-to-right tree traversal. */ int opApply(scope int delegate(ref E) dg) { - return root.opApply(dg); + if(root !is null) return root.opApply(dg); + else return 0; } /** * Implements a simple left-to-right tree traversal. */ int opApply(scope int delegate(K, ref E) dg) { - return root.opApply(dg); + if(root !is null) return root.opApply(dg); + else return 0; } /** * Implements a simple right-to-left tree traversal. */ int opApplyReverse(scope int delegate(ref E) dg) { - return root.opApplyReverse(dg); + if(root !is null) return root.opApplyReverse(dg); + else return 0; } /** * Implements a simple right-to-left tree traversal. */ int opApplyReverse(scope int delegate(K, ref E) dg) { - return root.opApplyReverse(dg); + if(root !is null) return root.opApplyReverse(dg); + else return 0; } } else { /** * Implements a simple left-to-right tree traversal by depth. */ int opApply(scope int delegate(K) dg) { - return root.opApply(dg); + if(root !is null) return root.opApply(dg); + else return 0; } /** * Implements a simple right-to-left tree traversal. */ int opApplyReverse(scope int delegate(K) dg) { - return root.opApplyReverse(dg); + if(root !is null) return root.opApplyReverse(dg); + else return 0; + } + /** + * Returns an array representation of the set. + */ + @property K[] arrayOf() { + K[] result; + result.reserve(nOfElements); + int putToResult(K elem) @safe pure nothrow { + result ~= elem; + return 0; + } + root.opApply(&putToResult); + return result; } } /** @@ -711,4 +747,22 @@ unittest { } assert(test0.length == 0, "Treemap item removal failure"); } + { //test set operators + alias IntSet = TreeMap!(int, void, true); + IntSet a = IntSet([1, 3, 5, 7, 9]), b = IntSet([1, 5, 9]), c = IntSet([3, 7]); + IntSet union_ab = a | b, union_ac = a | c, union_bc = b | c; + IntSet intrsctn_ab = a & b, intrsctn_ac = a & c; + IntSet cmplmnt_ab = a - b, cmplmnt_ac = a - c; + IntSet diff_ab = a ^ b, diff_ac = a ^ c, diff_bc = b ^ c; + assert(union_ab.hasRange([1, 3, 5, 7, 9]) == 5); + assert(union_ac.hasRange([1, 3, 5, 7, 9]) == 5); + assert(union_bc.hasRange([1, 3, 5, 7, 9]) == 5); + assert(intrsctn_ab.hasRange([1, 5, 9]) == 3); + assert(intrsctn_ac.hasRange([3, 7]) == 2); + assert(cmplmnt_ab.hasRange([3, 7]) == 2); + assert(cmplmnt_ac.hasRange([1, 5, 9]) == 3); + assert(diff_ab.hasRange([3, 7]) == 2); + assert(diff_ac.hasRange([1, 5, 9]) == 3); + assert(diff_bc.hasRange([1, 3, 5, 7, 9]) == 5); + } } \ No newline at end of file