Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add iterator_wrapping convenience container
authorMaxwell Pirtle <maxwellpirtle@gmail.com>
Mon, 6 Mar 2023 13:01:48 +0000 (14:01 +0100)
committerMaxwell Pirtle <maxwellpirtle@gmail.com>
Mon, 6 Mar 2023 13:27:31 +0000 (14:27 +0100)
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
src/xbt/utils/iter/iterator_wrapping.hpp [new file with mode: 0644]
tools/cmake/DefinePackages.cmake

index 1a2ac34..37e3826 100644 (file)
@@ -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 (file)
index 0000000..e4a4ea9
--- /dev/null
@@ -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 <tuple>
+#include <type_traits>
+
+namespace simgrid::xbt {
+
+template <typename T> struct ref_or_value {
+  using type = std::conditional_t<std::is_lvalue_reference<T>::value,
+                                  std::reference_wrapper<typename std::remove_reference<T>::type>, T>;
+};
+template <typename T> using ref_or_value_t = typename ref_or_value<T>::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 <typename Iterator, typename... Args> struct iterator_wrapping {
+private:
+  std::tuple<ref_or_value_t<Args>...> m_args;
+  iterator_wrapping(Args&&... begin_iteration) : m_args(std::forward<ref_or_value_t<Args>>(begin_iteration)...) {}
+
+  template <typename IteratorType, typename... Arguments>
+  friend iterator_wrapping<IteratorType, Arguments...> make_iterator_wrapping(Arguments&&... args);
+
+  template <typename IteratorType, typename... Arguments>
+  friend iterator_wrapping<IteratorType, Arguments...> 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 <typename Iterator, typename... Args>
+iterator_wrapping<Iterator, Args...> make_iterator_wrapping(Args&&... args)
+{
+  return iterator_wrapping<Iterator, Args...>(std::forward<Args>(args)...);
+}
+
+template <typename Iterator, typename... Args>
+iterator_wrapping<Iterator, Args...> make_iterator_wrapping_explicit(Args... args)
+{
+  return iterator_wrapping<Iterator, Args...>(std::forward<Args>(args)...);
+}
+
+} // namespace simgrid::xbt
+
+#endif
index fe21530..1024675 100644 (file)
@@ -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