Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add iterator_wrapping convenience container
[simgrid.git] / src / xbt / utils / iter / iterator_wrapping.hpp
1 /* Copyright (c) 2004-2023 The SimGrid Team. All rights reserved.           */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #ifndef XBT_UTILS_ITER_ITERATOR_WRAPPING_HPP
7 #define XBT_UTILS_ITER_ITERATOR_WRAPPING_HPP
8
9 #include <tuple>
10 #include <type_traits>
11
12 namespace simgrid::xbt {
13
14 template <typename T> struct ref_or_value {
15   using type = std::conditional_t<std::is_lvalue_reference<T>::value,
16                                   std::reference_wrapper<typename std::remove_reference<T>::type>, T>;
17 };
18 template <typename T> using ref_or_value_t = typename ref_or_value<T>::type;
19
20 /**
21  * @brief A container which simply forwards its arguments to an
22  * iterator to begin traversal over another collection
23  *
24  * An `iterator_wrapping` acts as a proxy to the collection that it
25  * wraps. You create an `iterator_wrapping` as a convenience to needing
26  * to manually check stop and end conditions when constructing iterators
27  * directly, e.g. in a for-loop. With an `iterator_wrapping`, you can
28  * simply act as if the iterator were a collection and use it e.g. in
29  * auto-based for-loops.
30  *
31  * @class Iterator: The type of the iterator that is constructed to
32  * traverse the container.
33  *
34  * @note The wrapping only works correctly if the iterator type (Iterator)
35  * that is constructed can be default constructed, and only if the default-constructed
36  * iterate is a valid representation of the "end()" of any iterator type.
37  * That is, if you must supply additional arguments to indicate the end of a collection,
38  * you'll have to construct is manually.
39  */
40 template <typename Iterator, typename... Args> struct iterator_wrapping {
41 private:
42   std::tuple<ref_or_value_t<Args>...> m_args;
43   iterator_wrapping(Args&&... begin_iteration) : m_args(std::forward<ref_or_value_t<Args>>(begin_iteration)...) {}
44
45   template <typename IteratorType, typename... Arguments>
46   friend iterator_wrapping<IteratorType, Arguments...> make_iterator_wrapping(Arguments&&... args);
47
48   template <typename IteratorType, typename... Arguments>
49   friend iterator_wrapping<IteratorType, Arguments...> make_iterator_wrapping_explicit(Arguments... args);
50
51 public:
52   iterator_wrapping(const iterator_wrapping&)            = delete;
53   iterator_wrapping(iterator_wrapping&&)                 = delete;
54   iterator_wrapping& operator=(const iterator_wrapping&) = delete;
55   iterator_wrapping& operator=(iterator_wrapping&&)      = delete;
56
57   Iterator begin() const
58   {
59     return std::apply([](auto&... args) { return Iterator(args...); }, m_args);
60   }
61   Iterator end() const { return Iterator(); }
62 };
63
64 template <typename Iterator, typename... Args>
65 iterator_wrapping<Iterator, Args...> make_iterator_wrapping(Args&&... args)
66 {
67   return iterator_wrapping<Iterator, Args...>(std::forward<Args>(args)...);
68 }
69
70 template <typename Iterator, typename... Args>
71 iterator_wrapping<Iterator, Args...> make_iterator_wrapping_explicit(Args... args)
72 {
73   return iterator_wrapping<Iterator, Args...>(std::forward<Args>(args)...);
74 }
75
76 } // namespace simgrid::xbt
77
78 #endif