libdap Updated for version 3.20.11
libdap4 is an implementation of OPeNDAP's DAP protocol.
Array.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of libdap, A C++ implementation of the OPeNDAP Data
4// Access Protocol.
5
6// Copyright (c) 2002,2003 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25// (c) COPYRIGHT URI/MIT 1994-1999
26// Please read the full copyright statement in the file COPYRIGHT_URI.
27//
28// Authors:
29// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
30
31// Implementation for Array.
32//
33// jhrg 9/13/94
34
35#include "config.h"
36
37//#define DODS_DEBUG
38
39#include <algorithm>
40#include <functional>
41#include <sstream>
42
43#include "Array.h"
44#include "Grid.h"
45
46#include "D4Attributes.h"
47#include "DMR.h"
48#include "D4Dimensions.h"
49#include "D4Maps.h"
50#include "D4Group.h"
51#include "D4EnumDefs.h"
52#include "D4Enum.h"
53#include "XMLWriter.h"
54
55#include "util.h"
56#include "debug.h"
57#include "InternalErr.h"
58#include "escaping.h"
59#include "DapIndent.h"
60
61using namespace std;
62
63namespace libdap {
64
65Array::dimension::dimension(D4Dimension *d) :
66 dim(d), use_sdim_for_slice(true)
67{
68 size = d->size();
69 name = d->name();
70
71 start = 0;
72 stop = size - 1;
73 stride = 1;
74 c_size = size;
75}
76
77void Array::_duplicate(const Array &a)
78{
79 _shape = a._shape;
80
81 // Deep copy the Maps if they are being used.
82 if (a.d_maps) {
83 d_maps = new D4Maps(*(a.d_maps));
84 }
85 else {
86 d_maps = 0;
87 }
88}
89
90// The first method of calculating length works when only one dimension is
91// constrained and you want the others to appear in total. This is important
92// when selecting from grids since users may not select from all dimensions
93// in which case that means they want the whole thing. Array projection
94// should probably work this way too, but it doesn't. 9/21/2001 jhrg
95
102void Array::update_length(int)
103{
104 int length = 1;
105 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
106 length *= (*i).c_size;
107 }
108
109 set_length(length);
110}
111
112// Construct an instance of Array. The (BaseType *) is assumed to be
113// allocated using new - The dtor for Vector will delete this object.
114
130Array::Array(const string &n, BaseType *v, bool is_dap4 /* default:false */) :
131 Vector(n, 0, dods_array_c, is_dap4), d_maps(0)
132{
133 add_var(v); // Vector::add_var() stores null if v is null
134}
135
149Array::Array(const string &n, const string &d, BaseType *v, bool is_dap4 /* default:false */) :
150 Vector(n, d, 0, dods_array_c, is_dap4), d_maps(0)
151{
152 add_var(v); // Vector::add_var() stores null if v is null
153}
154
156Array::Array(const Array &rhs) :
157 Vector(rhs)
158{
159 _duplicate(rhs);
160}
161
164{
165 delete d_maps;
166}
167
168BaseType *
170{
171 return new Array(*this);
172}
173
174Array &
175Array::operator=(const Array &rhs)
176{
177 if (this == &rhs) return *this;
178 Vector::operator=(rhs);
179 _duplicate(rhs);
180 return *this;
181}
182
184{
185 Array *dest = static_cast<Array*>(ptr_duplicate());
186
187 // If it's already a DAP4 object then we can just return it!
188 if (is_dap4()) {
189 container->add_var_nocopy(dest);
190 }
191
192 // Process the Array's dimensions, making D4 shared dimensions for
193 // D2 dimensions that are named. If there is just a size, don't make
194 // a D4Dimension (In DAP4 you cannot share a dimension unless it has
195 // a name). jhrg 3/18/14
196
197 D4Dimensions *root_dims = root->dims();
198 for (Array::Dim_iter dap2_dim = dest->dim_begin(), e = dest->dim_end(); dap2_dim != e; ++dap2_dim) {
199 if (!(*dap2_dim).name.empty()) {
200
201 // If a D4Dimension with the name already exists, use it.
202 D4Dimension *d4_dim = root_dims->find_dim((*dap2_dim).name);
203 if (!d4_dim) {
204 d4_dim = new D4Dimension((*dap2_dim).name, (*dap2_dim).size);
205 root_dims->add_dim_nocopy(d4_dim);
206 }
207 else {
208 DBG(cerr << __func__ << "() -" <<
209 " Using Existing D4Dimension '"<< d4_dim->name() << "' (" <<
210 (void *)d4_dim << ")"<< endl);;
211
212 if (d4_dim->size() != (unsigned long) (*dap2_dim).size) {
213 // TODO Revisit this decision. jhrg 3/18/14
214 // ...in case the name/size are different, make a unique D4Dimension
215 // but don't fiddle with the name. Not sure I like this idea, so I'm
216 // making the case explicit (could be rolled in to the block above).
217 // jhrg 3/18/14
218 //
219 // This is causing problems in the FITS handler because there are cases
220 // where two arrays have dimensions with the same name but different
221 // sizes. The deserializing code is using the first size listed, which is
222 // wrong in some cases. I'm going to try making this new D4Dimension using
223 // the dim name along with the variable name. jhrg 8/15/14
224 d4_dim = new D4Dimension((*dap2_dim).name + "_" + name(), (*dap2_dim).size);
225 DBG(cerr << __func__ << "() -" <<
226 " Utilizing Name/Size Conflict Naming Artifice. name'"<< d4_dim->name() << "' (" <<
227 (void *)d4_dim << ")"<< endl);;
228 root_dims->add_dim_nocopy(d4_dim);
229 }
230 }
231 // At this point d4_dim's name and size == those of (*d) so just set
232 // the D4Dimension pointer so it matches the one in the D4Group.
233 (*dap2_dim).dim = d4_dim;
234 }
235
236 }
237
238 // Copy the D2 attributes to D4 Attributes
240 dest->set_is_dap4(true);
241 container->add_var_nocopy(dest);
242 DBG(cerr << __func__ << "() - END (array:" << name() << ")" << endl);;
243}
244
245bool Array::is_dap2_grid()
246{
247 bool is_grid = false;
248 if (this->is_dap4()) {
249 DBG( cerr << __func__ << "() - Array '"<< name() << "' is DAP4 object!" << endl);
250 D4Maps *d4_maps = this->maps();
251 is_grid = d4_maps->size(); // It can't be a grid if there are no maps...
252 if (is_grid) {
253 DBG( cerr << __func__ << "() - Array '"<< name() << "' has D4Maps." << endl);
254 // hmmm this might be a DAP2 Grid...
255 D4Maps::D4MapsIter i = d4_maps->map_begin();
256 D4Maps::D4MapsIter e = d4_maps->map_end();
257 while (i != e) {
258 DBG( cerr << __func__ << "() - Map '"<< (*i)->array()->name() << " has " << (*i)->array()->_shape.size() << " dimension(s)." << endl);
259 if ((*i)->array()->_shape.size() > 1) {
260 is_grid = false;
261 i = e;
262 }
263 else {
264 i++;
265 }
266 }
267 }
268 else {
269 DBG( cerr << __func__ << "() - Array '"<< name() << "' has no D4Maps." << endl);
270 }
271 }
272
273 DBG( cerr << __func__ << "() - is_grid: "<< (is_grid?"true":"false") << endl);
274 return is_grid;
275}
276
292std::vector<BaseType *> *
294{
295 DBG(cerr << __func__ << "() - BEGIN Array '"<< name() << "'" << endl);;
296
297 BaseType *dest;
298 if (!is_dap4()) { // Don't convert a DAP2 thing
299 dest = ptr_duplicate();
300 }
301 else {
302 // At this point we have a DAP4 Array. It have D4Attributes and nothing
303 // in the DAP2 AttrTable (which is held as a reference, defined in BaseType).
304 // This test determines in the D4 Array qualifies as a D2 Grid.
305 if (is_dap2_grid()) {
306 // Oh yay! Grids are special.
307 DBG(cerr << __func__ << "() - Array '"<< name() << "' is dap2 Grid!" << endl);;
308 Grid *g = new Grid(name());
309 dest = g;
310 Array *grid_array = static_cast<Array *>(ptr_duplicate());
311 g->set_array(grid_array);
312
313 // Fix for HK-403. jhrg 6/17/19
315
316 // Process the Map Arrays.
317 D4Maps *d4_maps = this->maps();
318 vector<BaseType *> dropped_maps;
319 D4Maps::D4MapsIter miter = d4_maps->map_begin();
320 D4Maps::D4MapsIter end = d4_maps->map_end();
321 for (; miter != end; miter++) {
322 D4Map *d4_map = (*miter);
323 Array *d4_map_array = const_cast<Array*>(d4_map->array());
324 vector<BaseType *> *d2_result = d4_map_array->transform_to_dap2(&(g->get_attr_table()));
325 if (d2_result) {
326 if (d2_result->size() > 1)
327 throw Error(internal_error, "D4Map Array conversion resulted in multiple DAP2 objects.");
328
329 // TODO - This is probably slow and needs a better pattern. const_cast? static_cast?
330 Array *d2_map_array = dynamic_cast<Array *>((*d2_result)[0]);
331 if (d2_map_array) {
332 if (d2_map_array->dimensions() != 1)
333 throw Error(internal_error, "DAP2 array from D4Map Array conversion has more than 1 dimension.");
334
335 g->add_map(d2_map_array, false);
336 AttrTable at = d2_map_array->get_attr_table();
337 DBG( cerr << __func__ << "() - " <<
338 "DAS For Grid Map '" << d2_map_array->name() << "':" << endl;
339 at.print(cerr); );
340 }
341 else {
342 throw Error(internal_error, "Unable to interpret returned DAP2 content.");
343 }
344 delete d2_result;
345 }
346 else {
347 dropped_maps.push_back(d4_map_array);
348 }
349 }
350
351 // Did we have a transform failure?
352 if (!dropped_maps.empty()) {
353 // Yup... tell the story in the attributes.
354 AttrTable *dv_table = Constructor::make_dropped_vars_attr_table(&dropped_maps);
355 dest->get_attr_table().append_container(dv_table, dv_table->get_name());
356 }
357 }
358 else {
359 DBG( cerr << __func__ << "() - Array '"<< name() << "' is not a Grid!" << endl);
360
361 BaseType *proto = prototype();
362 switch (proto->type()) {
363 case dods_int64_c:
364 case dods_uint64_c:
365 case dods_enum_c:
366 case dods_opaque_c:
367 // For now we punt on these types as they have no easy representation in
368 // the DAP2 data model. By setting this to NULL we cause the Array to be
369 // dropped and this will be reflected in the metadata (DAS).
370 dest = NULL;
371 break;
372
373 default:
374 // ptr_duplicate() does the Attributes too.
375 dest = ptr_duplicate();
376
377 // Fix for HK-403. jhrg 6/17/19
378 // Only transform the DAP4 attributes to DAP2 ones if the DAP2 object lacks
379 // attributes. If the new DAP2 variable already has attributes, they were
380 // added by this process (driven by D4Group::transform_to_dap2() and calling
381 // attributes()->transform_to_dap2() will put a second copy of each attribute's
382 // value in the DAP2 AttrTable. This attribute transform code (here and elsewhere)
383 // depends on the AttrTable for a DAP4 variable initially being empty. Once it
384 // contains attributes, the code assumes they were put there by this transform
385 // process. jhrg 6/18/19
386 if (dest->get_attr_table().get_size() == 0) {
388 dest->get_attr_table().set_name(name());
389 }
390
391 dest->set_is_dap4(false);
392 break;
393 }
394 }
395 }
396
397 vector<BaseType *> *result;
398 if (dest) {
399 result = new vector<BaseType *>();
400 result->push_back(dest);
401 }
402 else {
403 result = NULL;
404 }
405
406 DBG( cerr << __func__ << "() - END Array '"<< name() << "'" << endl);;
407 return result;
408}
409
421void Array::update_dimension_pointers(D4Dimensions *old_dims, D4Dimensions *new_dims)
422{
423 std::vector<dimension>::iterator i = _shape.begin(), e = _shape.end();
424 while (i != e) {
425 D4Dimensions::D4DimensionsIter old_i = old_dims->dim_begin(), old_e = old_dims->dim_end();
426 while (old_i != old_e) {
427 if ((*i).dim == *old_i) {
428 (*i).dim = new_dims->find_dim((*old_i)->name());
429 }
430 ++old_i;
431 }
432
433 ++i;
434 }
435}
436
462{
463// If 'v' is an Array, add the template instance to this object and
464// then copy the dimension information. Odd semantics; I wonder if this
465//is ever used. jhrg 6/13/12
466 if (v && v->type() == dods_array_c) {
467 Array *a = static_cast<Array*>(v);
468 Vector::add_var(a->var());
469
470 Dim_iter i = a->dim_begin();
471 Dim_iter i_end = a->dim_end();
472 while (i != i_end) {
474 ++i;
475 }
476 }
477 else {
479 }
480}
481
482void Array::add_var_nocopy(BaseType *v, Part)
483{
484// If 'v' is an Array, add the template instance to this object and
485// then copy the dimension information. Odd semantics; I wonder if this
486//is ever used. jhrg 6/13/12
487 if (v && v->type() == dods_array_c) {
488 Array &a = dynamic_cast<Array&>(*v);
489 Vector::add_var_nocopy(a.var());
490 Dim_iter i = a.dim_begin();
491 Dim_iter i_end = a.dim_end();
492 while (i != i_end) {
494 ++i;
495 }
496 }
497 else {
498 Vector::add_var_nocopy(v);
499 }
500}
501
513void Array::append_dim(int size, const string &name)
514{
515 dimension d(size, www2id(name));
516 _shape.push_back(d);
517
519}
520
522{
523 dimension d(/*dim->size(), www2id(dim->name()),*/dim);
524 _shape.push_back(d);
525
527}
528
534void Array::prepend_dim(int size, const string& name/* = "" */)
535{
536 dimension d(size, www2id(name));
537// Shifts the whole array, but it's tiny in general
538 _shape.insert(_shape.begin(), d);
539
540 update_length(); // the number is ignored...
541}
542
544{
545 dimension d(/*dim->size(), www2id(dim->name()),*/dim);
546// Shifts the whole array, but it's tiny in general
547 _shape.insert(_shape.begin(), d);
548
549 update_length(); // the number is ignored...
550}
551
556{
557 _shape.clear();
558}
559
565void Array::rename_dim(const string &oldName, const string &newName)
566{
567 std::vector<dimension>::iterator i = _shape.begin(), e = _shape.end();
568 while (i != e) {
569 dimension &d = *i;
570 if (d.name == oldName) {
571 DBG(cerr << "Old name = " << d.name << " newName = " << newName << endl);
572 d.name = newName;
573 }
574
575 ++i;
576 }
577}
578
585{
586 set_length(-1);
587
588 for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
589 (*i).start = 0;
590 (*i).stop = (*i).size - 1;
591 (*i).stride = 1;
592 (*i).c_size = (*i).size;
593
595 }
596}
597
608{
610}
611
612// Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n
613// is explicit.
614static const char *array_sss =
615 "Invalid constraint parameters: At least one of the start, stride or stop \n\
616specified do not match the array variable.";
617
638void Array::add_constraint(Dim_iter i, int start, int stride, int stop)
639{
640 dimension &d = *i;
641
642// if stop is -1, set it to the array's max element index
643// jhrg 12/20/12
644 if (stop == -1) stop = d.size - 1;
645
646// Check for bad constraints.
647// Jose Garcia
648// Usually invalid data for a constraint is the user's mistake
649// because they build a wrong URL in the client side.
650 if (start >= d.size || stop >= d.size || stride > d.size || stride <= 0) throw Error(malformed_expr, array_sss);
651
652 if (((stop - start) / stride + 1) > d.size) throw Error(malformed_expr, array_sss);
653
654 d.start = start;
655 d.stop = stop;
656 d.stride = stride;
657
658 d.c_size = (stop - start) / stride + 1;
659
660 DBG(cerr << "add_constraint: c_size = " << d.c_size << endl);
661
663
664 d.use_sdim_for_slice = false;
665}
666
667void Array::add_constraint(Dim_iter i, D4Dimension *dim)
668{
669 dimension &d = *i;
670
671 if (dim->constrained()) add_constraint(i, dim->c_start(), dim->c_stride(), dim->c_stop());
672
673 dim->set_used_by_projected_var(true);
674
675// In this case the value below overrides the value for use_sdim_for_slice
676// set in the above call. jhrg 12/20/13
677 d.use_sdim_for_slice = true;
678}
679
682{
683 return _shape.begin();
684}
685
688{
689 return _shape.end();
690}
691
692//TODO Many of these methods take a bool parameter that serves no use; remove.
693
702unsigned int Array::dimensions(bool /*constrained*/)
703{
704 return _shape.size();
705}
706
724int Array::dimension_size(Dim_iter i, bool constrained)
725{
726 int size = 0;
727
728 if (!_shape.empty()) {
729 if (constrained)
730 size = (*i).c_size;
731 else
732 size = (*i).size;
733 }
734
735 return size;
736}
737
756int Array::dimension_start(Dim_iter i, bool /*constrained*/)
757{
758 return (!_shape.empty()) ? (*i).start : 0;
759}
760
779int Array::dimension_stop(Dim_iter i, bool /*constrained*/)
780{
781 return (!_shape.empty()) ? (*i).stop : 0;
782}
783
803int Array::dimension_stride(Dim_iter i, bool /*constrained*/)
804{
805 return (!_shape.empty()) ? (*i).stride : 0;
806}
807
819{
820// Jose Garcia
821// Since this method is public, it is possible for a user
822// to call it before the Array object has been properly set
823// this will cause an exception which is the user's fault.
824// (User in this context is the developer of the surrogate library.)
825 if (_shape.empty()) throw InternalErr(__FILE__, __LINE__, "*This* array has no dimensions.");
826 return (*i).name;
827}
828
830Array::dimension_D4dim(Dim_iter i)
831{
832 return (!_shape.empty()) ? (*i).dim : 0;
833}
834
835D4Maps *
836Array::maps()
837{
838 if (!d_maps) d_maps = new D4Maps(this); // init with this as parent
839 return d_maps;
840}
841
842#if 0
849unsigned int Array::width(bool constrained) const
850{
851
852 if (constrained) {
853 // This preserves the original method's semantics when we ask for the
854 // size of the constrained array but no constraint has been applied.
855 // In this case, length will be -1. Wrong, I know...
856 return length() * var()->width(constrained);
857 }
858 else {
859 int length = 1;
860 for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
861 length *= dimension_size(i, false);
862 }
863 return length * var()->width(false);
864 }
865}
866#endif
867
868class PrintD4ArrayDimXMLWriter: public unary_function<Array::dimension&, void> {
869 XMLWriter &xml;
870// Was this variable constrained using local/direct slicing? i.e., is d_local_constraint set?
871// If so, don't use shared dimensions; instead emit Dim elements that are anonymous.
872 bool d_constrained;
873public:
874
875 PrintD4ArrayDimXMLWriter(XMLWriter &xml, bool c) :
876 xml(xml), d_constrained(c)
877 {
878 }
879
880 void operator()(Array::dimension &d)
881 {
882 // This duplicates code in D4Dimensions (where D4Dimension::print_dap4() is defined
883 // because of the need to print the constrained size of a dimension. I think that
884 // the constraint information has to be kept here and not in the dimension (since they
885 // are shared dims). Could hack print_dap4() to take the constrained size, however.
886 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dim") < 0)
887 throw InternalErr(__FILE__, __LINE__, "Could not write Dim element");
888
889 string name = (d.dim) ? d.dim->fully_qualified_name() : d.name;
890 // If there is a name, there must be a Dimension (named dimension) in scope
891 // so write its name but not its size.
892 if (!d_constrained && !name.empty()) {
893 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name.c_str())
894 < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
895 }
896 else if (d.use_sdim_for_slice) {
897 assert(!name.empty());
898 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name.c_str())
899 < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
900 }
901 else {
902 ostringstream size;
903 size << (d_constrained ? d.c_size : d.size);
904 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size",
905 (const xmlChar*) size.str().c_str()) < 0)
906 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
907 }
908
909 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
910 throw InternalErr(__FILE__, __LINE__, "Could not end Dim element");
911 }
912};
913
914class PrintD4ConstructorVarXMLWriter: public unary_function<BaseType*, void> {
915 XMLWriter &xml;
916 bool d_constrained;
917public:
918 PrintD4ConstructorVarXMLWriter(XMLWriter &xml, bool c) :
919 xml(xml), d_constrained(c)
920 {
921 }
922
923 void operator()(BaseType *btp)
924 {
925 btp->print_dap4(xml, d_constrained);
926 }
927};
928
929class PrintD4MapXMLWriter: public unary_function<D4Map*, void> {
930 XMLWriter &xml;
931
932public:
933 PrintD4MapXMLWriter(XMLWriter &xml) :
934 xml(xml)
935 {
936 }
937
938 void operator()(D4Map *m)
939 {
940 m->print_dap4(xml);
941 }
942};
943
949void Array::print_dap4(XMLWriter &xml, bool constrained /* default: false*/)
950{
951 if (constrained && !send_p()) return;
952
953 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) var()->type_name().c_str()) < 0)
954 throw InternalErr(__FILE__, __LINE__, "Could not write " + type_name() + " element");
955
956 if (!name().empty())
957 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name().c_str()) < 0)
958 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
959
960// Hack job... Copied from D4Enum::print_xml_writer. jhrg 11/12/13
961 if (var()->type() == dods_enum_c) {
962 D4Enum *e = static_cast<D4Enum*>(var());
963 string path = e->enumeration()->name();
964 if (e->enumeration()->parent()) {
965 // print the FQN for the enum def; D4Group::FQN() includes the trailing '/'
966 path = static_cast<D4Group*>(e->enumeration()->parent()->parent())->FQN() + path;
967 }
968 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "enum", (const xmlChar*) path.c_str()) < 0)
969 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for enum");
970 }
971
972 if (prototype()->is_constructor_type()) {
973 Constructor &c = static_cast<Constructor&>(*prototype());
974 for_each(c.var_begin(), c.var_end(), PrintD4ConstructorVarXMLWriter(xml, constrained));
975 // bind2nd(mem_fun_ref(&BaseType::print_dap4), xml));
976 }
977
978// Drop the local_constraint which is per-array and use a per-dimension on instead
979 for_each(dim_begin(), dim_end(), PrintD4ArrayDimXMLWriter(xml, constrained));
980
981 attributes()->print_dap4(xml);
982
983 for_each(maps()->map_begin(), maps()->map_end(), PrintD4MapXMLWriter(xml));
984
985 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
986 throw InternalErr(__FILE__, __LINE__, "Could not end " + type_name() + " element");
987}
988
1006void Array::print_decl(FILE *out, string space, bool print_semi, bool constraint_info, bool constrained)
1007{
1008 ostringstream oss;
1009 print_decl(oss, space, print_semi, constraint_info, constrained);
1010 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1011}
1012
1030void Array::print_decl(ostream &out, string space, bool print_semi, bool constraint_info, bool constrained)
1031{
1032 if (constrained && !send_p()) return;
1033
1034// print it, but w/o semicolon
1035 var()->print_decl(out, space, false, constraint_info, constrained);
1036
1037 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
1038 out << "[";
1039 if ((*i).name != "") {
1040 out << id2www((*i).name) << " = ";
1041 }
1042 if (constrained) {
1043 out << (*i).c_size << "]";
1044 }
1045 else {
1046 out << (*i).size << "]";
1047 }
1048 }
1049
1050 if (print_semi) {
1051 out << ";\n";
1052 }
1053}
1054
1058void Array::print_xml(FILE *out, string space, bool constrained)
1059{
1060 XMLWriter xml(space);
1061 print_xml_writer_core(xml, constrained, "Array");
1062 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
1063}
1064
1068void Array::print_xml(ostream &out, string space, bool constrained)
1069{
1070 XMLWriter xml(space);
1071 print_xml_writer_core(xml, constrained, "Array");
1072 out << xml.get_doc();
1073}
1074
1078void Array::print_as_map_xml(FILE *out, string space, bool constrained)
1079{
1080 XMLWriter xml(space);
1081 print_xml_writer_core(xml, constrained, "Map");
1082 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
1083}
1084
1088void Array::print_as_map_xml(ostream &out, string space, bool constrained)
1089{
1090 XMLWriter xml(space);
1091 print_xml_writer_core(xml, constrained, "Map");
1092 out << xml.get_doc();
1093}
1094
1098void Array::print_xml_core(FILE *out, string space, bool constrained, string tag)
1099{
1100 XMLWriter xml(space);
1101 print_xml_writer_core(xml, constrained, tag);
1102 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
1103}
1104
1108void Array::print_xml_core(ostream &out, string space, bool constrained, string tag)
1109{
1110 XMLWriter xml(space);
1111 print_xml_writer_core(xml, constrained, tag);
1112 out << xml.get_doc();
1113}
1114
1115void Array::print_xml_writer(XMLWriter &xml, bool constrained)
1116{
1117 print_xml_writer_core(xml, constrained, "Array");
1118}
1119
1120void Array::print_as_map_xml_writer(XMLWriter &xml, bool constrained)
1121{
1122 print_xml_writer_core(xml, constrained, "Map");
1123}
1124
1125class PrintArrayDimXMLWriter: public unary_function<Array::dimension&, void> {
1126 XMLWriter &xml;
1127 bool d_constrained;
1128public:
1129 PrintArrayDimXMLWriter(XMLWriter &xml, bool c) :
1130 xml(xml), d_constrained(c)
1131 {
1132 }
1133
1134 void operator()(Array::dimension &d)
1135 {
1136 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dimension") < 0)
1137 throw InternalErr(__FILE__, __LINE__, "Could not write dimension element");
1138
1139 if (!d.name.empty())
1140 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) d.name.c_str())
1141 < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1142
1143 ostringstream size;
1144 size << (d_constrained ? d.c_size : d.size);
1145 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size", (const xmlChar*) size.str().c_str())
1146 < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1147
1148 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1149 throw InternalErr(__FILE__, __LINE__, "Could not end dimension element");
1150 }
1151};
1152
1153void Array::print_xml_writer_core(XMLWriter &xml, bool constrained, string tag)
1154{
1155 if (constrained && !send_p()) return;
1156
1157 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) tag.c_str()) < 0)
1158 throw InternalErr(__FILE__, __LINE__, "Could not write " + tag + " element");
1159
1160 if (!name().empty())
1161 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name().c_str()) < 0)
1162 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1163
1165
1166 BaseType *btp = var();
1167 string tmp_name = btp->name();
1168 btp->set_name("");
1169 btp->print_xml_writer(xml, constrained);
1170 btp->set_name(tmp_name);
1171
1172 for_each(dim_begin(), dim_end(), PrintArrayDimXMLWriter(xml, constrained));
1173
1174 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1175 throw InternalErr(__FILE__, __LINE__, "Could not end " + tag + " element");
1176}
1177
1189unsigned int Array::print_array(FILE *out, unsigned int index, unsigned int dims, unsigned int shape[])
1190{
1191 ostringstream oss;
1192 unsigned int i = print_array(oss, index, dims, shape);
1193 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1194
1195 return i;
1196}
1197
1209unsigned int Array::print_array(ostream &out, unsigned int index, unsigned int dims, unsigned int shape[])
1210{
1211 if (dims == 1) {
1212 out << "{";
1213
1214 // Added test in case this method is passed an array with no elements. jhrg 1/27/16
1215 if (shape[0] >= 1) {
1216 for (unsigned i = 0; i < shape[0] - 1; ++i) {
1217 var(index++)->print_val(out, "", false);
1218 out << ", ";
1219 }
1220 var(index++)->print_val(out, "", false);
1221 }
1222
1223 out << "}";
1224
1225 return index;
1226 }
1227 else {
1228 out << "{";
1229 // Fixed an off-by-one error in the following loop. Since the array
1230 // length is shape[dims-1]-1 *and* since we want one less dimension
1231 // than that, the correct limit on this loop is shape[dims-2]-1. From
1232 // Todd Karakasian.
1233 //
1234 // The saga continues; the loop test should be `i < shape[0]-1'. jhrg
1235 // 9/12/96.
1236 //
1237 // For arrays that hold zero values but have rank > 1, the print out
1238 // may look a little odd (e.g., x[4][0] will print as { {}, {}, {}, {} })
1239 // but it's not wrong and this is really for debugging mostly. jhrg 1/28/16
1240 if (shape[0] > 0) {
1241 for (unsigned i = 0; i < shape[0] - 1; ++i) {
1242 index = print_array(out, index, dims - 1, shape + 1);
1243 out << ",";
1244 }
1245
1246 index = print_array(out, index, dims - 1, shape + 1);
1247 }
1248
1249 out << "}";
1250
1251 return index;
1252 }
1253}
1254
1255void Array::print_val(FILE *out, string space, bool print_decl_p)
1256{
1257 ostringstream oss;
1258 print_val(oss, space, print_decl_p);
1259 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1260}
1261
1262void Array::print_val(ostream &out, string space, bool print_decl_p)
1263{
1264// print the declaration if print decl is true.
1265// for each dimension,
1266// for each element,
1267// print the array given its shape, number of dimensions.
1268// Add the `;'
1269
1270 if (print_decl_p) {
1271 print_decl(out, space, false, false, false);
1272 out << " = ";
1273 }
1274
1275 unsigned int *shape = new unsigned int[dimensions(true)];
1276 unsigned int index = 0;
1277 for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i)
1278 shape[index++] = dimension_size(i, true);
1279
1280 print_array(out, 0, dimensions(true), shape);
1281
1282 delete[] shape;
1283 shape = 0;
1284
1285 if (print_decl_p) {
1286 out << ";\n";
1287 }
1288}
1289
1299bool Array::check_semantics(string &msg, bool)
1300{
1301 bool sem = BaseType::check_semantics(msg) && !_shape.empty();
1302
1303 if (!sem) msg = "An array variable must have dimensions";
1304
1305 return sem;
1306}
1307
1316void Array::dump(ostream &strm) const
1317{
1318 strm << DapIndent::LMarg << "Array::dump - (" << (void *) this << ")" << endl;
1319 DapIndent::Indent();
1320 Vector::dump(strm);
1321 strm << DapIndent::LMarg << "shape:" << endl;
1322 DapIndent::Indent();
1323 Dim_citer i = _shape.begin();
1324 Dim_citer ie = _shape.end();
1325 unsigned int dim_num = 0;
1326 for (; i != ie; i++) {
1327 strm << DapIndent::LMarg << "dimension " << dim_num++ << ":" << endl;
1328 DapIndent::Indent();
1329 strm << DapIndent::LMarg << "name: " << (*i).name << endl;
1330 strm << DapIndent::LMarg << "size: " << (*i).size << endl;
1331 strm << DapIndent::LMarg << "start: " << (*i).start << endl;
1332 strm << DapIndent::LMarg << "stop: " << (*i).stop << endl;
1333 strm << DapIndent::LMarg << "stride: " << (*i).stride << endl;
1334 strm << DapIndent::LMarg << "constrained size: " << (*i).c_size << endl;
1335 DapIndent::UnIndent();
1336 }
1337 DapIndent::UnIndent();
1338 DapIndent::UnIndent();
1339}
1340
1341} // namespace libdap
1342
A multidimensional array of identical data types.
Definition: Array.h:113
virtual int dimension_start(Dim_iter i, bool constrained=false)
Return the start index of a dimension.
Definition: Array.cc:756
virtual void clear_constraint()
Clears the projection; add each projected dimension explicitly using add_constraint.
Definition: Array.cc:607
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Array.cc:1316
virtual std::vector< BaseType * > * transform_to_dap2(AttrTable *parent_attr_table)
Transforms this instance of a D4Array into the corresponding DAP2 object.
Definition: Array.cc:293
Dim_iter dim_end()
Definition: Array.cc:687
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: Array.cc:183
virtual BaseType * ptr_duplicate()
Definition: Array.cc:169
virtual void print_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Array.cc:1068
unsigned int print_array(FILE *out, unsigned int index, unsigned int dims, unsigned int shape[])
Print the value given the current constraint.
Definition: Array.cc:1189
virtual int dimension_stop(Dim_iter i, bool constrained=false)
Return the stop index of the constraint.
Definition: Array.cc:779
virtual void update_length(int size=0)
Definition: Array.cc:102
virtual void add_constraint(Dim_iter i, int start, int stride, int stop)
Adds a constraint to an Array dimension.
Definition: Array.cc:638
virtual string dimension_name(Dim_iter i)
Returns the name of the specified dimension.
Definition: Array.cc:818
virtual void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Prints a DDS entry for the Array.
Definition: Array.cc:1030
void append_dim(int size, const string &name="")
Add a dimension of a given size.
Definition: Array.cc:513
std::vector< dimension >::iterator Dim_iter
Definition: Array.h:206
void rename_dim(const string &oldName="", const string &newName="")
Renames dimension.
Definition: Array.cc:565
virtual int dimension_size(Dim_iter i, bool constrained=false)
Returns the size of the dimension.
Definition: Array.cc:724
void clear_all_dims()
Definition: Array.cc:555
virtual void print_dap4(XMLWriter &xml, bool constrained=false)
Print the DAP4 representation of an array.
Definition: Array.cc:949
virtual bool check_semantics(string &msg, bool all=false)
Check semantic features of the Array.
Definition: Array.cc:1299
std::vector< dimension >::const_iterator Dim_citer
Definition: Array.h:198
virtual void print_as_map_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Array.cc:1088
virtual void reset_constraint()
Reset constraint to select entire array.
Definition: Array.cc:584
void add_var(BaseType *v, Part p=nil)
Add the BaseType pointer to this constructor type instance.
Definition: Array.cc:461
virtual ~Array()
The Array destructor.
Definition: Array.cc:163
virtual void print_xml_core(FILE *out, string space, bool constrained, string tag)
Definition: Array.cc:1098
void prepend_dim(int size, const string &name="")
Definition: Array.cc:534
Dim_iter dim_begin()
Definition: Array.cc:681
Array(const string &n, BaseType *v, bool is_dap4=false)
Array constructor.
Definition: Array.cc:130
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: Array.cc:1115
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: Array.cc:1262
virtual unsigned int dimensions(bool constrained=false)
Return the total number of dimensions in the array.
Definition: Array.cc:702
virtual int dimension_stride(Dim_iter i, bool constrained=false)
Returns the stride value of the constraint.
Definition: Array.cc:803
Contains the attributes for a dataset.
Definition: AttrTable.h:143
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:410
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition: AttrTable.cc:245
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:238
void print_xml_writer(XMLWriter &xml)
Definition: AttrTable.cc:1425
virtual void print(FILE *out, string pad=" ", bool dereference=false)
Prints the attribute table.
Definition: AttrTable.cc:1243
virtual unsigned int get_size() const
Get the number of entries in this attribute table.
Definition: AttrTable.cc:231
The basic data type for the DODS DAP types.
Definition: BaseType.h:118
virtual string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:375
virtual AttrTable & get_attr_table()
Definition: BaseType.cc:578
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:316
virtual void print_decl(FILE *out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Print an ASCII representation of the variable structure.
Definition: BaseType.cc:999
virtual unsigned int width(bool constrained=false) const
How many bytes does this variable use Return the number of bytes of storage this variable uses....
Definition: BaseType.cc:1295
virtual bool is_constructor_type() const
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable.
Definition: BaseType.cc:408
virtual D4Attributes * attributes()
Definition: BaseType.cc:595
virtual std::string FQN() const
Definition: BaseType.cc:328
virtual bool send_p()
Should this variable be sent?
Definition: BaseType.cc:550
virtual bool check_semantics(string &msg, bool all=false)
Compare an object's current state with the semantics of its type.
Definition: BaseType.cc:1205
BaseType(const string &n, const Type &t, bool is_dap4=false)
The BaseType constructor.
Definition: BaseType.cc:126
virtual Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:361
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: BaseType.cc:1086
Vars_iter var_end()
Definition: Constructor.cc:280
void add_var_nocopy(BaseType *bt, Part part=nil) override
Definition: Constructor.cc:345
Vars_iter var_begin()
Definition: Constructor.cc:272
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
void transform_attrs_to_dap2(AttrTable *d2_attr_table)
Copy the attributes from this D4Attributes object to a DAP2 AttrTable.
vector< D4Dimension * >::iterator D4DimensionsIter
Iterator used for D4Dimensions.
Definition: D4Dimensions.h:122
void add_dim_nocopy(D4Dimension *dim)
Definition: D4Dimensions.h:160
D4DimensionsIter dim_end()
Get an iterator to the end of the dimensions.
Definition: D4Dimensions.h:166
D4DimensionsIter dim_begin()
Get an iterator to the start of the dimensions.
Definition: D4Dimensions.h:163
Holds a DAP4 enumeration.
Definition: D4Enum.h:56
D4Dimensions * dims()
Get the dimensions defined for this Group.
Definition: D4Group.h:83
A class for error processing.
Definition: Error.h:94
Holds the Grid data type.
Definition: Grid.h:123
virtual void set_array(Array *p_new_arr)
Definition: Grid.cc:368
virtual Array * add_map(Array *p_new_map, bool add_copy)
Definition: Grid.cc:434
A class for software fault reporting.
Definition: InternalErr.h:65
Holds a one-dimensional collection of DAP2 data types.
Definition: Vector.h:81
virtual void add_var(BaseType *v, Part p=nil)
Add the BaseType pointer to this constructor type instance.
Definition: Vector.cc:1961
virtual void set_length(int l)
Definition: Vector.cc:555
virtual int length() const
Definition: Vector.cc:548
virtual unsigned int width(bool constrained=false) const
Returns the width of the data, in bytes.
Definition: Vector.cc:536
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Vector.cc:2044
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Definition: Vector.cc:433
top level DAP object to house generic methods
Definition: AlarmHandler.h:36
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:220
Part
Names the parts of multi-section constructor data types.
Definition: Type.h:48
string id2www(string in, const string &allowable)
Definition: escaping.cc:153
int stride
The constraint stride.
Definition: Array.h:150
string name
The name of this dimension.
Definition: Array.h:136
bool use_sdim_for_slice
Used to control printing the DMR in data responses.
Definition: Array.h:146
int start
The constraint start index.
Definition: Array.h:148
int size
The unconstrained dimension size.
Definition: Array.h:135
int stop
The constraint end index.
Definition: Array.h:149
int c_size
Size of dimension once constrained.
Definition: Array.h:151