1 /**
2 Copyright: Copyright (c) 2018, Joakim Brännström. All rights reserved.
3 Authors: Jacob Carlborg
4 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
5 
6 Copied from DStep.
7 
8 Convenient functions for a set.
9 */
10 module dextool.set;
11 
12 import std.algorithm : filter;
13 import std.range : ElementType, isOutputRange;
14 
15 @safe:
16 
17 struct Set(T) {
18     alias Type = void[0][T];
19     Type data;
20 
21     bool opBinaryRight(string op)(T key) if (op == "in") {
22         return (key in data) !is null;
23     }
24 
25     bool empty() @safe pure nothrow const @nogc {
26         return data.length == 0;
27     }
28 
29     size_t length() @safe pure nothrow const @nogc {
30         return data.length;
31     }
32 
33     void add(T value) @safe pure nothrow {
34         data[value] = (void[0]).init;
35     }
36 
37     void add(Set!T set) @safe pure nothrow {
38         add(set.data);
39     }
40 
41     void add(Type set) @safe pure nothrow {
42         foreach (key; set.byKey)
43             data[key] = (void[0]).init;
44     }
45 
46     void add(Range)(Range r) @safe pure nothrow if (is(ElementType!Range == T)) {
47         foreach (v; r)
48             data[v] = (void[0]).init;
49     }
50 
51     void remove(T value) {
52         data.remove(value);
53     }
54 
55     Set!T clone() @safe pure nothrow {
56         Set!T result;
57         result.add(data);
58         return result;
59     }
60 
61     bool contains(T value) {
62         return (value in data) !is null;
63     }
64 
65     /** The set difference according to Set Theory.
66      *
67      * It is the set of all members in self that are not members of set.
68      */
69     Set!T setDifference(Set!T set) {
70         typeof(this) r;
71         foreach (k; toRange.filter!(a => !set.contains(a)))
72             r.add(k);
73 
74         return r;
75     }
76 
77     /** The symmetric difference according to Set Theory.
78      *
79      * It is the set of all objects that are a member of exactly one of self and set.
80      */
81     Set!T symmetricDifference(Set!T set) {
82         typeof(this) r;
83         foreach (k; toRange.filter!(a => !contains(a)))
84             r.add(k);
85         foreach (k; toRange.filter!(a => !contains(a)))
86             r.add(k);
87 
88         return r;
89     }
90 
91     /** The intersection according to Set Theory.
92      *
93      * It is the set of all objects that are members of both self and set.
94      */
95     Set!T intersect(Set!T set) {
96 
97         typeof(this) r;
98         foreach (k; toRange.filter!(a => set.contains(a)))
99             r.add(k);
100 
101         return r;
102     }
103 
104     auto toArray() {
105         import std.array : appender;
106 
107         auto app = appender!(T[])();
108         foreach (key; toRange)
109             app.put(key);
110         return app.data;
111     }
112 
113     auto toRange() inout {
114         return data.byKey;
115     }
116 
117     string toString() {
118         import std.array : appender;
119 
120         auto buf = appender!string;
121         toString(buf);
122         return buf.data;
123     }
124 
125     void toString(Writer)(ref Writer w) const if (isOutputRange!(Writer, char)) {
126         import std.format : formattedWrite;
127 
128         formattedWrite(w, "Set!(%s)(%-(%s, %))", T.stringof, toRange);
129     }
130 }
131 
132 auto toSet(RangeT)(RangeT range) {
133     import std.traits : Unqual;
134 
135     alias T = ElementType!RangeT;
136 
137     Set!(Unqual!T) result;
138     foreach (item; range)
139         result.add(item);
140     return result;
141 }