bes  Updated for version 3.20.6
Shape.cc
1 // This file is part of the "NcML Module" project, a BES module designed
3 // to allow NcML files to be used to be used as a wrapper to add
4 // AIS to existing datasets of any format.
5 //
6 // Copyright (c) 2009 OPeNDAP, Inc.
7 // Author: Michael Johnson <m.johnson@opendap.org>
8 //
9 // For more information, please also see the main website: http://opendap.org/
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // Please see the files COPYING and COPYRIGHT for more information on the GLPL.
26 //
27 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
29 
30 #include "Shape.h"
31 #include "NCMLDebug.h"
32 #include <sstream> // for std::stringstream
33 
34 namespace ncml_module {
35 typedef vector<Array::dimension>::const_iterator DimItC;
36 
39  _dims()
40 {
41 }
42 
43 Shape::Shape(const Array& copyDimsFrom)
44 {
45  Array& from = const_cast<Array&>(copyDimsFrom);
46  Array::Dim_iter endIt = from.dim_end();
47  Array::Dim_iter it;
48  for (it = from.dim_begin(); it != endIt; ++it) {
49  const Array::dimension& dim = (*it);
50  _dims.push_back(dim);
51  }
52 }
53 
54 Shape::Shape(const Shape& proto)
55 {
56  _dims = proto._dims;
57 }
58 
59 Shape::~Shape()
60 {
61  _dims.resize(0);
62 }
63 
64 Shape&
65 Shape::operator=(const Shape& rhs)
66 {
67  if (&rhs == this) {
68  return *this;
69  }
70 
71  _dims = rhs._dims;
72  return *this;
73 }
74 
75 bool Shape::operator==(const Shape& rhs) const
76 {
77  bool ret = true;
78 
79  // Simple dimensionality check must pass first
80  if (rhs._dims.size() != _dims.size()) {
81  ret = false;
82  }
83  else // then compare all the dimensions
84  {
85  for (unsigned int i = 0; i < _dims.size(); ++i) {
86  ret = areDimensionsEqual(_dims[i], rhs._dims[i]);
87  if (!ret) // just give up...
88  {
89  break;
90  }
91  }
92  }
93  return ret;
94 }
95 
97 {
98  bool ret = false;
99  for (unsigned int i = 0; i < _dims.size(); ++i) {
100  const Array::dimension& dim = _dims[i];
101  ret |= (dim.c_size != dim.size);
102  if (ret) {
103  break;
104  }
105  }
106  return ret;
107 }
108 
110 {
111  for (unsigned int i = 0; i < _dims.size(); ++i) {
112  Array::dimension& dim = _dims[i];
113  dim.c_size = dim.size;
114  dim.start = 0;
115  dim.stop = dim.size - 1;
116  dim.stride = 1;
117  }
118 }
119 
120 bool Shape::areDimensionsEqual(const Array::dimension& lhs, const Array::dimension& rhs)
121 {
122  // Stolen from Array::dimension....
123  /*
124  int size; ///< The unconstrained dimension size.
125  string name; ///< The name of this dimension.
126  int start; ///< The constraint start index
127  int stop; ///< The constraint end index
128  int stride; ///< The constraint stride
129  int c_size; ///< Size of dimension once constrained
130  */
131  // Must all match
132  bool equal = true;
133  equal &= (lhs.size == rhs.size);
134  equal &= (lhs.name == rhs.name);
135  equal &= (lhs.start == rhs.start);
136  equal &= (lhs.stride == rhs.stride);
137  equal &= (lhs.c_size == rhs.c_size);
138  return equal;
139 }
140 
141 unsigned int Shape::getRowMajorIndex(const IndexTuple& indices, bool validate /* = true */) const
142 {
143  if (validate && !validateIndices(indices)) {
144  THROW_NCML_INTERNAL_ERROR(
145  "Shape::getRowMajorIndex got indices that were out of range for the given space dimensions!");
146  }
147 
148  NCML_ASSERT(indices.size() >= 1);
149  unsigned int index = indices[0];
150  for (unsigned int i = 1; i < indices.size(); ++i) {
151  index = indices[i] + (_dims[i].size * index);
152  }
153  return index;
154 }
155 
157 {
158  return IndexIterator(*this, false);
159 }
160 
162 {
163  return IndexIterator(*this, true);
164 }
165 
166 std::string Shape::toString() const
167 {
168  std::stringstream sos;
169  print(sos);
170  return sos.str();
171 }
172 
173 void Shape::print(std::ostream& strm) const
174 {
175  strm << "Shape = { ";
176  for (unsigned int i = 0; i < _dims.size(); ++i) {
177  const Array::dimension& dim = _dims[i];
178  printDimension(strm, dim);
179  }
180  strm << " }\n";
181 }
182 
183 void Shape::printDimension(std::ostream& strm, const Array::dimension& dim)
184 {
185  strm << "\tDim = { \n";
186  strm << "\t\tname=" << dim.name << "\n";
187  strm << "\t\tsize=" << dim.size << "\n";
188  strm << "\t\tc_size=" << dim.c_size << "\n";
189  strm << "\t\tstart=" << dim.start << "\n";
190  strm << "\t\tstop=" << dim.stop << "\n";
191  strm << "\t\tstride=" << dim.stride << "\n";
192 }
193 
194 bool Shape::validateIndices(const IndexTuple& indices) const
195 {
196  if (indices.size() != _dims.size()) {
197  return false;
198  }
199 
200  for (unsigned int i = 0; i < _dims.size(); ++i) {
201  // Must be > 0 and <= size-1
202  if (indices[i] >= static_cast<unsigned int>(_dims[i].size)) {
203  return false;
204  }
205  }
206 
207  return true;
208 }
209 
212 
214  _shape(0), _current(), _end(true)
215 {
216 }
217 
218 Shape::IndexIterator::IndexIterator(const Shape& shape, bool isEnd/*=false*/) :
219  _shape(&shape), _current(shape.getNumDimensions()) // start with default of proper size, we'll fix it later.
220  , _end(isEnd)
221 {
222  setCurrentToStart();
223 }
224 
226  _shape(proto._shape), _current(proto._current), _end(proto._end)
227 {
228 }
229 
230 Shape::IndexIterator::~IndexIterator()
231 {
232  _shape = 0;
233  _current.resize(0);
234  _end = true;
235 }
236 
237 Shape::IndexIterator&
238 Shape::IndexIterator::operator=(const Shape::IndexIterator& rhs)
239 {
240  if (this == &rhs) {
241  return *this;
242  }
243 
244  _shape = rhs._shape;
245  _current = rhs._current;
246  _end = rhs._end;
247  return *this;
248 }
249 
250 bool Shape::IndexIterator::operator==(const Shape::IndexIterator& rhs) const
251 {
252  // The ptr's must be the same... It has to come from the same Shape object.
253  // We could use Shape::operator== but this is too slow for every increment.
254  if (_shape != rhs._shape) {
255  return false;
256  }
257 
258  // If one has end set, the other needs to as well to be equal
259  if (_end != rhs._end) {
260  return false;
261  }
262 
263  // Finally, make sure the arrays have the same values.
264  return (_current == rhs._current);
265 }
266 
285 void Shape::IndexIterator::advanceCurrent()
286 {
287  // We're done already, let the caller know they goofed. This works for uninitialize with null _shape as well.
288  if (_end) {
289  THROW_NCML_INTERNAL_ERROR("Shape::IndexIterator::advanceCurrent(): tried to advance beyond end()!");
290  }
291 
292  bool carry = true; // if a dimension's index wraps back to start on increment, this is set. Starts true to initiate loop.
293  unsigned int dimInd = _shape->getNumDimensions();
294  while (carry && dimInd-- > 0) // first pass will decrement this so it starts at N-1m as we desire.
295  {
296  const Array::dimension& dim = _shape->_dims[dimInd];
297  // grab the reference so we mutate the elt itself
298  unsigned int& currentDimIndex = _current[dimInd];
299  currentDimIndex += dim.stride;
300  carry = false; // assume no carry to start
301  // if we wrap, then set the carry bit to propagate the increment to the dimension to our left in the tuple
302  if (currentDimIndex > static_cast<unsigned int>(dim.stop)) {
303  currentDimIndex = dim.start;
304  carry = true;
305  }
306  }
307 
308  // If we end the loop with carry still set, we've wrapped the slowest varying dimension
309  // and we're back to the starting group element. Set _end!
310  if (carry) {
311  _end = true;
312  }
313 }
314 
315 void Shape::IndexIterator::setCurrentToStart()
316 {
317  VALID_PTR(_shape);
318  for (unsigned int i = 0; i < _shape->getNumDimensions(); ++i) {
319  _current[i] = _shape->_dims[i].start;
320  }
321 }
322 
323 } // namespace ncml_module
ncml_module::Shape::isConstrained
bool isConstrained() const
Definition: Shape.cc:96
ncml_module::Shape::Shape
Shape()
Definition: Shape.cc:38
ncml_module::Shape::operator==
bool operator==(const Shape &rhs) const
Definition: Shape.cc:75
ncml_module::Shape
A wrapper class for a vector of Array::dimension structs.
Definition: Shape.h:58
ncml_module::Shape::print
void print(std::ostream &strm) const
Definition: Shape.cc:173
ncml_module::Shape::validateIndices
bool validateIndices(const IndexTuple &indices) const
Definition: Shape.cc:194
ncml_module::Shape::IndexIterator
Definition: Shape.h:71
ncml_module::Shape::endSpaceEnumeration
Shape::IndexIterator endSpaceEnumeration() const
Definition: Shape.cc:161
ncml_module::Shape::setToUnconstrained
void setToUnconstrained()
Definition: Shape.cc:109
ncml_module::Shape::printDimension
static void printDimension(std::ostream &strm, const Array::dimension &dim)
Definition: Shape.cc:183
ncml_module::Shape::areDimensionsEqual
static bool areDimensionsEqual(const Array::dimension &lhs, const Array::dimension &rhs)
Definition: Shape.cc:120
ncml_module
NcML Parser for adding/modifying/removing metadata (attributes) to existing local datasets using NcML...
Definition: AggregationElement.cc:72
ncml_module::Shape::beginSpaceEnumeration
Shape::IndexIterator beginSpaceEnumeration() const
Definition: Shape.cc:156
ncml_module::Shape::toString
std::string toString() const
Definition: Shape.cc:166
ncml_module::Shape::getRowMajorIndex
unsigned int getRowMajorIndex(const IndexTuple &indices, bool validate=true) const
Definition: Shape.cc:141
ncml_module::Shape::IndexIterator::IndexIterator
IndexIterator()
Definition: Shape.cc:213