bes Updated for version 3.20.10
Odometer.h
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of libdap, A C++ implementation of the OPeNDAP Data
4// Access Protocol.
5
6// Copyright (c) 2015 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25#ifndef ODOMETER_H_
26#define ODOMETER_H_
27
28#include <vector>
29
30namespace functions {
31
44{
45public:
46 typedef std::vector<unsigned int> shape;
47
48private:
49 // The state set by the ctor
50 shape d_shape;
51 unsigned int d_highest_offset;
52 unsigned int d_rank;
53
54 // The varying state of the Odometer
55 shape d_indices;
56 unsigned int d_offset;
57
58public:
67 Odometer(shape shape) : d_shape(shape), d_offset(0)
68 {
69 d_rank = d_shape.size();
70
71 // compute the highest offset value based on the array shape
72 d_highest_offset = 1;
73 for (unsigned int i = 0; i < d_rank; ++i) {
74 d_highest_offset *= d_shape.at(i);
75 }
76
77 d_indices.resize(d_rank, 0);
78 }
79#if 0
80 // This might be a good idea, but I didn't need it. The three D case is probably
81 // more important. jhrg 5/26/15
82 Odometer(unsigned int x, unsigned int y) : d_offset(0)
83 {
84 d_rank = 2;
85 d_shape.push_back(x);
86 d_shape.push_back(y);
87
88 // compute the highest offset value based on the array shape
89 d_highest_offset = 1;
90 for (unsigned int i = 0; i < d_rank; ++i) {
91 d_highest_offset *= d_shape.at(i);
92 }
93
94 d_indices.resize(d_rank, 0);
95 }
96#endif
97 /*
98 * reset(): zero internal state
99 * next(): move to the next element, incrementing the shape information and returning an offset into a linear vector for that element.
100 * Calling next() when the object is at the last element should return one past the last element. calling next() after that should throw an exception.
101 * vector<int> indices(): for the given state of the odometer, return the indices that match the offset.
102 * offset(): return the offset
103 * end(): should return one past the last valid offset - the value returned by next() when it indicates all elements/indices have been visited.
104 *
105 */
106
111 void reset()
112 {
113 for (unsigned int i = 0; i < d_rank; ++i)
114 d_indices.at(i) = 0;
115 d_offset = 0;
116 }
117
129 inline unsigned int next()
130 {
131 // About 2.4 seconds for 10^9 elements
132 shape::reverse_iterator si = d_shape.rbegin();
133 for (shape::reverse_iterator i = d_indices.rbegin(), e = d_indices.rend(); i != e; ++i, ++si) {
134 if (++(*i) == *si) {
135 *i = 0;
136 }
137 else {
138 break;
139 }
140 }
141
142 return ++d_offset;
143 }
144
145 // This version throws Error if offset() == end()
146 unsigned int next_safe();
147
155 inline unsigned int set_indices(const shape &indices)
156 {
157 d_indices = indices;
158#if 0
159 d_offset = 0;
160 unsigned int chunk_size = 1;
161#endif
162 // I copied this algorithm from Nathan's code in NDimenensionalArray in the
163 // ugrid function module. jhrg 5/22/15
164#if 0
165 shape::reverse_iterator si = d_shape.rbegin();
166 for (shape::reverse_iterator i = d_indices.rbegin(), e = d_indices.rend(); i != e; ++i, ++si) {
167 // The initial multiply is always 1 * N in both cases
168 d_offset += chunk_size * *i;
169 chunk_size *= *si;
170 }
171#endif
172 shape::reverse_iterator shape_index = d_shape.rbegin();
173 shape::reverse_iterator index = d_indices.rbegin(), index_end = d_indices.rend();
174 d_offset = *index++;
175 unsigned int chunk_size = *shape_index++;
176 while (index != index_end) {
177 d_offset += chunk_size * *index++;
178 chunk_size *= *shape_index++;
179 }
180
181 return d_offset;
182 }
183
184 unsigned int set_indices(const std::vector<int> &indices)
185 {
186 shape temp;
187 std::copy(indices.begin(), indices.end(), std::back_inserter(temp));
188
189 return set_indices(temp);
190 }
191
198 inline void indices(shape &indices)
199 {
200 indices = d_indices;
201 }
202
206 inline unsigned int offset()
207 {
208 return d_offset;
209 }
210
218 inline unsigned int end()
219 {
220 return d_highest_offset;
221 }
222
223};
224
225} // namespace libdap
226
227#endif /* ODOMETER_H_ */
unsigned int offset()
Definition: Odometer.h:206
unsigned int set_indices(const shape &indices)
Definition: Odometer.h:155
Odometer(shape shape)
Definition: Odometer.h:67
void indices(shape &indices)
Definition: Odometer.h:198
unsigned int end()
Definition: Odometer.h:218
unsigned int next()
Definition: Odometer.h:129