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