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 }