2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/jit/id-set.h"
19 #include <folly/Lazy.h>
20 #include <folly/portability/GTest.h>
27 explicit Foo(uint32_t id
) : m_id
{id
} {}
28 uint32_t id() const { return m_id
; }
31 bool operator<(const Foo
& o
) const {
34 bool operator==(const Foo
& o
) const {
35 return m_id
== o
.m_id
;
39 using FooVector
= std::vector
<Foo
>;
40 using FooSet
= IdSet
<Foo
>;
42 void PrintTo(const Foo
& f
, std::ostream
* os
) {
46 void PrintTo(const FooVector
& v
, std::ostream
* os
) {
49 for (auto const& foo
: v
) {
50 if (!first
) *os
<< ", ";
57 FooVector
toFooVector(const FooSet
& s
) {
59 s
.forEach([&] (uint32_t id
) { ret
.emplace_back(Foo
{id
}); });
63 bool inFooVector(const FooVector
& v
, const Foo
& f
) {
64 return std::find(v
.begin(), v
.end(), f
) != v
.end();
67 void removeFromFooVector(FooVector
& v
, const Foo
& f
) {
68 v
.erase(std::remove(v
.begin(), v
.end(), f
), v
.end());
71 FooVector
unionFooVector(const FooVector
& v1
, const FooVector
& v2
) {
73 out
.insert(out
.end(), v2
.begin(), v2
.end());
74 std::sort(out
.begin(), out
.end());
75 out
.erase(std::unique(out
.begin(), out
.end()), out
.end());
79 auto const foos
= folly::lazy(
84 Foo
{FooSet::kBlockSize
- 1},
85 Foo
{FooSet::kBlockSize
},
86 Foo
{FooSet::kBlockSize
+ 1},
87 Foo
{FooSet::kBlockSize
* 2 - 1},
88 Foo
{FooSet::kBlockSize
* 2},
89 Foo
{FooSet::kBlockSize
* 2 + 1},
90 Foo
{FooSet::kBlockSize
* 5 + 27}
95 auto const membershipFoos
= folly::lazy(
98 out
.emplace_back(Foo
{2});
99 out
.emplace_back(FooSet::kBlockSize
+ 5);
100 out
.emplace_back(FooSet::kBlockSize
* 4 - 7);
101 out
.emplace_back(1000001);
106 auto const eraseOpFoos
= folly::lazy(
110 Foo
{FooSet::kBlockSize
+ 1},
111 Foo
{FooSet::kBlockSize
* 2 + 1},
112 Foo
{FooSet::kBlockSize
* 3 + 1},
113 Foo
{FooSet::kBlockSize
* 4 + 1}
118 auto const eraseOpFoosWithZero
= folly::lazy(
120 auto out
= eraseOpFoos();
121 out
.emplace_back(Foo
{0});
126 auto const eraseOpFoosWithZeroPairs
= folly::lazy(
128 std::vector
<std::pair
<Foo
, Foo
>> out
;
129 for (auto const& f1
: eraseOpFoosWithZero()) {
130 for (auto const& f2
: eraseOpFoosWithZero()) {
131 out
.emplace_back(f1
, f2
);
138 std::vector
<FooVector
> makeSubsets(const FooVector
& v
) {
139 std::vector
<FooVector
> out
;
141 uint64_t selected
= 0;
142 while (selected
< (1ULL << v
.size())) {
144 for (size_t i
= 0; i
< v
.size(); ++i
) {
145 if (selected
& (1ULL << i
)) current
.emplace_back(v
[i
]);
147 out
.emplace_back(std::move(current
));
154 void sortSubsets(std::vector
<FooVector
>& subsets
) {
155 for (auto& subset
: subsets
) std::sort(subset
.begin(), subset
.end());
158 std::vector
<FooVector
> permutations(const std::vector
<FooVector
>& sorted
) {
159 std::vector
<FooVector
> out
;
160 for (auto subset
: sorted
) {
162 out
.emplace_back(subset
);
163 } while (std::next_permutation(subset
.begin(), subset
.end()));
169 folly::lazy([] { return makeSubsets(foos()); });
170 auto const eraseOpSubsets
=
171 folly::lazy([] { return makeSubsets(eraseOpFoos()); });
173 auto const sortedSubsets
= folly::lazy(
181 auto const sortedEraseOpSubsets
= folly::lazy(
183 auto s
= eraseOpSubsets();
190 folly::lazy([] { return permutations(sortedSubsets()); });
191 auto const eraseOpAll
=
192 folly::lazy([] { return permutations(sortedEraseOpSubsets()); });
197 for (auto values
: all()) {
199 for (auto const& value
: values
) s
.add(value
);
201 EXPECT_EQ(s
.none(), values
.empty());
202 for (auto const& foo
: membershipFoos()) {
203 EXPECT_EQ(s
[foo
], inFooVector(values
, foo
));
205 std::sort(values
.begin(), values
.end());
206 EXPECT_EQ(toFooVector(s
), values
);
211 for (auto values
: sortedSubsets()) {
213 for (auto const& value
: values
) s
.add(value
);
215 for (auto const& foo
: membershipFoos()) {
217 removeFromFooVector(values
, foo
);
218 EXPECT_FALSE(s
[foo
]);
219 EXPECT_EQ(toFooVector(s
), values
);
220 for (auto const& foo
: membershipFoos()) {
221 EXPECT_EQ(s
[foo
], inFooVector(values
, foo
));
225 EXPECT_TRUE(s
.none());
230 for (auto const& values
: sortedSubsets()) {
232 for (auto const& value
: values
) s
.add(value
);
235 EXPECT_TRUE(s
.none());
236 for (auto const& foo
: membershipFoos()) EXPECT_FALSE(s
[foo
]);
237 EXPECT_EQ(toFooVector(s
), FooVector
{});
241 TEST(IdSet
, AddDuplicate
) {
242 for (auto const& values
: sortedSubsets()) {
244 for (auto const& value
: values
) s
.add(value
);
246 for (auto const& foo
: foos()) {
247 if (!inFooVector(values
, foo
)) continue;
251 EXPECT_EQ(toFooVector(s
), values
);
252 for (auto const& foo
: membershipFoos()) {
253 EXPECT_EQ(s
[foo
], inFooVector(values
, foo
));
260 for (auto const& values
: sortedSubsets()) {
262 for (auto const& value
: values
) s
.add(value
);
265 EXPECT_EQ(toFooVector(s
), toFooVector(s2
));
266 EXPECT_EQ(toFooVector(s2
), values
);
267 for (auto const& foo
: membershipFoos()) {
268 EXPECT_EQ(s
[foo
], s2
[foo
]);
269 EXPECT_EQ(s2
[foo
], inFooVector(values
, foo
));
271 EXPECT_EQ(s
.none(), s2
.none());
272 EXPECT_EQ(values
.empty(), s2
.none());
276 TEST(IdSet
, MoveCopy
) {
277 for (auto const& values
: sortedSubsets()) {
279 for (auto const& value
: values
) s
.add(value
);
282 auto const s2
= std::move(s
);
283 EXPECT_EQ(toFooVector(orig
), toFooVector(s2
));
284 EXPECT_EQ(toFooVector(s2
), values
);
285 for (auto const& foo
: membershipFoos()) {
286 EXPECT_EQ(orig
[foo
], s2
[foo
]);
287 EXPECT_EQ(s2
[foo
], inFooVector(values
, foo
));
289 EXPECT_EQ(orig
.none(), s2
.none());
290 EXPECT_EQ(values
.empty(), s2
.none());
294 TEST(IdSet
, Assign
) {
295 for (auto const& values1
: sortedSubsets()) {
296 for (auto const& values2
: sortedSubsets()) {
298 for (auto const& value
: values1
) s1
.add(value
);
299 for (auto const& value
: values2
) s2
.add(value
);
302 EXPECT_EQ(toFooVector(s1
), toFooVector(s2
));
303 EXPECT_EQ(toFooVector(s1
), values2
);
304 for (auto const& foo
: membershipFoos()) {
305 EXPECT_EQ(s1
[foo
], s2
[foo
]);
306 EXPECT_EQ(s1
[foo
], inFooVector(values2
, foo
));
308 EXPECT_EQ(s1
.none(), s2
.none());
309 EXPECT_EQ(values2
.empty(), s1
.none());
314 TEST(IdSet
, MoveAssign
) {
315 for (auto const& values1
: sortedSubsets()) {
316 for (auto const& values2
: sortedSubsets()) {
318 for (auto const& value
: values1
) s1
.add(value
);
319 for (auto const& value
: values2
) s2
.add(value
);
323 EXPECT_EQ(toFooVector(s1
), toFooVector(s3
));
324 EXPECT_EQ(toFooVector(s1
), values2
);
325 for (auto const& foo
: membershipFoos()) {
326 EXPECT_EQ(s1
[foo
], s3
[foo
]);
327 EXPECT_EQ(s1
[foo
], inFooVector(values2
, foo
));
329 EXPECT_EQ(s1
.none(), s3
.none());
330 EXPECT_EQ(values2
.empty(), s1
.none());
336 for (auto const& values1
: sortedSubsets()) {
337 for (auto const& values2
: sortedSubsets()) {
339 for (auto const& value
: values1
) s1
.add(value
);
340 for (auto const& value
: values2
) s2
.add(value
);
343 EXPECT_EQ(toFooVector(s1
), values2
);
344 EXPECT_EQ(toFooVector(s2
), values1
);
345 for (auto const& foo
: membershipFoos()) {
346 EXPECT_EQ(s1
[foo
], inFooVector(values2
, foo
));
347 EXPECT_EQ(s2
[foo
], inFooVector(values1
, foo
));
349 EXPECT_EQ(values2
.empty(), s1
.none());
350 EXPECT_EQ(values1
.empty(), s2
.none());
356 for (auto const& values1
: sortedSubsets()) {
357 for (auto const& values2
: sortedSubsets()) {
359 for (auto const& value
: values1
) s1
.add(value
);
360 for (auto const& value
: values2
) s2
.add(value
);
363 auto const values3
= unionFooVector(values1
, values2
);
364 EXPECT_EQ(toFooVector(s3
), values3
);
365 for (auto const& foo
: membershipFoos()) {
366 EXPECT_EQ(s1
[foo
] || s2
[foo
], s3
[foo
]);
367 EXPECT_EQ(s3
[foo
], inFooVector(values3
, foo
));
369 EXPECT_EQ(s1
.none() && s2
.none(), s3
.none());
370 EXPECT_EQ(values3
.empty(), s3
.none());
377 template <typename F
> void forEachEraseOpCase(F
&& f
) {
378 for (auto const& values
: sortedEraseOpSubsets()) {
379 for (auto const& p
: eraseOpFoosWithZeroPairs()) {
381 for (auto const& value
: values
) s
.add(value
);
385 removeFromFooVector(v
, p
.first
);
386 removeFromFooVector(v
, p
.second
);
392 template <typename F
> void forEachEraseOpPair(F
&& f
) {
393 for (auto const& values1
: sortedEraseOpSubsets()) {
394 for (auto const& values2
: sortedEraseOpSubsets()) {
395 for (auto const& erase1
: eraseOpFoosWithZeroPairs()) {
396 for (auto const& erase2
: eraseOpFoosWithZeroPairs()) {
398 for (auto const& value
: values1
) s1
.add(value
);
399 for (auto const& value
: values2
) s2
.add(value
);
400 s1
.erase(erase1
.first
);
401 s1
.erase(erase1
.second
);
402 s2
.erase(erase2
.first
);
403 s2
.erase(erase2
.second
);
407 removeFromFooVector(v1
, erase1
.first
);
408 removeFromFooVector(v1
, erase1
.second
);
409 removeFromFooVector(v2
, erase2
.first
);
410 removeFromFooVector(v2
, erase2
.second
);
420 TEST(IdSet
, EraseCopy
) {
422 [&] (const FooSet
& s1
, const FooVector
& v1
) {
424 EXPECT_EQ(toFooVector(s1
), toFooVector(s2
));
425 EXPECT_EQ(toFooVector(s2
), v1
);
426 for (auto const& foo
: eraseOpFoos()) {
427 EXPECT_EQ(s1
[foo
], s2
[foo
]);
428 EXPECT_EQ(s2
[foo
], inFooVector(v1
, foo
));
430 EXPECT_EQ(s1
.none(), s2
.none());
431 EXPECT_EQ(v1
.empty(), s2
.none());
436 TEST(IdSet
, EraseAssign
) {
438 [&] (FooSet
& s1
, const FooVector
&,
439 const FooSet
& s2
, const FooVector
& v2
) {
441 EXPECT_EQ(toFooVector(s1
), toFooVector(s2
));
442 EXPECT_EQ(toFooVector(s1
), v2
);
443 for (auto const& foo
: eraseOpFoos()) {
444 EXPECT_EQ(s1
[foo
], s2
[foo
]);
445 EXPECT_EQ(s1
[foo
], inFooVector(v2
, foo
));
447 EXPECT_EQ(s1
.none(), s2
.none());
448 EXPECT_EQ(v2
.empty(), s1
.none());
453 TEST(IdSet
, EraseUnion
) {
455 [&] (FooSet
& s1
, const FooVector
& v1
,
456 const FooSet
& s2
, const FooVector
& v2
) {
457 auto const v3
= unionFooVector(v1
, v2
);
458 auto const copy
= s1
;
460 EXPECT_EQ(toFooVector(s1
), v3
);
461 for (auto const& foo
: eraseOpFoos()) {
462 EXPECT_EQ(copy
[foo
] || s2
[foo
], s1
[foo
]);
463 EXPECT_EQ(s1
[foo
], inFooVector(v3
, foo
));
465 EXPECT_EQ(copy
.none() && s2
.none(), s1
.none());
466 EXPECT_EQ(v3
.empty(), s1
.none());