libdap Updated for version 3.20.5
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 // d_maps = a.d_maps ? new D4Maps(*(a.d_maps)) : 0;
89}
90
91// The first method of calculating length works when only one dimension is
92// constrained and you want the others to appear in total. This is important
93// when selecting from grids since users may not select from all dimensions
94// in which case that means they want the whole thing. Array projection
95// should probably work this way too, but it doesn't. 9/21/2001 jhrg
96
103void Array::update_length(int)
104{
105 int length = 1;
106 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
107#if 0
108 // If the size of any dimension is zero, then the array is not
109 // capable of storing any values. jhrg 1/28/16
110 length *= (*i).c_size > 0 ? (*i).c_size : 1;
111#endif
112 length *= (*i).c_size;
113 }
114
115 set_length(length);
116}
117
118// Construct an instance of Array. The (BaseType *) is assumed to be
119// allocated using new - The dtor for Vector will delete this object.
120
136Array::Array(const string &n, BaseType *v, bool is_dap4 /* default:false */) :
137 Vector(n, 0, dods_array_c, is_dap4), d_maps(0)
138{
139 add_var(v); // Vector::add_var() stores null if v is null
140}
141
155Array::Array(const string &n, const string &d, BaseType *v, bool is_dap4 /* default:false */) :
156 Vector(n, d, 0, dods_array_c, is_dap4), d_maps(0)
157{
158 add_var(v); // Vector::add_var() stores null if v is null
159}
160
162Array::Array(const Array &rhs) :
163 Vector(rhs)
164{
165 _duplicate(rhs);
166}
167
170{
171 delete d_maps;
172}
173
174BaseType *
176{
177 return new Array(*this);
178}
179
180Array &
181Array::operator=(const Array &rhs)
182{
183 if (this == &rhs) return *this;
184
185 dynamic_cast<Vector &>(*this) = rhs;
186
187 _duplicate(rhs);
188
189 return *this;
190}
191
193{
194 Array *dest = static_cast<Array*>(ptr_duplicate());
195
196 // If it's already a DAP4 object then we can just return it!
197 if (is_dap4()) {
198 container->add_var_nocopy(dest);
199 }
200
201 // Process the Array's dimensions, making D4 shared dimensions for
202 // D2 dimensions that are named. If there is just a size, don't make
203 // a D4Dimension (In DAP4 you cannot share a dimension unless it has
204 // a name). jhrg 3/18/14
205
206 D4Dimensions *root_dims = root->dims();
207 for (Array::Dim_iter dap2_dim = dest->dim_begin(), e = dest->dim_end(); dap2_dim != e; ++dap2_dim) {
208 if (!(*dap2_dim).name.empty()) {
209
210 // If a D4Dimension with the name already exists, use it.
211 D4Dimension *d4_dim = root_dims->find_dim((*dap2_dim).name);
212 if (!d4_dim) {
213 d4_dim = new D4Dimension((*dap2_dim).name, (*dap2_dim).size);
214 root_dims->add_dim_nocopy(d4_dim);
215 }
216 else {
217 DBG(cerr << __func__ << "() -" <<
218 " Using Existing D4Dimension '"<< d4_dim->name() << "' (" <<
219 (void *)d4_dim << ")"<< endl);;
220
221 if (d4_dim->size() != (unsigned long) (*dap2_dim).size) {
222 // TODO Revisit this decision. jhrg 3/18/14
223 // ...in case the name/size are different, make a unique D4Dimension
224 // but don't fiddle with the name. Not sure I like this idea, so I'm
225 // making the case explicit (could be rolled in to the block above).
226 // jhrg 3/18/14
227 //
228 // This is causing problems in the FITS handler because there are cases
229 // where two arrays have dimensions with the same name but different
230 // sizes. The deserializing code is using the first size listed, which is
231 // wrong in some cases. I'm going to try making this new D4Dimension using
232 // the dim name along with the variable name. jhrg 8/15/14
233 d4_dim = new D4Dimension((*dap2_dim).name + "_" + name(), (*dap2_dim).size);
234 DBG(cerr << __func__ << "() -" <<
235 " Utilizing Name/Size Conflict Naming Artifice. name'"<< d4_dim->name() << "' (" <<
236 (void *)d4_dim << ")"<< endl);;
237 root_dims->add_dim_nocopy(d4_dim);
238 }
239 }
240 // At this point d4_dim's name and size == those of (*d) so just set
241 // the D4Dimension pointer so it matches the one in the D4Group.
242 (*dap2_dim).dim = d4_dim;
243 }
244
245 }
246
247 // Copy the D2 attributes to D4 Attributes
249 dest->set_is_dap4(true);
250 container->add_var_nocopy(dest);
251 DBG(cerr << __func__ << "() - END (array:" << name() << ")" << endl);;
252}
253
254bool Array::is_dap2_grid()
255{
256 bool is_grid = false;
257 if (this->is_dap4()) {
258 DBG( cerr << __func__ << "() - Array '"<< name() << "' is DAP4 object!" << endl);
259 D4Maps *d4_maps = this->maps();
260 is_grid = d4_maps->size(); // It can't be a grid if there are no maps...
261 if (is_grid) {
262 DBG( cerr << __func__ << "() - Array '"<< name() << "' has D4Maps." << endl);
263 // hmmm this might be a DAP2 Grid...
264 D4Maps::D4MapsIter i = d4_maps->map_begin();
265 D4Maps::D4MapsIter e = d4_maps->map_end();
266 while (i != e) {
267 DBG( cerr << __func__ << "() - Map '"<< (*i)->array()->name() << " has " << (*i)->array()->_shape.size() << " dimension(s)." << endl);
268 if ((*i)->array()->_shape.size() > 1) {
269 is_grid = false;
270 i = e;
271 }
272 else {
273 i++;
274 }
275 }
276 }
277 else {
278 DBG( cerr << __func__ << "() - Array '"<< name() << "' has no D4Maps." << endl);
279 }
280 }
281
282 DBG( cerr << __func__ << "() - is_grid: "<< (is_grid?"true":"false") << endl);
283 return is_grid;
284}
285
301std::vector<BaseType *> *
303{
304 DBG(cerr << __func__ << "() - BEGIN Array '"<< name() << "'" << endl);;
305
306 BaseType *dest;
307 if (!is_dap4()) { // Don't convert a DAP2 thing
308 dest = ptr_duplicate();
309 }
310 else {
311 // At this point we have a DAP4 Array. It have D4Attributes and nothing
312 // in the DAP2 AttrTable (which is held as a reference, defined in BaseType).
313 // This test determines in the D4 Array qualifies as a D2 Grid.
314 if (is_dap2_grid()) {
315 // Oh yay! Grids are special.
316 DBG(cerr << __func__ << "() - Array '"<< name() << "' is dap2 Grid!" << endl);;
317 Grid *g = new Grid(name());
318 dest = g;
319 Array *grid_array = static_cast<Array *>(ptr_duplicate());
320 g->set_array(grid_array);
321
322 // Fix for HK-403. jhrg 6/17/19
324
325 // Process the Map Arrays.
326 D4Maps *d4_maps = this->maps();
327 vector<BaseType *> dropped_maps;
328 D4Maps::D4MapsIter miter = d4_maps->map_begin();
329 D4Maps::D4MapsIter end = d4_maps->map_end();
330 for (; miter != end; miter++) {
331 D4Map *d4_map = (*miter);
332 Array *d4_map_array = const_cast<Array*>(d4_map->array());
333 vector<BaseType *> *d2_result = d4_map_array->transform_to_dap2(&(g->get_attr_table()));
334 if (d2_result) {
335 if (d2_result->size() > 1)
336 throw Error(internal_error, "D4Map Array conversion resulted in multiple DAP2 objects.");
337
338 // TODO - This is probably slow and needs a better pattern. const_cast? static_cast?
339 Array *d2_map_array = dynamic_cast<Array *>((*d2_result)[0]);
340 if (d2_map_array) {
341 if (d2_map_array->dimensions() != 1)
342 throw Error(internal_error, "DAP2 array from D4Map Array conversion has more than 1 dimension.");
343
344 g->add_map(d2_map_array, false);
345 AttrTable at = d2_map_array->get_attr_table();
346 DBG( cerr << __func__ << "() - " <<
347 "DAS For Grid Map '" << d2_map_array->name() << "':" << endl;
348 at.print(cerr); );
349 }
350 else {
351 throw Error(internal_error, "Unable to interpret returned DAP2 content.");
352 }
353 delete d2_result;
354 }
355 else {
356 dropped_maps.push_back(d4_map_array);
357 }
358 }
359
360 // Did we have a transform failure?
361 if (!dropped_maps.empty()) {
362 // Yup... tell the story in the attributes.
363 AttrTable *dv_table = Constructor::make_dropped_vars_attr_table(&dropped_maps);
364 dest->get_attr_table().append_container(dv_table, dv_table->get_name());
365 }
366 }
367 else {
368 DBG( cerr << __func__ << "() - Array '"<< name() << "' is not a Grid!" << endl);
369
370 BaseType *proto = prototype();
371 switch (proto->type()) {
372 case dods_int64_c:
373 case dods_uint64_c:
374 case dods_enum_c:
375 case dods_opaque_c:
376 // For now we punt on these types as they have no easy representation in
377 // the DAP2 data model. By setting this to NULL we cause the Array to be
378 // dropped and this will be reflected in the metadata (DAS).
379 dest = NULL;
380 break;
381
382 default:
383 // ptr_duplicate() does the Attributes too.
384 dest = ptr_duplicate();
385
386 // Fix for HK-403. jhrg 6/17/19
387 // Only transform the DAP4 attributes to DAP2 ones if the DAP2 object lacks
388 // attributes. If the new DAP2 variable already has attributes, they were
389 // added by this process (driven by D4Group::transform_to_dap2() and calling
390 // attributes()->transform_to_dap2() will put a second copy of each attribute's
391 // value in the DAP2 AttrTable. This attribute transform code (here and elsewhere)
392 // depends on the AttrTable for a DAP4 variable initially being empty. Once it
393 // contains attributes, the code assumes they were put there by this transform
394 // process. jhrg 6/18/19
395 if (dest->get_attr_table().get_size() == 0) {
397 dest->get_attr_table().set_name(name());
398 }
399
400 dest->set_is_dap4(false);
401 break;
402 }
403 }
404 }
405
406 vector<BaseType *> *result;
407 if (dest) {
408 result = new vector<BaseType *>();
409 result->push_back(dest);
410 }
411 else {
412 result = NULL;
413 }
414
415 DBG( cerr << __func__ << "() - END Array '"<< name() << "'" << endl);;
416 return result;
417}
418
430void Array::update_dimension_pointers(D4Dimensions *old_dims, D4Dimensions *new_dims)
431{
432 std::vector<dimension>::iterator i = _shape.begin(), e = _shape.end();
433 while (i != e) {
434 D4Dimensions::D4DimensionsIter old_i = old_dims->dim_begin(), old_e = old_dims->dim_end();
435 while (old_i != old_e) {
436 if ((*i).dim == *old_i) {
437 (*i).dim = new_dims->find_dim((*old_i)->name());
438 }
439 ++old_i;
440 }
441
442 ++i;
443 }
444}
445
471{
472// If 'v' is an Array, add the template instance to this object and
473// then copy the dimension information. Odd semantics; I wonder if this
474//is ever used. jhrg 6/13/12
475 if (v && v->type() == dods_array_c) {
476 Array *a = static_cast<Array*>(v);
477 Vector::add_var(a->var());
478
479 Dim_iter i = a->dim_begin();
480 Dim_iter i_end = a->dim_end();
481 while (i != i_end) {
483 ++i;
484 }
485 }
486 else {
488 }
489}
490
491void Array::add_var_nocopy(BaseType *v, Part)
492{
493// If 'v' is an Array, add the template instance to this object and
494// then copy the dimension information. Odd semantics; I wonder if this
495//is ever used. jhrg 6/13/12
496 if (v && v->type() == dods_array_c) {
497 Array &a = dynamic_cast<Array&>(*v);
498 Vector::add_var_nocopy(a.var());
499 Dim_iter i = a.dim_begin();
500 Dim_iter i_end = a.dim_end();
501 while (i != i_end) {
503 ++i;
504 }
505 }
506 else {
507 Vector::add_var_nocopy(v);
508 }
509}
510
522void Array::append_dim(int size, const string &name)
523{
524 dimension d(size, www2id(name));
525 _shape.push_back(d);
526
528}
529
531{
532 dimension d(/*dim->size(), www2id(dim->name()),*/dim);
533 _shape.push_back(d);
534
536}
537
543void Array::prepend_dim(int size, const string& name/* = "" */)
544{
545 dimension d(size, www2id(name));
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
553{
554 dimension d(/*dim->size(), www2id(dim->name()),*/dim);
555// Shifts the whole array, but it's tiny in general
556 _shape.insert(_shape.begin(), d);
557
558 update_length(); // the number is ignored...
559}
560
565{
566 _shape.clear();
567}
568
574void Array::rename_dim(const string &oldName, const string &newName)
575{
576 std::vector<dimension>::iterator i = _shape.begin(), e = _shape.end();
577 while (i != e) {
578 dimension &d = *i;
579 if (d.name == oldName) {
580 DBG(cerr << "Old name = " << d.name << " newName = " << newName << endl);
581 d.name = newName;
582 }
583
584 ++i;
585 }
586}
587
594{
595 set_length(-1);
596
597 for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
598 (*i).start = 0;
599 (*i).stop = (*i).size - 1;
600 (*i).stride = 1;
601 (*i).c_size = (*i).size;
602
604 }
605}
606
620
621// Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n
622// is explicit.
623static const char *array_sss =
624 "Invalid constraint parameters: At least one of the start, stride or stop \n\
625specified do not match the array variable.";
626
647void Array::add_constraint(Dim_iter i, int start, int stride, int stop)
648{
649 dimension &d = *i;
650
651// if stop is -1, set it to the array's max element index
652// jhrg 12/20/12
653 if (stop == -1) stop = d.size - 1;
654
655// Check for bad constraints.
656// Jose Garcia
657// Usually invalid data for a constraint is the user's mistake
658// because they build a wrong URL in the client side.
659 if (start >= d.size || stop >= d.size || stride > d.size || stride <= 0) throw Error(malformed_expr, array_sss);
660
661 if (((stop - start) / stride + 1) > d.size) throw Error(malformed_expr, array_sss);
662
663 d.start = start;
664 d.stop = stop;
665 d.stride = stride;
666
667 d.c_size = (stop - start) / stride + 1;
668
669 DBG(cerr << "add_constraint: c_size = " << d.c_size << endl);
670
672
673 d.use_sdim_for_slice = false;
674}
675
676void Array::add_constraint(Dim_iter i, D4Dimension *dim)
677{
678 dimension &d = *i;
679
680 if (dim->constrained()) add_constraint(i, dim->c_start(), dim->c_stride(), dim->c_stop());
681
682 dim->set_used_by_projected_var(true);
683
684// In this case the value below overrides the value for use_sdim_for_slice
685// set in the above call. jhrg 12/20/13
686 d.use_sdim_for_slice = true;
687}
688
691{
692 return _shape.begin();
693}
694
697{
698 return _shape.end();
699}
700
701//TODO Many of these methods take a bool parameter that serves no use; remove.
702
711unsigned int Array::dimensions(bool /*constrained*/)
712{
713 return _shape.size();
714}
715
733int Array::dimension_size(Dim_iter i, bool constrained)
734{
735 int size = 0;
736
737 if (!_shape.empty()) {
738 if (constrained)
739 size = (*i).c_size;
740 else
741 size = (*i).size;
742 }
743
744 return size;
745}
746
765int Array::dimension_start(Dim_iter i, bool /*constrained*/)
766{
767 return (!_shape.empty()) ? (*i).start : 0;
768}
769
788int Array::dimension_stop(Dim_iter i, bool /*constrained*/)
789{
790 return (!_shape.empty()) ? (*i).stop : 0;
791}
792
812int Array::dimension_stride(Dim_iter i, bool /*constrained*/)
813{
814 return (!_shape.empty()) ? (*i).stride : 0;
815}
816
828{
829// Jose Garcia
830// Since this method is public, it is possible for a user
831// to call it before the Array object has been properly set
832// this will cause an exception which is the user's fault.
833// (User in this context is the developer of the surrogate library.)
834 if (_shape.empty()) throw InternalErr(__FILE__, __LINE__, "*This* array has no dimensions.");
835 return (*i).name;
836}
837
839Array::dimension_D4dim(Dim_iter i)
840{
841 return (!_shape.empty()) ? (*i).dim : 0;
842}
843
844D4Maps *
845Array::maps()
846{
847 if (!d_maps) d_maps = new D4Maps(this); // init with this as parent
848 return d_maps;
849}
850
851#if 0
858unsigned int Array::width(bool constrained) const
859{
860
861 if (constrained) {
862 // This preserves the original method's semantics when we ask for the
863 // size of the constrained array but no constraint has been applied.
864 // In this case, length will be -1. Wrong, I know...
865 return length() * var()->width(constrained);
866 }
867 else {
868 int length = 1;
869 for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
870 length *= dimension_size(i, false);
871 }
872 return length * var()->width(false);
873 }
874}
875#endif
876
877class PrintD4ArrayDimXMLWriter: public unary_function<Array::dimension&, void> {
878 XMLWriter &xml;
879// Was this variable constrained using local/direct slicing? i.e., is d_local_constraint set?
880// If so, don't use shared dimensions; instead emit Dim elements that are anonymous.
881 bool d_constrained;
882public:
883
884 PrintD4ArrayDimXMLWriter(XMLWriter &xml, bool c) :
885 xml(xml), d_constrained(c)
886 {
887 }
888
889 void operator()(Array::dimension &d)
890 {
891 // This duplicates code in D4Dimensions (where D4Dimension::print_dap4() is defined
892 // because of the need to print the constrained size of a dimension. I think that
893 // the constraint information has to be kept here and not in the dimension (since they
894 // are shared dims). Could hack print_dap4() to take the constrained size, however.
895 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dim") < 0)
896 throw InternalErr(__FILE__, __LINE__, "Could not write Dim element");
897
898 string name = (d.dim) ? d.dim->fully_qualified_name() : d.name;
899 // If there is a name, there must be a Dimension (named dimension) in scope
900 // so write its name but not its size.
901 if (!d_constrained && !name.empty()) {
902 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name.c_str())
903 < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
904 }
905 else if (d.use_sdim_for_slice) {
906 assert(!name.empty());
907 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name.c_str())
908 < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
909 }
910 else {
911 ostringstream size;
912 size << (d_constrained ? d.c_size : d.size);
913 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size",
914 (const xmlChar*) size.str().c_str()) < 0)
915 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
916 }
917
918 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
919 throw InternalErr(__FILE__, __LINE__, "Could not end Dim element");
920 }
921};
922
923class PrintD4ConstructorVarXMLWriter: public unary_function<BaseType*, void> {
924 XMLWriter &xml;
925 bool d_constrained;
926public:
927 PrintD4ConstructorVarXMLWriter(XMLWriter &xml, bool c) :
928 xml(xml), d_constrained(c)
929 {
930 }
931
932 void operator()(BaseType *btp)
933 {
934 btp->print_dap4(xml, d_constrained);
935 }
936};
937
938class PrintD4MapXMLWriter: public unary_function<D4Map*, void> {
939 XMLWriter &xml;
940
941public:
942 PrintD4MapXMLWriter(XMLWriter &xml) :
943 xml(xml)
944 {
945 }
946
947 void operator()(D4Map *m)
948 {
949 m->print_dap4(xml);
950 }
951};
952
958void Array::print_dap4(XMLWriter &xml, bool constrained /* default: false*/)
959{
960 if (constrained && !send_p()) return;
961
962 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) var()->type_name().c_str()) < 0)
963 throw InternalErr(__FILE__, __LINE__, "Could not write " + type_name() + " element");
964
965 if (!name().empty())
966 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name().c_str()) < 0)
967 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
968
969// Hack job... Copied from D4Enum::print_xml_writer. jhrg 11/12/13
970 if (var()->type() == dods_enum_c) {
971 D4Enum *e = static_cast<D4Enum*>(var());
972 string path = e->enumeration()->name();
973 if (e->enumeration()->parent()) {
974 // print the FQN for the enum def; D4Group::FQN() includes the trailing '/'
975 path = static_cast<D4Group*>(e->enumeration()->parent()->parent())->FQN() + path;
976 }
977 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "enum", (const xmlChar*) path.c_str()) < 0)
978 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for enum");
979 }
980
981 if (prototype()->is_constructor_type()) {
982 Constructor &c = static_cast<Constructor&>(*prototype());
983 for_each(c.var_begin(), c.var_end(), PrintD4ConstructorVarXMLWriter(xml, constrained));
984 // bind2nd(mem_fun_ref(&BaseType::print_dap4), xml));
985 }
986
987// Drop the local_constraint which is per-array and use a per-dimension on instead
988 for_each(dim_begin(), dim_end(), PrintD4ArrayDimXMLWriter(xml, constrained));
989
990 attributes()->print_dap4(xml);
991
992 for_each(maps()->map_begin(), maps()->map_end(), PrintD4MapXMLWriter(xml));
993
994 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
995 throw InternalErr(__FILE__, __LINE__, "Could not end " + type_name() + " element");
996}
997
1015void Array::print_decl(FILE *out, string space, bool print_semi, bool constraint_info, bool constrained)
1016{
1017 ostringstream oss;
1018 print_decl(oss, space, print_semi, constraint_info, constrained);
1019 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1020}
1021
1039void Array::print_decl(ostream &out, string space, bool print_semi, bool constraint_info, bool constrained)
1040{
1041 if (constrained && !send_p()) return;
1042
1043// print it, but w/o semicolon
1044 var()->print_decl(out, space, false, constraint_info, constrained);
1045
1046 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
1047 out << "[";
1048 if ((*i).name != "") {
1049 out << id2www((*i).name) << " = ";
1050 }
1051 if (constrained) {
1052 out << (*i).c_size << "]";
1053 }
1054 else {
1055 out << (*i).size << "]";
1056 }
1057 }
1058
1059 if (print_semi) {
1060 out << ";\n";
1061 }
1062}
1063
1067void Array::print_xml(FILE *out, string space, bool constrained)
1068{
1069 XMLWriter xml(space);
1070 print_xml_writer_core(xml, constrained, "Array");
1071 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
1072}
1073
1077void Array::print_xml(ostream &out, string space, bool constrained)
1078{
1079 XMLWriter xml(space);
1080 print_xml_writer_core(xml, constrained, "Array");
1081 out << xml.get_doc();
1082}
1083
1087void Array::print_as_map_xml(FILE *out, string space, bool constrained)
1088{
1089 XMLWriter xml(space);
1090 print_xml_writer_core(xml, constrained, "Map");
1091 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
1092}
1093
1097void Array::print_as_map_xml(ostream &out, string space, bool constrained)
1098{
1099 XMLWriter xml(space);
1100 print_xml_writer_core(xml, constrained, "Map");
1101 out << xml.get_doc();
1102}
1103
1107void Array::print_xml_core(FILE *out, string space, bool constrained, string tag)
1108{
1109 XMLWriter xml(space);
1110 print_xml_writer_core(xml, constrained, tag);
1111 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
1112}
1113
1117void Array::print_xml_core(ostream &out, string space, bool constrained, string tag)
1118{
1119 XMLWriter xml(space);
1120 print_xml_writer_core(xml, constrained, tag);
1121 out << xml.get_doc();
1122}
1123
1124void Array::print_xml_writer(XMLWriter &xml, bool constrained)
1125{
1126 print_xml_writer_core(xml, constrained, "Array");
1127}
1128
1129void Array::print_as_map_xml_writer(XMLWriter &xml, bool constrained)
1130{
1131 print_xml_writer_core(xml, constrained, "Map");
1132}
1133
1134class PrintArrayDimXMLWriter: public unary_function<Array::dimension&, void> {
1135 XMLWriter &xml;
1136 bool d_constrained;
1137public:
1138 PrintArrayDimXMLWriter(XMLWriter &xml, bool c) :
1139 xml(xml), d_constrained(c)
1140 {
1141 }
1142
1143 void operator()(Array::dimension &d)
1144 {
1145 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dimension") < 0)
1146 throw InternalErr(__FILE__, __LINE__, "Could not write dimension element");
1147
1148 if (!d.name.empty())
1149 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) d.name.c_str())
1150 < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1151
1152 ostringstream size;
1153 size << (d_constrained ? d.c_size : d.size);
1154 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size", (const xmlChar*) size.str().c_str())
1155 < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1156
1157 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1158 throw InternalErr(__FILE__, __LINE__, "Could not end dimension element");
1159 }
1160};
1161
1162void Array::print_xml_writer_core(XMLWriter &xml, bool constrained, string tag)
1163{
1164 if (constrained && !send_p()) return;
1165
1166 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) tag.c_str()) < 0)
1167 throw InternalErr(__FILE__, __LINE__, "Could not write " + tag + " element");
1168
1169 if (!name().empty())
1170 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name().c_str()) < 0)
1171 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1172
1174
1175 BaseType *btp = var();
1176 string tmp_name = btp->name();
1177 btp->set_name("");
1178 btp->print_xml_writer(xml, constrained);
1179 btp->set_name(tmp_name);
1180
1181 for_each(dim_begin(), dim_end(), PrintArrayDimXMLWriter(xml, constrained));
1182
1183 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1184 throw InternalErr(__FILE__, __LINE__, "Could not end " + tag + " element");
1185}
1186
1198unsigned int Array::print_array(FILE *out, unsigned int index, unsigned int dims, unsigned int shape[])
1199{
1200 ostringstream oss;
1201 unsigned int i = print_array(oss, index, dims, shape);
1202 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1203
1204 return i;
1205}
1206
1218unsigned int Array::print_array(ostream &out, unsigned int index, unsigned int dims, unsigned int shape[])
1219{
1220 if (dims == 1) {
1221 out << "{";
1222
1223 // Added test in case this method is passed an array with no elements. jhrg 1/27/16
1224 if (shape[0] >= 1) {
1225 for (unsigned i = 0; i < shape[0] - 1; ++i) {
1226 var(index++)->print_val(out, "", false);
1227 out << ", ";
1228 }
1229 var(index++)->print_val(out, "", false);
1230 }
1231
1232 out << "}";
1233
1234 return index;
1235 }
1236 else {
1237 out << "{";
1238 // Fixed an off-by-one error in the following loop. Since the array
1239 // length is shape[dims-1]-1 *and* since we want one less dimension
1240 // than that, the correct limit on this loop is shape[dims-2]-1. From
1241 // Todd Karakasian.
1242 //
1243 // The saga continues; the loop test should be `i < shape[0]-1'. jhrg
1244 // 9/12/96.
1245 //
1246 // For arrays that hold zero values but have rank > 1, the print out
1247 // may look a little odd (e.g., x[4][0] will print as { {}, {}, {}, {} })
1248 // but it's not wrong and this is really for debugging mostly. jhrg 1/28/16
1249 if (shape[0] > 0) {
1250 for (unsigned i = 0; i < shape[0] - 1; ++i) {
1251 index = print_array(out, index, dims - 1, shape + 1);
1252 out << ",";
1253 }
1254
1255 index = print_array(out, index, dims - 1, shape + 1);
1256 }
1257
1258 out << "}";
1259
1260 return index;
1261 }
1262}
1263
1264void Array::print_val(FILE *out, string space, bool print_decl_p)
1265{
1266 ostringstream oss;
1267 print_val(oss, space, print_decl_p);
1268 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1269}
1270
1271void Array::print_val(ostream &out, string space, bool print_decl_p)
1272{
1273// print the declaration if print decl is true.
1274// for each dimension,
1275// for each element,
1276// print the array given its shape, number of dimensions.
1277// Add the `;'
1278
1279 if (print_decl_p) {
1280 print_decl(out, space, false, false, false);
1281 out << " = ";
1282 }
1283
1284 unsigned int *shape = new unsigned int[dimensions(true)];
1285 unsigned int index = 0;
1286 for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i)
1287 shape[index++] = dimension_size(i, true);
1288
1289 print_array(out, 0, dimensions(true), shape);
1290
1291 delete[] shape;
1292 shape = 0;
1293
1294 if (print_decl_p) {
1295 out << ";\n";
1296 }
1297}
1298
1308bool Array::check_semantics(string &msg, bool)
1309{
1310 bool sem = BaseType::check_semantics(msg) && !_shape.empty();
1311
1312 if (!sem) msg = "An array variable must have dimensions";
1313
1314 return sem;
1315}
1316
1325void Array::dump(ostream &strm) const
1326{
1327 strm << DapIndent::LMarg << "Array::dump - (" << (void *) this << ")" << endl;
1328 DapIndent::Indent();
1329 Vector::dump(strm);
1330 strm << DapIndent::LMarg << "shape:" << endl;
1331 DapIndent::Indent();
1332 Dim_citer i = _shape.begin();
1333 Dim_citer ie = _shape.end();
1334 unsigned int dim_num = 0;
1335 for (; i != ie; i++) {
1336 strm << DapIndent::LMarg << "dimension " << dim_num++ << ":" << endl;
1337 DapIndent::Indent();
1338 strm << DapIndent::LMarg << "name: " << (*i).name << endl;
1339 strm << DapIndent::LMarg << "size: " << (*i).size << endl;
1340 strm << DapIndent::LMarg << "start: " << (*i).start << endl;
1341 strm << DapIndent::LMarg << "stop: " << (*i).stop << endl;
1342 strm << DapIndent::LMarg << "stride: " << (*i).stride << endl;
1343 strm << DapIndent::LMarg << "constrained size: " << (*i).c_size << endl;
1344 DapIndent::UnIndent();
1345 }
1346 DapIndent::UnIndent();
1347 DapIndent::UnIndent();
1348}
1349
1350} // namespace libdap
1351
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:765
virtual void clear_constraint()
Clears the projection; add each projected dimension explicitly using add_constraint.
Definition Array.cc:616
virtual void dump(ostream &strm) const
dumps information about this object
Definition Array.cc:1325
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:302
Dim_iter dim_end()
Definition Array.cc:696
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition Array.cc:192
virtual BaseType * ptr_duplicate()
Definition Array.cc:175
virtual void print_xml(ostream &out, string space=" ", bool constrained=false)
Definition Array.cc:1077
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:1198
virtual int dimension_stop(Dim_iter i, bool constrained=false)
Return the stop index of the constraint.
Definition Array.cc:788
virtual void update_length(int size=0)
Definition Array.cc:103
virtual void add_constraint(Dim_iter i, int start, int stride, int stop)
Adds a constraint to an Array dimension.
Definition Array.cc:647
virtual string dimension_name(Dim_iter i)
Returns the name of the specified dimension.
Definition Array.cc:827
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:1039
void append_dim(int size, const string &name="")
Add a dimension of a given size.
Definition Array.cc:522
std::vector< dimension >::iterator Dim_iter
Definition Array.h:206
void rename_dim(const string &oldName="", const string &newName="")
Renames dimension.
Definition Array.cc:574
virtual int dimension_size(Dim_iter i, bool constrained=false)
Returns the size of the dimension.
Definition Array.cc:733
void clear_all_dims()
Definition Array.cc:564
virtual void print_dap4(XMLWriter &xml, bool constrained=false)
Print the DAP4 representation of an array.
Definition Array.cc:958
virtual bool check_semantics(string &msg, bool all=false)
Check semantic features of the Array.
Definition Array.cc:1308
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:1097
virtual void reset_constraint()
Reset constraint to select entire array.
Definition Array.cc:593
void add_var(BaseType *v, Part p=nil)
Add the BaseType pointer to this constructor type instance.
Definition Array.cc:470
virtual ~Array()
The Array destructor.
Definition Array.cc:169
virtual void print_xml_core(FILE *out, string space, bool constrained, string tag)
Definition Array.cc:1107
void prepend_dim(int size, const string &name="")
Definition Array.cc:543
Dim_iter dim_begin()
Definition Array.cc:690
Array(const string &n, BaseType *v, bool is_dap4=false)
Array constructor.
Definition Array.cc:136
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition Array.cc:1124
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition Array.cc:1271
virtual unsigned int dimensions(bool constrained=false)
Return the total number of dimensions in the array.
Definition Array.cc:711
virtual int dimension_stride(Dim_iter i, bool constrained=false)
Returns the stride value of the constraint.
Definition Array.cc:812
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)
virtual void print(FILE *out, string pad=" ", bool dereference=false)
Prints the attribute table.
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:379
virtual AttrTable & get_attr_table()
Definition BaseType.cc:582
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:320
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:1003
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:1299
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:412
virtual D4Attributes * attributes()
Definition BaseType.cc:599
virtual std::string FQN() const
Definition BaseType.cc:332
virtual bool send_p()
Should this variable be sent?
Definition BaseType.cc:554
virtual bool check_semantics(string &msg, bool all=false)
Compare an object's current state with the semantics of its type.
Definition BaseType.cc:1209
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:365
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition BaseType.cc:1090
virtual void add_var_nocopy(BaseType *bt, Part part=nil)
Vars_iter var_begin()
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.
void add_dim_nocopy(D4Dimension *dim)
D4DimensionsIter dim_end()
Get an iterator to the end of the dimensions.
D4DimensionsIter dim_begin()
Get an iterator to the start of the dimensions.
Holds a DAP4 enumeration.
Definition D4Enum.h:62
D4Dimensions * dims()
Get the dimensions defined for this Group.
Definition D4Group.h:82
A class for error processing.
Definition Error.h:93
Holds the Grid data type.
Definition Grid.h:123
virtual void set_array(Array *p_new_arr)
Definition Grid.cc:389
virtual Array * add_map(Array *p_new_map, bool add_copy)
Definition Grid.cc:455
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:1946
virtual void set_length(int l)
Definition Vector.cc:555
virtual int length() const
Definition Vector.cc:548
virtual void dump(ostream &strm) const
dumps information about this object
Definition Vector.cc:2029
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
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