bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
NCMLArray.h
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#ifndef __NCML_MODULE__NCMLARRAY_H__
30#define __NCML_MODULE__NCMLARRAY_H__
31
32#include <libdap/dods-datatypes.h>
33#include <libdap/Array.h>
34#include <libdap/BaseType.h>
35#include <libdap/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
46using libdap::Array;
47using libdap::dods_byte;
48using libdap::dods_int16;
49using libdap::dods_uint16;
50using libdap::dods_int32;
51using libdap::dods_uint32;
52using libdap::dods_float32;
53using libdap::dods_float64;
54
55namespace ncml_module {
56class Shape;
57
85template<typename T>
86class NCMLArray: public NCMLBaseArray {
87public:
88 // Class methods
89
90public:
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
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
131 virtual NCMLArray<T>* ptr_duplicate()
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 size() 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
287protected:
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 size() to be the same as unconstrained space size, but it wasn't!";
315 oss << "size(): " << size() << "' 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();
367 Shape::IndexIterator endIt = shape.endSpaceEnumeration();
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
398private:
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() noexcept
421 {
422 delete _allValues;
423 _allValues = 0;
424 }
425
426private:
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__ */
A parameterized subclass of libdap::Array that allows us to apply constraints on NcML-specified data ...
Definition NCMLArray.h:86
virtual void createAndSetConstrainedValueBuffer()
Definition NCMLArray.h:345
virtual void cacheValuesIfNeeded()
Definition NCMLArray.h:298
virtual void copyDataFrom(libdap::Array &from)
Definition NCMLArray.h:143
virtual bool isDataCached() const
Definition NCMLArray.h:174
virtual NCMLArray< T > * ptr_duplicate()
Definition NCMLArray.h:131
virtual Shape getSuperShape() const
A wrapper class for a vector of Array::dimension structs.
Definition Shape.h:58
STL class.
STL class.
STL class.
NcML Parser for adding/modifying/removing metadata (attributes) to existing local datasets using NcML...