bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
Shape.cc
1
2// 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
34namespace ncml_module {
35typedef vector<Array::dimension>::const_iterator DimItC;
36
39 _dims()
40{
41}
42
43Shape::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
54Shape::Shape(const Shape& proto)
55{
56 _dims = proto._dims;
57}
58
59Shape::~Shape()
60{
61 _dims.resize(0);
62}
63
64Shape&
65Shape::operator=(const Shape& rhs)
66{
67 if (&rhs == this) {
68 return *this;
69 }
70
71 _dims = rhs._dims;
72 return *this;
73}
74
75bool 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
120bool 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
141unsigned 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
166std::string Shape::toString() const
167{
168 std::stringstream sos;
169 print(sos);
170 return sos.str();
171}
172
173void 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
183void 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
194bool 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
218Shape::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
230Shape::IndexIterator::~IndexIterator()
231{
232 _shape = 0;
233 _current.resize(0);
234 _end = true;
235}
236
237Shape::IndexIterator&
238Shape::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
250bool 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
285void 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
315void 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
A wrapper class for a vector of Array::dimension structs.
Definition Shape.h:58
Shape::IndexIterator endSpaceEnumeration() const
Definition Shape.cc:161
void setToUnconstrained()
Definition Shape.cc:109
std::string toString() const
Definition Shape.cc:166
static bool areDimensionsEqual(const Array::dimension &lhs, const Array::dimension &rhs)
Definition Shape.cc:120
bool validateIndices(const IndexTuple &indices) const
Definition Shape.cc:194
bool isConstrained() const
Definition Shape.cc:96
unsigned int getRowMajorIndex(const IndexTuple &indices, bool validate=true) const
Definition Shape.cc:141
Shape::IndexIterator beginSpaceEnumeration() const
Definition Shape.cc:156
bool operator==(const Shape &rhs) const
Definition Shape.cc:75
static void printDimension(std::ostream &strm, const Array::dimension &dim)
Definition Shape.cc:183
void print(std::ostream &strm) const
Definition Shape.cc:173
NcML Parser for adding/modifying/removing metadata (attributes) to existing local datasets using NcML...