Skip to content

Commit bd53e62

Browse files
committed
Add more IntSet methods:
- add_range - is_subset_of - min/max - union, intersect, subtract, sym diff.
1 parent 873a8ae commit bd53e62

File tree

2 files changed

+150
-19
lines changed

2 files changed

+150
-19
lines changed

common/int_set.h

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef COMMON_INT_SET
22
#define COMMON_INT_SET
33

4+
#include <optional>
5+
46
#include "common/hb_set_unique_ptr.h"
57
namespace common {
68

@@ -78,14 +80,14 @@ class IntSet {
7880
}
7981

8082
IntSet(const hb_set_t* set) : set_(make_hb_set()) {
81-
// We always keep exclusive ownership of the internal set, so copy the contents
82-
// of the input set instead of referencing it.
83+
// We always keep exclusive ownership of the internal set, so copy the
84+
// contents of the input set instead of referencing it.
8385
hb_set_union(set_.get(), set);
8486
}
8587

8688
IntSet(const hb_set_unique_ptr& set) : set_(make_hb_set()) {
87-
// We always keep exclusive ownership of the internal set, so copy the contents
88-
// of the input set instead of referencing it.
89+
// We always keep exclusive ownership of the internal set, so copy the
90+
// contents of the input set instead of referencing it.
8991
hb_set_union(set_.get(), set.get());
9092
}
9193

@@ -147,8 +149,6 @@ class IntSet {
147149
return H::combine(std::move(h), harfbuzz_hash);
148150
}
149151

150-
// TODO(garretrieger): add union, intersection etc.
151-
152152
iterator begin() { return iterator(set_.get()); }
153153

154154
iterator end() { return iterator(); }
@@ -169,25 +169,72 @@ class IntSet {
169169

170170
void add(hb_codepoint_t codepoint) { hb_set_add(set_.get(), codepoint); }
171171

172+
void add_range(hb_codepoint_t start, hb_codepoint_t end) {
173+
hb_set_add_range(set_.get(), start, end);
174+
}
175+
172176
bool contains(hb_codepoint_t codepoint) const {
173177
return hb_set_has(set_.get(), codepoint);
174178
}
175179

180+
bool is_subset_of(const IntSet& other) const {
181+
return hb_set_is_subset(set_.get(), other.set_.get());
182+
}
183+
184+
std::optional<hb_codepoint_t> min() const {
185+
hb_codepoint_t value = hb_set_get_min(set_.get());
186+
if (value == HB_SET_VALUE_INVALID) {
187+
return std::nullopt;
188+
}
189+
return value;
190+
}
191+
192+
std::optional<hb_codepoint_t> max() const {
193+
hb_codepoint_t value = hb_set_get_max(set_.get());
194+
if (value == HB_SET_VALUE_INVALID) {
195+
return std::nullopt;
196+
}
197+
return value;
198+
}
199+
176200
void erase(hb_codepoint_t codepoint) { hb_set_del(set_.get(), codepoint); }
177201

178202
size_t size() const { return hb_set_get_population(set_.get()); }
179203

180204
bool empty() const { return hb_set_is_empty(set_.get()); }
181205

182-
// Remove all elements
206+
// Removes all elements
183207
void clear() { hb_set_clear(set_.get()); }
184208

209+
// Compute the union of this and other, store the result in this set.
210+
void union_set(const IntSet& other) {
211+
hb_set_union(set_.get(), other.set_.get());
212+
}
213+
214+
// Compute the intersection of this and other, store the result in this set.
215+
void intersect(const IntSet& other) {
216+
hb_set_intersect(set_.get(), other.set_.get());
217+
}
218+
219+
// Subtract other from this set.
220+
void subtract(const IntSet& other) {
221+
hb_set_subtract(set_.get(), other.set_.get());
222+
}
223+
224+
// Compute the symmetric difference of this and other, store the result in
225+
// this set.
226+
void symmetric_difference(const IntSet& other) {
227+
hb_set_symmetric_difference(set_.get(), other.set_.get());
228+
}
229+
185230
private:
186231
// Note: set_ must always point to a valid set object. nullptr is not allowed.
187-
// Note: we always retain exclusive ownership over set_. Normally hb_set_t* can be
188-
// shared (via hb_set_reference()), but for this container we don't ever expose
189-
// the underlying hb_set_t* pointer so that we know we're always the only owner.
190-
// This prevents the sets contents from being changed outside of this class.
232+
// Note: we always retain exclusive ownership over set_. Normally hb_set_t*
233+
// can be
234+
// shared (via hb_set_reference()), but for this container we don't ever
235+
// expose the underlying hb_set_t* pointer so that we know we're always
236+
// the only owner. This prevents the sets contents from being changed
237+
// outside of this class.
191238
hb_set_unique_ptr set_;
192239
};
193240

common/int_set_test.cc

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#include "common/int_set.h"
22

3+
#include <optional>
4+
5+
#include "absl/hash/hash_testing.h"
36
#include "common/hb_set_unique_ptr.h"
47
#include "gtest/gtest.h"
5-
#include "absl/hash/hash_testing.h"
68

79
namespace common {
810

@@ -126,7 +128,7 @@ TEST_F(IntSetTest, CopyHbSet) {
126128
// Make sure chaing hb_set doesn't cause changes in the IntSet's
127129
hb_set_add(hb_set.get(), 49);
128130

129-
IntSet expected {13, 47};
131+
IntSet expected{13, 47};
130132

131133
ASSERT_EQ(a, expected);
132134
ASSERT_EQ(b, expected);
@@ -219,13 +221,95 @@ TEST_F(IntSetTest, UseInHashSet) {
219221

220222
TEST_F(IntSetTest, SupportsAbslHash) {
221223
EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
222-
IntSet {},
223-
IntSet {7, 8},
224-
IntSet {7, 8, 11},
225-
IntSet {7, 8, 12},
226-
IntSet {8, 11},
227-
IntSet {7, 8, 12},
224+
IntSet{},
225+
IntSet{7, 8},
226+
IntSet{7, 8, 11},
227+
IntSet{7, 8, 12},
228+
IntSet{8, 11},
229+
IntSet{7, 8, 12},
228230
}));
229231
}
230232

233+
TEST_F(IntSetTest, MinMax) {
234+
IntSet empty{};
235+
IntSet a{8};
236+
IntSet b{7, 8, 11};
237+
238+
ASSERT_EQ(empty.min(), std::nullopt);
239+
ASSERT_EQ(empty.max(), std::nullopt);
240+
241+
ASSERT_EQ(*a.min(), 8);
242+
ASSERT_EQ(*a.max(), 8);
243+
244+
ASSERT_EQ(*b.min(), 7);
245+
ASSERT_EQ(*b.max(), 11);
246+
}
247+
248+
TEST_F(IntSetTest, AddRange) {
249+
IntSet a{7, 8, 11};
250+
251+
a.add_range(10, 15);
252+
IntSet expected{7, 8, 10, 11, 12, 13, 14, 15};
253+
254+
ASSERT_EQ(a, expected);
255+
}
256+
257+
TEST_F(IntSetTest, IsSubsetOf) {
258+
IntSet empty;
259+
IntSet a{7, 8};
260+
IntSet b{7, 8, 11};
261+
262+
ASSERT_TRUE(empty.is_subset_of(a));
263+
ASSERT_TRUE(empty.is_subset_of(b));
264+
265+
ASSERT_FALSE(a.is_subset_of(empty));
266+
ASSERT_FALSE(b.is_subset_of(empty));
267+
268+
ASSERT_TRUE(a.is_subset_of(b));
269+
ASSERT_FALSE(b.is_subset_of(a));
270+
271+
ASSERT_TRUE(a.is_subset_of(a));
272+
ASSERT_TRUE(b.is_subset_of(b));
273+
}
274+
275+
TEST_F(IntSetTest, Union) {
276+
IntSet a{5, 8};
277+
IntSet b{8, 11};
278+
IntSet expected{5, 8, 11};
279+
280+
a.union_set(b);
281+
282+
ASSERT_EQ(a, expected);
283+
}
284+
285+
TEST_F(IntSetTest, Intersect) {
286+
IntSet a{5, 8};
287+
IntSet b{8, 11};
288+
IntSet expected{8};
289+
290+
a.intersect(b);
291+
292+
ASSERT_EQ(a, expected);
293+
}
294+
295+
TEST_F(IntSetTest, Subtract) {
296+
IntSet a{5, 8};
297+
IntSet b{8, 11};
298+
IntSet expected{5};
299+
300+
a.subtract(b);
301+
302+
ASSERT_EQ(a, expected);
303+
}
304+
305+
TEST_F(IntSetTest, SymmetricDifference) {
306+
IntSet a{5, 8};
307+
IntSet b{8, 11};
308+
IntSet expected{5, 11};
309+
310+
a.symmetric_difference(b);
311+
312+
ASSERT_EQ(a, expected);
313+
}
314+
231315
} // namespace common

0 commit comments

Comments
 (0)