Skip to content

Commit

Permalink
Set operators fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
ZILtoid1991 committed May 28, 2020
1 parent 1fdb100 commit 662dc42
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 22 deletions.
62 changes: 52 additions & 10 deletions source/collections/hashset.d
Original file line number Diff line number Diff line change
Expand Up @@ -23,53 +23,75 @@ 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){
result.removeByElem(e);
}
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);
}
Expand All @@ -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 == "/=") {
Expand All @@ -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);
Expand All @@ -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 {
Expand All @@ -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);
}
31 changes: 30 additions & 1 deletion source/collections/linkedlist.d
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
}
32 changes: 31 additions & 1 deletion source/collections/sortedlist.d
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
74 changes: 64 additions & 10 deletions source/collections/treemap.d
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}
}
/**
Expand Down Expand Up @@ -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);
}
}

0 comments on commit 662dc42

Please sign in to comment.