1 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
2 // https://github.com/Dobiasd/FunctionalPlus
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 //  http://www.boost.org/LICENSE_1_0.txt)
6 
7 #pragma once
8 
9 #include <fplus/container_common.hpp>
10 
11 #include <algorithm>
12 #include <set>
13 #include <unordered_set>
14 
15 namespace fplus
16 {
17 
18 // API search type: set_includes : (Set a, Set a) -> Bool
19 // fwd bind count: 1
20 // Checks if every element of the second set is also present in the first set.
21 // Also known as is_subset_of.
22 template <typename SetType>
set_includes(const SetType & set1,const SetType & set2)23 bool set_includes(const SetType& set1, const SetType& set2)
24 {
25     return std::includes(std::begin(set1), std::end(set1),
26         std::begin(set2), std::end(set2));
27 }
28 
29 // API search type: unordered_set_includes : (Unordered_Set a, Unordered_Set a) -> Bool
30 // fwd bind count: 1
31 // Checks if every element of the second unordered_set
32 // is also present in the first unordered_set.
33 // Also known as is_subset_of.
34 template <typename UnorderSetType>
unordered_set_includes(const UnorderSetType & set1,const UnorderSetType & set2)35 bool unordered_set_includes(const UnorderSetType& set1,
36                             const UnorderSetType& set2)
37 {
38     auto first_not_included = std::find_if(set2.begin(), set2.end(),
39         [&](const typename UnorderSetType::value_type& x)
40         -> bool { return set1.find(x) == set1.end();});
41     return first_not_included == set2.end();
42 }
43 
44 // API search type: set_merge : (Set a, Set a) -> Set a
45 // fwd bind count: 1
46 // Returns the union of two given sets.
47 template <typename SetType>
set_merge(const SetType & set1,const SetType & set2)48 SetType set_merge(const SetType& set1, const SetType& set2)
49 {
50     SetType result;
51     auto itOut = internal::get_back_inserter(result);
52     std::merge(std::begin(set1), std::end(set1),
53         std::begin(set2), std::end(set2),
54         itOut);
55     return result;
56 }
57 
58 // API search type: unordered_set_merge : (Unordered_Set a, Unordered_Set a) -> Unordered_Set a
59 // fwd bind count: 1
60 // Returns the union of two given sets.
61 template <typename UnorderSetType>
unordered_set_merge(const UnorderSetType & set1,const UnorderSetType & set2)62 UnorderSetType unordered_set_merge(const UnorderSetType& set1, const UnorderSetType& set2)
63 {
64     UnorderSetType result;
65     auto itOut = internal::get_back_inserter(result);
66     std::copy(std::begin(set1), std::end(set1), itOut);
67     std::copy(std::begin(set2), std::end(set2), itOut);
68     return result;
69 }
70 
71 // API search type: set_intersection : (Set a, Set a) -> Set a
72 // fwd bind count: 1
73 // Returns the intersection of both sets.
74 template <typename SetType>
set_intersection(const SetType & set1,const SetType & set2)75 SetType set_intersection(const SetType& set1, const SetType& set2)
76 {
77     SetType result;
78     auto itOut = internal::get_back_inserter(result);
79     std::set_intersection(std::begin(set1), std::end(set1),
80         std::begin(set2), std::end(set2),
81         itOut);
82     return result;
83 }
84 
85 // API search type: unordered_set_intersection : (Unordered_Set a, Unordered_Set a) -> Unordered_Set a
86 // fwd bind count: 1
87 // Returns the intersection of both unordered_sets.
88 template <typename UnorderSetType>
unordered_set_intersection(const UnorderSetType & set1,const UnorderSetType & set2)89 UnorderSetType unordered_set_intersection(
90     const UnorderSetType& set1, const UnorderSetType& set2)
91 {
92     UnorderSetType result;
93     auto itOut = internal::get_back_inserter(result);
94     std::copy_if(std::begin(set2), std::end(set2),
95         itOut, [&](const typename UnorderSetType::value_type &x)
96         -> bool {return set1.find(x) != set1.end();});
97     return result;
98 }
99 
100 // API search type: set_is_disjoint : (Set a, Set a) -> Bool
101 // fwd bind count: 1
102 // Checks if two sets are disjoint.
103 template <typename SetType>
set_is_disjoint(const SetType & set1,const SetType & set2)104 bool set_is_disjoint(const SetType& set1, const SetType& set2)
105 {
106     return set_intersection(set1, set2).empty();
107 }
108 
109 // API search type: unordered_set_is_disjoint : (Unordered_Set a, Unordered_Set a) -> Bool
110 // fwd bind count: 1
111 // Checks if two unordered_sets are disjoint.
112 template <typename UnorderSetType>
unordered_set_is_disjoint(const UnorderSetType & set1,const UnorderSetType & set2)113 bool unordered_set_is_disjoint(
114     const UnorderSetType& set1, const UnorderSetType& set2)
115 {
116     return unordered_set_intersection(set1, set2).empty();
117 }
118 
119 // API search type: set_difference : (Set a, Set a) -> Set a
120 // fwd bind count: 1
121 // Returns the elements in set1 that are not present in set2.
122 template <typename SetType>
set_difference(const SetType & set1,const SetType & set2)123 SetType set_difference(const SetType& set1, const SetType& set2)
124 {
125     SetType result;
126     auto itOut = internal::get_back_inserter(result);
127     std::set_difference(std::begin(set1), std::end(set1),
128         std::begin(set2), std::end(set2),
129         itOut);
130     return result;
131 }
132 
133 // API search type: unordered_set_difference : (Unordered_Set a, Unordered_Set a) -> Unordered_Set a
134 // fwd bind count: 1
135 // Returns the elements in unordered_set1
136 // that are not present in unordered_set2.
137 template <typename UnorderSetType>
unordered_set_difference(const UnorderSetType & set1,const UnorderSetType & set2)138 UnorderSetType unordered_set_difference(const UnorderSetType& set1,
139 const UnorderSetType& set2)
140 {
141     UnorderSetType result;
142     auto itOut = internal::get_back_inserter(result);
143     std::copy_if(std::begin(set1), std::end(set1),
144         itOut, [&](const typename UnorderSetType::value_type &x)
145         -> bool {return set2.find(x) == set2.end();});
146     return result;
147 }
148 
149 // API search type: set_symmetric_difference : (Set a, Set a) -> Set a
150 // fwd bind count: 1
151 // Returns the symmetric difference of both sets.
152 template <typename SetType>
set_symmetric_difference(const SetType & set1,const SetType & set2)153 SetType set_symmetric_difference(const SetType& set1, const SetType& set2)
154 {
155     SetType result;
156     auto itOut = internal::get_back_inserter(result);
157     std::set_symmetric_difference(std::begin(set1), std::end(set1),
158         std::begin(set2), std::end(set2),
159         itOut);
160     return result;
161 }
162 
163 // API search type: unordered_set_symmetric_difference : (Unordered_Set a, Unordered_Set a) -> Unordered_Set a
164 // fwd bind count: 1
165 // Returns the symmetric difference of both unordered_sets.
166 template <typename UnorderSetType>
unordered_set_symmetric_difference(const UnorderSetType & set1,const UnorderSetType & set2)167 UnorderSetType unordered_set_symmetric_difference(
168     const UnorderSetType& set1, const UnorderSetType& set2)
169 {
170     UnorderSetType result;
171     auto itOut = internal::get_back_inserter(result);
172     std::copy_if(std::begin(set1), std::end(set1),
173         itOut, [&](const typename UnorderSetType::value_type &x)
174         -> bool {return set2.find(x) == set2.end();});
175     std::copy_if(std::begin(set2), std::end(set2),
176         itOut, [&](const typename UnorderSetType::value_type &x)
177         -> bool {return set1.find(x) == set1.end();});
178     return result;
179 }
180 
181 // API search type: sets_intersection : [Set a] -> Set a
182 // fwd bind count: 0
183 // Returns the intersection of the given sets.
184 // Also known as intersect_many.
185 // For performance try to sort the inputs sets prior, ascendending by size.
186 template <typename ContainerIn,
187     typename SetType = typename ContainerIn::value_type>
sets_intersection(const ContainerIn & sets)188 SetType sets_intersection(const ContainerIn& sets)
189 {
190     return fold_left_1(set_intersection<SetType>, sets);
191 }
192 
193 // API search type: unordered_sets_intersection : [Unordered_Set a] -> Unordered_Set a
194 // fwd bind count: 0
195 // Returns the intersection of the given unordered_sets.
196 // Also known as intersect_many.
197 template <typename ContainerIn,
198     typename UnordSetType = typename ContainerIn::value_type>
unordered_sets_intersection(const ContainerIn & sets)199 UnordSetType unordered_sets_intersection(const ContainerIn& sets)
200 {
201     return fold_left_1(unordered_set_intersection<UnordSetType>, sets);
202 }
203 
204 } // namespace fplus
205