From af783aa2cd9a69a50e4d88c0094bf9098f88e609 Mon Sep 17 00:00:00 2001 From: Maxwell Pirtle Date: Mon, 6 Mar 2023 14:01:48 +0100 Subject: [PATCH] Add iterator_wrapping convenience container The iterator_wrapping structure is a light-weight container whose contents are traversed according to the behavior of the iterator that it creates when asked. The wrapping can only construct a container around an iterator whose termination condition can be succinctly represented with a default-constructed argument. It is not always the case that such a default-constructed iterator represents the end, so this should be kept in made (although this is generally the convention). Creating an instance of a wrapping allows, e.g., for the traversal over a collection without explicit need to construct the iterators/loop manually. For example, a struct `Iterable` may define a method `make_complicated_forward_iterator_over_me()` that can be called and used inside e.g. an auto-based for-loop. This helps with readability immensely. --- MANIFEST.in | 1 + src/xbt/utils/iter/iterator_wrapping.hpp | 78 ++++++++++++++++++++++++ tools/cmake/DefinePackages.cmake | 1 + 3 files changed, 80 insertions(+) create mode 100644 src/xbt/utils/iter/iterator_wrapping.hpp diff --git a/MANIFEST.in b/MANIFEST.in index 1a2ac3494f..37e38261d8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2517,6 +2517,7 @@ include src/xbt/string.cpp include src/xbt/unit-tests_main.cpp include src/xbt/utils/iter/LazyKSubsets.hpp include src/xbt/utils/iter/LazyPowerset.hpp +include src/xbt/utils/iter/iterator_wrapping.hpp include src/xbt/utils/iter/powerset.hpp include src/xbt/utils/iter/subsets.hpp include src/xbt/utils/iter/subsets_tests.cpp diff --git a/src/xbt/utils/iter/iterator_wrapping.hpp b/src/xbt/utils/iter/iterator_wrapping.hpp new file mode 100644 index 0000000000..e4a4ea95c7 --- /dev/null +++ b/src/xbt/utils/iter/iterator_wrapping.hpp @@ -0,0 +1,78 @@ +/* Copyright (c) 2004-2023 The SimGrid Team. All rights reserved. */ + +/* This program is free software; you can redistribute it and/or modify it + * under the terms of the license (GNU LGPL) which comes with this package. */ + +#ifndef XBT_UTILS_ITER_ITERATOR_WRAPPING_HPP +#define XBT_UTILS_ITER_ITERATOR_WRAPPING_HPP + +#include +#include + +namespace simgrid::xbt { + +template struct ref_or_value { + using type = std::conditional_t::value, + std::reference_wrapper::type>, T>; +}; +template using ref_or_value_t = typename ref_or_value::type; + +/** + * @brief A container which simply forwards its arguments to an + * iterator to begin traversal over another collection + * + * An `iterator_wrapping` acts as a proxy to the collection that it + * wraps. You create an `iterator_wrapping` as a convenience to needing + * to manually check stop and end conditions when constructing iterators + * directly, e.g. in a for-loop. With an `iterator_wrapping`, you can + * simply act as if the iterator were a collection and use it e.g. in + * auto-based for-loops. + * + * @class Iterator: The type of the iterator that is constructed to + * traverse the container. + * + * @note The wrapping only works correctly if the iterator type (Iterator) + * that is constructed can be default constructed, and only if the default-constructed + * iterate is a valid representation of the "end()" of any iterator type. + * That is, if you must supply additional arguments to indicate the end of a collection, + * you'll have to construct is manually. + */ +template struct iterator_wrapping { +private: + std::tuple...> m_args; + iterator_wrapping(Args&&... begin_iteration) : m_args(std::forward>(begin_iteration)...) {} + + template + friend iterator_wrapping make_iterator_wrapping(Arguments&&... args); + + template + friend iterator_wrapping make_iterator_wrapping_explicit(Arguments... args); + +public: + iterator_wrapping(const iterator_wrapping&) = delete; + iterator_wrapping(iterator_wrapping&&) = delete; + iterator_wrapping& operator=(const iterator_wrapping&) = delete; + iterator_wrapping& operator=(iterator_wrapping&&) = delete; + + Iterator begin() const + { + return std::apply([](auto&... args) { return Iterator(args...); }, m_args); + } + Iterator end() const { return Iterator(); } +}; + +template +iterator_wrapping make_iterator_wrapping(Args&&... args) +{ + return iterator_wrapping(std::forward(args)...); +} + +template +iterator_wrapping make_iterator_wrapping_explicit(Args... args) +{ + return iterator_wrapping(std::forward(args)...); +} + +} // namespace simgrid::xbt + +#endif diff --git a/tools/cmake/DefinePackages.cmake b/tools/cmake/DefinePackages.cmake index fe21530c0c..1024675379 100644 --- a/tools/cmake/DefinePackages.cmake +++ b/tools/cmake/DefinePackages.cmake @@ -284,6 +284,7 @@ set(XBT_SRC src/xbt/xbt_parse_units.cpp src/xbt/xbt_replay.cpp src/xbt/xbt_str.cpp + src/xbt/utils/iter/iterator_wrapping.hpp src/xbt/utils/iter/subsets.hpp src/xbt/utils/iter/powerset.hpp src/xbt/utils/iter/variable_for_loop.hpp -- 2.20.1