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