1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2020 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 
18 
19 
20 #ifndef LIBMESH_INT_RANGE_H
21 #define LIBMESH_INT_RANGE_H
22 
23 #include "libmesh/libmesh_common.h" // cast_int
24 
25 // C++ includes
26 #include <vector>
27 
28 namespace libMesh
29 {
30 
31 // Forward declarations
32 template <typename T> class DenseSubVector;
33 template <typename T> class DenseVector;
34 template <typename T> class NumericVector;
35 
36 /**
37  * The \p IntRange templated class is intended to make it easy to
38  * loop over integers which are indices of a container.
39  *
40  * In cases where such a range is defined by the result of a virtual
41  * function call, this allows range-based for loops to be easily
42  * written which make only a single such call, rather than a new call
43  * for each iteration.
44  *
45  * We perform a cast_int operation (no-op in opt mode, test+assert in
46  * debug) at construction time to make sure that the given range
47  * bounds are representable by the given range type.
48  *
49  * \author  Roy H. Stogner
50  */
51 
52 template <typename T>
53 class IntRange
54 {
55 public:
56   class iterator {
57   public:
iterator(T i)58     iterator (T i) : _i(i) {}
59 
60     T operator* () const { return _i; }
61 
62     const iterator & operator++ () {
63       ++_i;
64       return *this;
65     }
66 
67     iterator operator++ (int) {
68       iterator returnval(*this);
69       ++_i;
70       return returnval;
71     }
72 
73     bool operator== (const iterator & j) const {
74       return ( _i == j._i );
75     }
76 
77     bool operator!= (const iterator & j) const {
78       return !(*this == j);
79     }
80 
81   private:
82     T _i;
83   };
84 
85   template <typename U, typename V>
IntRange(U begin,V end)86   IntRange(U begin, V end) :
87     _begin(cast_int<T>(begin)),
88     _end(cast_int<T>(end))
89   {}
90 
begin()91   iterator begin() const { return _begin; }
92 
end()93   iterator end () const { return _end; }
94 
95 private:
96   iterator _begin, _end;
97 };
98 
99 
100 
101 /**
102  * Helper function that returns an IntRange<std::size_t> representing
103  * all the indices of the passed-in vector.
104  */
105 template <typename T>
index_range(const std::vector<T> & vec)106 IntRange<std::size_t> index_range(const std::vector<T> & vec)
107 {
108   return IntRange<std::size_t>(0, vec.size());
109 }
110 
111 
112 /**
113  * Same thing but for DenseVector
114  */
115 template <typename T>
index_range(const DenseVector<T> & vec)116 IntRange<unsigned int> index_range(const DenseVector<T> & vec)
117 {
118   return {0, vec.size()};
119 }
120 
121 
122 /**
123  * Same thing but for DenseSubVector
124  */
125 template <typename T>
index_range(const DenseSubVector<T> & vec)126 IntRange<unsigned int> index_range(const DenseSubVector<T> & vec)
127 {
128   return {0, vec.size()};
129 }
130 
131 
132 
133 /**
134  * Same thing but for NumericVector. Returns a range (first_local_index, last_local_index).
135  */
136 template <typename T>
index_range(const NumericVector<T> & vec)137 IntRange<numeric_index_type> index_range(const NumericVector<T> & vec)
138 {
139   return {vec.first_local_index(), vec.last_local_index()};
140 }
141 
142 
143 
144 /**
145  * The 2-parameter make_range() helper function returns an IntRange<T>
146  * when both input parameters are of type T. This saves a bit of
147  * typing over calling the IntRange<T> constructor directly.
148  */
149 template <typename T>
make_range(T beg,T end)150 IntRange<T> make_range(T beg, T end)
151 {
152   return {beg, end};
153 }
154 
155 
156 
157 /**
158  * The 1-parameter version of make_range() saves even more typing in
159  * the common case of a 0 starting point. Example usage:
160  *
161  * for (auto i : make_range(10))
162  *
163  * will loop from 0 to 9. In more realistic cases such as:
164  *
165  * for (auto i : make_range(foo()))
166  *
167  * this construction guarantees that the function foo() is called
168  * exactly once rather than once per loop iteration.
169  */
170 template <typename T>
make_range(T end)171 IntRange<T> make_range(T end)
172 {
173   return {T(0), end};
174 }
175 
176 } // namespace libMesh
177 
178 #endif // LIBMESH_INT_RANGE_H
179