bes  Updated for version 3.20.6
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 
30 namespace functions {
31 
43 class Odometer
44 {
45 public:
46  typedef std::vector<unsigned int> shape;
47 
48 private:
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 
58 public:
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_ */
functions::Odometer::next
unsigned int next()
Definition: Odometer.h:129
functions::Odometer::reset
void reset()
Definition: Odometer.h:111
functions::Odometer::offset
unsigned int offset()
Definition: Odometer.h:206
functions::Odometer::indices
void indices(shape &indices)
Definition: Odometer.h:198
functions::Odometer::end
unsigned int end()
Definition: Odometer.h:218
functions::Odometer::set_indices
unsigned int set_indices(const shape &indices)
Definition: Odometer.h:155
functions::Odometer
Definition: Odometer.h:43
functions::Odometer::Odometer
Odometer(shape shape)
Definition: Odometer.h:67