bes  Updated for version 3.17.0
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 
39 class Odometer
40 {
41 public:
42  typedef std::vector<unsigned int> shape;
43 
44 private:
45  // The state set by the ctor
46  shape d_shape;
47  unsigned int d_highest_offset;
48  unsigned int d_rank;
49 
50  // The varying state of the Odometer
51  shape d_indices;
52  unsigned int d_offset;
53 
54 public:
63  Odometer(shape shape) : d_shape(shape), d_offset(0)
64  {
65  d_rank = d_shape.size();
66 
67  // compute the highest offset value based on the array shape
68  d_highest_offset = 1;
69  for (unsigned int i = 0; i < d_rank; ++i) {
70  d_highest_offset *= d_shape.at(i);
71  }
72 
73  d_indices.resize(d_rank, 0);
74  }
75 #if 0
76  // This might be a good idea, but I didn't need it. The three D case is probably
77  // more important. jhrg 5/26/15
78  Odometer(unsigned int x, unsigned int y) : d_offset(0)
79  {
80  d_rank = 2;
81  d_shape.push_back(x);
82  d_shape.push_back(y);
83 
84  // compute the highest offset value based on the array shape
85  d_highest_offset = 1;
86  for (unsigned int i = 0; i < d_rank; ++i) {
87  d_highest_offset *= d_shape.at(i);
88  }
89 
90  d_indices.resize(d_rank, 0);
91  }
92 #endif
93  /*
94  * reset(): zero internal state
95  * next(): move to the next element, incrementing the shape information and returning an offset into a linear vector for that element.
96  * 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.
97  * vector<int> indices(): for the given state of the odometer, return the indices that match the offset.
98  * offset(): return the offset
99  * end(): should return one past the last valid offset - the value returned by next() when it indicates all elements/indices have been visited.
100  *
101  */
102 
107  void reset()
108  {
109  for (unsigned int i = 0; i < d_rank; ++i)
110  d_indices.at(i) = 0;
111  d_offset = 0;
112  }
113 
125  inline unsigned int next()
126  {
127  // About 2.4 seconds for 10^9 elements
128  shape::reverse_iterator si = d_shape.rbegin();
129  for (shape::reverse_iterator i = d_indices.rbegin(), e = d_indices.rend(); i != e; ++i, ++si) {
130  if (++(*i) == *si) {
131  *i = 0;
132  }
133  else {
134  break;
135  }
136  }
137 
138  return ++d_offset;
139  }
140 
141  // This version throws Error if offset() == end()
142  unsigned int next_safe();
143 
151  inline unsigned int set_indices(const shape &indices)
152  {
153  d_indices = indices;
154 #if 0
155  d_offset = 0;
156  unsigned int chunk_size = 1;
157 #endif
158  // I copied this algorithm from Nathan's code in NDimenensionalArray in the
159  // ugrid function module. jhrg 5/22/15
160 #if 0
161  shape::reverse_iterator si = d_shape.rbegin();
162  for (shape::reverse_iterator i = d_indices.rbegin(), e = d_indices.rend(); i != e; ++i, ++si) {
163  // The initial multiply is always 1 * N in both cases
164  d_offset += chunk_size * *i;
165  chunk_size *= *si;
166  }
167 #endif
168  shape::reverse_iterator shape_index = d_shape.rbegin();
169  shape::reverse_iterator index = d_indices.rbegin(), index_end = d_indices.rend();
170  d_offset = *index++;
171  unsigned int chunk_size = *shape_index++;
172  while (index != index_end) {
173  d_offset += chunk_size * *index++;
174  chunk_size *= *shape_index++;
175  }
176 
177  return d_offset;
178  }
179 
180  unsigned int set_indices(const std::vector<int> &indices)
181  {
182  shape temp;
183  std::copy(indices.begin(), indices.end(), std::back_inserter(temp));
184 
185  return set_indices(temp);
186  }
187 
194  inline void indices(shape &indices)
195  {
196  indices = d_indices;
197  }
198 
202  inline unsigned int offset()
203  {
204  return d_offset;
205  }
206 
214  inline unsigned int end()
215  {
216  return d_highest_offset;
217  }
218 
219 };
220 
221 } // namespace libdap
222 
223 #endif /* ODOMETER_H_ */
unsigned int end()
Definition: Odometer.h:214
Odometer(shape shape)
Definition: Odometer.h:63
unsigned int set_indices(const shape &indices)
Definition: Odometer.h:151
unsigned int next()
Definition: Odometer.h:125
unsigned int offset()
Definition: Odometer.h:202
void indices(shape &indices)
Definition: Odometer.h:194