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.range : ElementType;
13 
14 alias Set(T) = void[0][T];
15 
16 void add(T)(ref void[0][T] self, T value) {
17     self[value] = (void[0]).init;
18 }
19 
20 /// Merge set into self
21 void add(T)(ref void[0][T] self, void[0][T] set) {
22     foreach (key; set.byKey) {
23         self.add(key);
24     }
25 }
26 
27 void remove(T)(ref void[0][T] self, T value) {
28     self.remove(value);
29 }
30 
31 Set!T clone(T)(ref void[0][T] self) {
32     Set!T result;
33     result.add(self);
34     return result;
35 }
36 
37 bool contains(T)(inout(void[0][T]) set, T value) {
38     return (value in set) !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 SetT setDifference(SetT)(ref SetT self, SetT set) {
46     import std.algorithm : filter;
47 
48     SetT r;
49     foreach (k; self.byKey.filter!(a => !set.contains(a))) {
50         r.add(k);
51     }
52 
53     return r;
54 }
55 
56 /** The symmetric difference according to Set Theory.
57  *
58  * It is the set of all objects that are a member of exactly one of `self` and `set`.
59  */
60 SetT symmetricDifference(SetT)(ref SetT self, SetT set) {
61     import std.algorithm : filter;
62 
63     SetT r;
64     foreach (k; self.byKey.filter!(a => !set.contains(a))) {
65         r.add(k);
66     }
67     foreach (k; set.byKey.filter!(a => !self.contains(a))) {
68         r.add(k);
69     }
70 
71     return r;
72 }
73 
74 /** The intersection according to Set Theory.
75  *
76  * It is the set of all objects that are members of both `self` and `set`.
77  */
78 SetT intersect(SetT)(ref SetT self, SetT set) {
79     import std.algorithm : filter;
80 
81     SetT r;
82     foreach (k; self.byKey.filter!(a => set.contains(a))) {
83         r.add(k);
84     }
85 
86     return r;
87 }
88 
89 Set!T setFromList(T)(T[] list) {
90     import std.traits;
91 
92     Set!(Unqual!T) result;
93 
94     foreach (item; list)
95         result.add(item);
96 
97     return result;
98 }
99 
100 Set!T setFromRange(T, RangeT)(RangeT range) if (is(ElementType!RangeT == T)) {
101     import std.traits;
102 
103     Set!(Unqual!T) result;
104 
105     foreach (item; range)
106         result.add(item);
107 
108     return result;
109 }
110 
111 auto setToList(T)(ref Set!T set) {
112     import std.array : appender;
113 
114     auto app = appender!(T[])();
115     foreach (key; set.byKey)
116         app.put(key);
117     return app.data;
118 }
119 
120 /// Specify the template type or it doesn't work.
121 auto setToRange(T)(ref inout Set!T set) {
122     return set.byKey;
123 }