namespace simgrid::xbt {
-template <class Iterable> class LazyKSubsets<Iterable>;
+template <class Iterable> class LazyKSubsets;
template <class Iterable> LazyKSubsets<Iterable> make_k_subsets_iter(unsigned k, const Iterable& container);
/**
*/
template <class Iterable> class LazyKSubsets final {
public:
- auto begin() const { return subsets_iterator<Iterable::iterator>(k, iterable.begin(), iterable.end()); }
- auto end() const { return subsets_iterator<Iterable::iterator>(k); }
+ auto begin() const
+ {
+ return subsets_iterator<typename Iterable::const_iterator>(k, iterable.begin(), iterable.end());
+ }
+ auto end() const { return subsets_iterator<typename Iterable::const_iterator>(k); }
private:
const unsigned k;
const Iterable& iterable;
LazyKSubsets(unsigned k, const Iterable& iterable) : k(k), iterable(iterable) {}
- friend LazyKSubsets<Iterable> make_k_subsets_iter(unsigned k, const Iterable& iterable);
+
+ template <class IterableType>
+ friend LazyKSubsets<IterableType> make_k_subsets_iter(unsigned k, const IterableType& iterable);
};
template <class Iterable> LazyKSubsets<Iterable> make_k_subsets_iter(unsigned k, const Iterable& container)
namespace simgrid::xbt {
-template <class Iterable> class LazyPowerset<Iterable>;
+template <class Iterable> class LazyPowerset;
template <class Iterable> LazyPowerset<Iterable> make_powerset_iter(const Iterable& container);
/**
*/
template <class Iterable> class LazyPowerset final {
public:
- auto begin() const { return powerset_iterator<Iterable::iterator>(iterable.begin(), iterable.end()); }
- auto end() const { return powerset_iterator<Iterable::iterator>(); }
+ auto begin() const { return powerset_iterator<typename Iterable::const_iterator>(iterable.begin(), iterable.end()); }
+ auto end() const { return powerset_iterator<typename Iterable::const_iterator>(); }
private:
const Iterable& iterable;
LazyPowerset(const Iterable& iterable) : iterable(iterable) {}
- friend LazyPowerset<Iterable> make_powerset_iter(const Iterable& iterable);
+ template <class IterableType> friend LazyPowerset<IterableType> make_powerset_iter(const IterableType& iterable);
};
template <class Iterable> LazyPowerset<Iterable> make_powerset_iter(const Iterable& container)
--- /dev/null
+#include "src/3rd-party/catch.hpp"
+#include "src/xbt/utils/iter/LazyKSubsets.hpp"
+#include "src/xbt/utils/iter/LazyPowerset.hpp"
+
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+using namespace simgrid::xbt;
+
+// This is used in a number of tests below
+// to verify that counts of elements for example.
+static unsigned integer_power(unsigned x, unsigned p)
+{
+ unsigned i = 1;
+ for (unsigned j = 1; j <= p; j++)
+ i *= x;
+ return i;
+}
+
+TEST_CASE("simgrid::xbt::subsets_iterator: Iteration General Properties")
+{
+ std::vector<int> example_vec{0, 1, 2, 3, 4, 5, 6, 7};
+
+ SECTION("Each element of each subset is distinct and appears half of the time")
+ {
+ for (unsigned k = 0; static_cast<size_t>(k) < example_vec.size(); k++) {
+ for (auto& subset : make_k_subsets_iter(k, example_vec)) {
+ // Each subset must have size `k`
+ REQUIRE(subset.size() == k);
+
+ // Each subset must be comprised only of distinct elements
+ std::unordered_set<int> elements_seen(k);
+ for (const auto& element_ptr : subset) {
+ const auto& element = *element_ptr;
+ REQUIRE(elements_seen.find(element) == elements_seen.end());
+ elements_seen.insert(element);
+ }
+ }
+ }
+ }
+}
+
+TEST_CASE("simgrid::xbt::powerset_iterator: Iteration General Properties")
+{
+ std::vector<int> example_vec{0, 1, 2, 3, 4, 5, 6, 7};
+
+ SECTION("Each element of each subset is distinct and appears half of the time in all subsets iteration")
+ {
+ // Each element is expected to be found in half of the sets
+ const unsigned k = static_cast<unsigned>(example_vec.size());
+ const int expected_count = integer_power(2, k - 1);
+
+ std::unordered_map<int, int> element_counts(k);
+
+ for (auto& subset : make_powerset_iter(example_vec)) {
+ // Each subset must be comprised only of distinct elements
+ std::unordered_set<int> elements_seen(k);
+ for (const auto& element_ptr : subset) {
+ const auto& element = *element_ptr;
+ REQUIRE(elements_seen.find(element) == elements_seen.end());
+ elements_seen.insert(element);
+ element_counts[element]++;
+ }
+ }
+
+ for (const auto& iter : element_counts) {
+ REQUIRE(iter.second == expected_count);
+ }
+ }
+}
\ No newline at end of file