1 /** 2 Copyright: Copyright (c) 2019, Joakim Brännström. All rights reserved. 3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 */ 6 module dsnapshot.set; 7 8 import std.range : ElementType; 9 10 struct Set(T) { 11 alias Type = void[0][T]; 12 Type data; 13 14 void add(T value) @safe pure nothrow { 15 data[value] = (void[0]).init; 16 } 17 18 void add(Set!T set) @safe pure nothrow { 19 add(set.data); 20 } 21 22 void add(Type set) @safe pure nothrow { 23 foreach (key; set.byKey) 24 data[key] = (void[0]).init; 25 } 26 27 void remove(T value) { 28 data.remove(value); 29 } 30 31 Set!T clone() @safe pure nothrow { 32 Set!T result; 33 result.add(data); 34 return result; 35 } 36 37 bool contains(T value) { 38 return (value in data) !is null; 39 } 40 41 /** The set difference according to Set Theory. 42 * 43 * It is the set of all members in `self` that are not members of `set`. 44 */ 45 Set!T setDifference(Set!T set) @safe pure nothrow { 46 import std.algorithm : filter; 47 48 typeof(this) r; 49 foreach (k; toRange.filter!(a => !set.contains(a))) 50 r.add(k); 51 52 return r; 53 } 54 55 /** The symmetric difference according to Set Theory. 56 * 57 * It is the set of all objects that are a member of exactly one of `self` and `set`. 58 */ 59 Set!T symmetricDifference(Set!T set) @safe pure nothrow { 60 import std.algorithm : filter; 61 62 typeof(this) r; 63 foreach (k; toRange.filter!(a => !contains(a))) 64 r.add(k); 65 foreach (k; toRange.filter!(a => !contains(a))) 66 r.add(k); 67 68 return r; 69 } 70 71 /** The intersection according to Set Theory. 72 * 73 * It is the set of all objects that are members of both `self` and `set`. 74 */ 75 Set!T intersect(Set!T set) { 76 import std.algorithm : filter; 77 78 typeof(this) r; 79 foreach (k; toRange.filter!(a => set.contains(a))) 80 r.add(k); 81 82 return r; 83 } 84 85 auto toList() { 86 import std.array : appender; 87 88 auto app = appender!(T[])(); 89 foreach (key; toRange) 90 app.put(key); 91 return app.data; 92 } 93 94 /// Specify the template type or it doesn't work. 95 auto toRange() { 96 return data.byKey; 97 } 98 } 99 100 Set!T toSet(T)(T[] list) { 101 import std.traits : Unqual; 102 103 Set!(Unqual!T) result; 104 foreach (item; list) 105 result.add(item); 106 return result; 107 } 108 109 auto toSet(RangeT)(RangeT range) { 110 import std.traits : Unqual; 111 112 alias T = ElementType!RangeT; 113 114 Set!(Unqual!T) result; 115 foreach (item; range) 116 result.add(item); 117 return result; 118 }