bes  Updated for version 3.20.6
NCMLArray.h
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 #ifndef __NCML_MODULE__NCMLARRAY_H__
30 #define __NCML_MODULE__NCMLARRAY_H__
31 
32 #include <dods-datatypes.h>
33 #include <Array.h>
34 #include <BaseType.h>
35 #include <Vector.h>
36 #include <memory>
37 // #include "MyBaseTypeFactory.h"
38 #include "NCMLBaseArray.h"
39 #include "NCMLDebug.h"
40 #include "Shape.h"
41 #include <sstream>
42 #include <string>
43 #include <typeinfo>
44 #include <vector>
45 
46 using libdap::Array;
47 using libdap::dods_byte;
48 using libdap::dods_int16;
49 using libdap::dods_uint16;
50 using libdap::dods_int32;
51 using libdap::dods_uint32;
52 using libdap::dods_float32;
53 using libdap::dods_float64;
54 
55 namespace ncml_module {
56 class Shape;
57 
85 template<typename T>
86 class NCMLArray: public NCMLBaseArray {
87 public:
88  // Class methods
89 
90 public:
91  // Instance methods
92  NCMLArray() :
93  NCMLBaseArray(""), _allValues(0)
94  {
95  }
96 
97  explicit NCMLArray(const string& name) :
98  NCMLBaseArray(name), _allValues(0)
99  {
100  }
101 
102  explicit NCMLArray(const NCMLArray<T>& proto) :
103  NCMLBaseArray(proto), _allValues(0)
104  {
105  copyLocalRepFrom(proto);
106  }
107 
109  virtual ~NCMLArray()
110  {
111  destroy(); // helper
112  }
113 
114  NCMLArray<T>&
115  operator=(const NCMLArray<T>& rhs)
116  {
117  if (&rhs == this) {
118  return *this;
119  }
120 
121  // Call the super assignment
122  NCMLBaseArray::operator=(rhs);
123 
124  // Copy local private rep
125  copyLocalRepFrom(rhs);
126 
127  return *this;
128  }
129 
132  {
133  return new NCMLArray(*this);
134  }
135 
143  virtual void copyDataFrom(libdap::Array& from)
144  {
145  // We both better have a valid template class.
146  VALID_PTR(from.var());
147 
148  // clear out any current local values
149  destroy();
150 
151  // OK, now that we have it, we need to copy the attribute table and the prototype variable
152  set_attr_table(from.get_attr_table());
153  // switched to add_var_ncopy() to avoid memory leak. jhrg 8/3/18
154  add_var_nocopy(from.var()->ptr_duplicate()); // This may leak memory. Fixed.
155 
156  // add all the dimensions
157  Array::Dim_iter endIt = from.dim_end();
158  Array::Dim_iter it;
159  for (it = from.dim_begin(); it != endIt; ++it) {
160  Array::dimension& dim = *it;
161  append_dim(dim.size, dim.name);
162  }
163 
164  // Finally, copy the data.
165  // Initialize with length() values so the storage and size of _allValues is correct.
166  _allValues = new std::vector<T>(from.length());
167  NCML_ASSERT(_allValues->size() == static_cast<unsigned int>(from.length()));
168 
169  // Copy the values in from._buf into our cache!
170  T* pFirst = &((*_allValues)[0]);
171  from.buf2val(reinterpret_cast<void**>(&pFirst));
172  }
173 
174  virtual bool isDataCached() const
175  {
176  return _allValues;
177  }
178 
180  // We have to override these to make a copy in this subclass as well since constraints added before read().
181  // TODO Consider instead allowing add_constraint() in Array to be virtual so we can catch it and cache at that point rather than
182  // all the time!!
183 
184  // Helper macros to avoid a bunch of cut & paste
185 
186 #define NCMLARRAY_CHECK_ARRAY_TYPE_THEN_CALL_SUPER(arrayValue, sz) \
187  if (typeid(arrayValue) != typeid(T*)) \
188  { \
189  THROW_NCML_INTERNAL_ERROR("NCMLArray<T>::set_value(): got wrong type of value array, doesn't match type T!"); \
190  } \
191  bool ret = Vector::set_value((arrayValue), (sz)); \
192  cacheSuperclassStateIfNeeded(); \
193  return ret;
194 
195 #define NCMLARRAY_CHECK_VECTOR_TYPE_THEN_CALL_SUPER(vecValue, sz) \
196  if (typeid(vecValue) != typeid(vector<T>&)) \
197  { \
198  THROW_NCML_INTERNAL_ERROR("NCMLArray<T>::setValue(): got wrong type of value vector, doesn't match type T!"); \
199  } \
200  bool ret = Vector::set_value((vecValue), (sz)); \
201  cacheSuperclassStateIfNeeded(); \
202  return ret;
203 
204  virtual bool set_value(dods_byte *val, int sz)
205  {
206  NCMLARRAY_CHECK_ARRAY_TYPE_THEN_CALL_SUPER(val, sz);
207  }
208 
209  virtual bool set_value(vector<dods_byte> &val, int sz)
210  {
211  NCMLARRAY_CHECK_VECTOR_TYPE_THEN_CALL_SUPER(val, sz);
212  }
213 
214  virtual bool set_value(dods_int16 *val, int sz)
215  {
216  NCMLARRAY_CHECK_ARRAY_TYPE_THEN_CALL_SUPER(val, sz);
217  }
218 
219  virtual bool set_value(vector<dods_int16> &val, int sz)
220  {
221  NCMLARRAY_CHECK_VECTOR_TYPE_THEN_CALL_SUPER(val, sz);
222  }
223 
224  virtual bool set_value(dods_uint16 *val, int sz)
225  {
226  NCMLARRAY_CHECK_ARRAY_TYPE_THEN_CALL_SUPER(val, sz);
227  }
228 
229  virtual bool set_value(vector<dods_uint16> &val, int sz)
230  {
231  NCMLARRAY_CHECK_VECTOR_TYPE_THEN_CALL_SUPER(val, sz);
232  }
233 
234  virtual bool set_value(dods_int32 *val, int sz)
235  {
236  NCMLARRAY_CHECK_ARRAY_TYPE_THEN_CALL_SUPER(val, sz);
237  }
238 
239  virtual bool set_value(vector<dods_int32> &val, int sz)
240  {
241  NCMLARRAY_CHECK_VECTOR_TYPE_THEN_CALL_SUPER(val, sz);
242  }
243 
244  virtual bool set_value(dods_uint32 *val, int sz)
245  {
246  NCMLARRAY_CHECK_ARRAY_TYPE_THEN_CALL_SUPER(val, sz);
247  }
248 
249  virtual bool set_value(vector<dods_uint32> &val, int sz)
250  {
251  NCMLARRAY_CHECK_VECTOR_TYPE_THEN_CALL_SUPER(val, sz);
252  }
253 
254  virtual bool set_value(dods_float32 *val, int sz)
255  {
256  NCMLARRAY_CHECK_ARRAY_TYPE_THEN_CALL_SUPER(val, sz);
257  }
258 
259  virtual bool set_value(vector<dods_float32> &val, int sz)
260  {
261  NCMLARRAY_CHECK_VECTOR_TYPE_THEN_CALL_SUPER(val, sz);
262  }
263 
264  virtual bool set_value(dods_float64 *val, int sz)
265  {
266  NCMLARRAY_CHECK_ARRAY_TYPE_THEN_CALL_SUPER(val, sz);
267  }
268 
269  virtual bool set_value(vector<dods_float64> &val, int sz)
270  {
271  NCMLARRAY_CHECK_VECTOR_TYPE_THEN_CALL_SUPER(val, sz);
272  }
273 
274  virtual bool set_value(string *val, int sz)
275  {
276  NCMLARRAY_CHECK_ARRAY_TYPE_THEN_CALL_SUPER(val, sz);
277  }
278 
279  virtual bool set_value(vector<string> &val, int sz)
280  {
281  NCMLARRAY_CHECK_VECTOR_TYPE_THEN_CALL_SUPER(val, sz);
282  }
283 
284 #undef NCMLARRAY_CHECK_ARRAY_TYPE_THEN_CALL_SUPER
285 #undef NCMLARRAY_CHECK_VECTOR_TYPE_THEN_CALL_SUPER
286 
287 protected:
288 
298  virtual void cacheValuesIfNeeded()
299  {
300  // If the super Vector has no capacity, it's not set up correctly, so don't call this or we get exception.
301  if (get_value_capacity() == 0) {
302  BESDEBUG("ncml", "cacheValuesIfNeeded: the superclass Vector has no data so not copying...");
303  }
304 
305  // If we haven't gotten this yet, go get it,
306  // assuming the super Vector contains all values
307  if (!_allValues) {
308  BESDEBUG("ncml",
309  "NCMLArray<T>:: we don't have unconstrained values cached, caching from Vector now..." << endl);
310  unsigned int spaceSize = _noConstraints->getUnconstrainedSpaceSize();
311 
312 #if 0
313  ostringstream oss;
314  oss <<"NCMLArray expected superclass Vector length() to be the same as unconstrained space size, but it wasn't!";
315  oss << "length(): " << length() << "' spaceSize: " << spaceSize;
316  NCML_ASSERT_MSG(static_cast<unsigned int>(length()) == spaceSize, oss.str());
317 #else
318  NCML_ASSERT_MSG(static_cast<unsigned int>(length()) == spaceSize,
319  "NCMLArray expected superclass Vector length() to be the same as unconstrained space size, but it wasn't!");
320 #endif
321  // Make new default storage with enough space for all the data.
322  _allValues = new vector<T>(spaceSize);
323  NCML_ASSERT(_allValues->size() == spaceSize); // the values should all be default for T().
324  // Grab the address of the start of the vector memory block.
325  // This is safe since vector memory is required to be contiguous
326  T* pFirstElt = &((*_allValues)[0]);
327  // Now overwrite the defaults in from the buffer.
328  unsigned int stored = buf2val(reinterpret_cast<void**>(&pFirstElt));
329 
330  NCML_ASSERT((stored / sizeof(T)) == spaceSize); // make sure it did what it was supposed to do.
331  // OK, we have our copy now!
332  }
333 
334  // We ignore the current constraints since we don't worry about them until later in read().
335  }
336 
346  {
347  BESDEBUG("ncml", "NCMLArray<T>::createAndSetConstrainedValueBuffer() called!" << endl);
348 
349  // Whether to validate, depending on debug build or not.
350 #ifdef NDEBUG
351  const bool validateBounds = false;
352 #else
353  const bool validateBounds = true;
354 #endif
355 
356  // These need to exist or caller goofed.
357  VALID_PTR(_noConstraints);
358  VALID_PTR(_allValues);
359 
360  // This reflects the current constraints, so is what we want.
361  unsigned int numVals = length();
362  vector<T> values; // Exceptions may wind through and I want this storage cleaned, so vector<T> rather than T*.
363  values.reserve(numVals);
364 
365  // Our current space, with constraints
366  const Shape shape = getSuperShape();
369  unsigned int count = 0; // just a counter for number of points for sanity checking
370  for (it = shape.beginSpaceEnumeration(); it != endIt; ++it, ++count) {
371  // Take the current point in constrained space, look it up in cached 3values, set it as next elt in output
372  values.push_back((*_allValues)[_noConstraints->getRowMajorIndex(*it, validateBounds)]);
373  }
374 
375  // Sanity check the number of points we added. They need to match or something is wrong.
376  if (count != static_cast<unsigned int>(length())) {
377  stringstream msg;
378  msg << "While adding points to hyperslab buffer we got differing number of points "
379  "from Shape space enumeration as expected from the constraints! "
380  "Shape::IndexIterator produced " << count << " points but we expected " << length();
381  THROW_NCML_INTERNAL_ERROR(msg.str());
382  }
383 
384  if (count != shape.getConstrainedSpaceSize()) {
385  stringstream msg;
386  msg << "While adding points to hyperslab buffer we got differing number of points "
387  "from Shape space enumeration as expected from the shape.getConstrainedSpaceSize()! "
388  "Shape::IndexIterator produced " << count << " points but we expected "
389  << shape.getConstrainedSpaceSize();
390  THROW_NCML_INTERNAL_ERROR(msg.str());
391  }
392 
393  // Otherwise, we're good, so blast the values into the valuebuffer.
394  // tell it to reuse the current buffer since by definition is has enough room since it holds all points to start.
395  val2buf(static_cast<void*>(&(values[0])), true);
396  }
397 
398 private:
399  // This class ONLY methods
400 
403  void copyLocalRepFrom(const NCMLArray<T>& proto)
404  {
405  // Avoid unnecessary finagling
406  if (&proto == this) {
407  return;
408  }
409 
410  // Blow away any old data before copying new
411  destroy();
412 
413  // If there are values, make a copy of the vector.
414  if (proto._allValues) {
415  _allValues = new vector<T>(*(proto._allValues));
416  }
417  }
418 
420  void destroy() throw ()
421  {
422  delete _allValues;
423  _allValues = 0;
424  }
425 
426 private:
427 
428  // The unconstrained data set, cached from super in first call to cacheSuperclassStateIfNeeded()
429  // if it is null.
430  std::vector<T>* _allValues;
431 
432 };
433 // class NCMLArray<T>
434 
435 }// namespace ncml_module
436 
437 #endif /* __NCML_MODULE__NCMLARRAY_H__ */
ncml_module::Shape::getConstrainedSpaceSize
unsigned int getConstrainedSpaceSize() const
Definition: Shape.h:169
ncml_module::NCMLBaseArray::getSuperShape
virtual Shape getSuperShape() const
Definition: NCMLBaseArray.cc:152
ncml_module::NCMLArray::ptr_duplicate
virtual NCMLArray< T > * ptr_duplicate()
Definition: NCMLArray.h:131
ncml_module::Shape
A wrapper class for a vector of Array::dimension structs.
Definition: Shape.h:58
ncml_module::NCMLArray::cacheValuesIfNeeded
virtual void cacheValuesIfNeeded()
Definition: NCMLArray.h:298
ncml_module::NCMLArray::~NCMLArray
virtual ~NCMLArray()
Definition: NCMLArray.h:109
ncml_module::NCMLArray::copyDataFrom
virtual void copyDataFrom(libdap::Array &from)
Definition: NCMLArray.h:143
ncml_module::Shape::IndexIterator
Definition: Shape.h:71
ncml_module::Shape::endSpaceEnumeration
Shape::IndexIterator endSpaceEnumeration() const
Definition: Shape.cc:161
ncml_module::Shape::getUnconstrainedSpaceSize
unsigned int getUnconstrainedSpaceSize() const
Definition: Shape.h:159
ncml_module
NcML Parser for adding/modifying/removing metadata (attributes) to existing local datasets using NcML...
Definition: AggregationElement.cc:72
ncml_module::NCMLArray::createAndSetConstrainedValueBuffer
virtual void createAndSetConstrainedValueBuffer()
Definition: NCMLArray.h:345
ncml_module::NCMLBaseArray
Definition: NCMLBaseArray.h:43
ncml_module::Shape::beginSpaceEnumeration
Shape::IndexIterator beginSpaceEnumeration() const
Definition: Shape.cc:156
ncml_module::NCMLArray
A parameterized subclass of libdap::Array that allows us to apply constraints on NcML-specified data ...
Definition: NCMLArray.h:86
ncml_module::Shape::getRowMajorIndex
unsigned int getRowMajorIndex(const IndexTuple &indices, bool validate=true) const
Definition: Shape.cc:141
ncml_module::NCMLArray::isDataCached
virtual bool isDataCached() const
Definition: NCMLArray.h:174