libdap Updated for version 3.21.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
Grid.cc
Go to the documentation of this file.
1
2// -*- mode: c++; c-basic-offset:4 -*-
3
4// This file is part of libdap, A C++ implementation of the OPeNDAP Data
5// Access Protocol.
6
7// Copyright (c) 2002,2003 OPeNDAP, Inc.
8// Author: James Gallagher <jgallagher@opendap.org>
9//
10// This library is free software; you can redistribute it and/or
11// modify it under the terms of the GNU Lesser General Public
12// License as published by the Free Software Foundation; either
13// version 2.1 of the License, or (at your option) any later version.
14//
15// This library is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18// Lesser General Public License for more details.
19//
20// You should have received a copy of the GNU Lesser General Public
21// License along with this library; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23//
24// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25
26// (c) COPYRIGHT URI/MIT 1994-1999
27// Please read the full copyright statement in the file COPYRIGHT_URI.
28//
29// Authors:
30// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
31
32// implementation for Grid.
33//
34// jhrg 9/15/94
35
36#include "config.h"
37
38#include <algorithm>
39#include <functional>
40#include <sstream>
41
42#include "Array.h" // for downcasts
43#include "DDS.h"
44#include "Grid.h"
45#include "InternalErr.h"
46#include "XDRStreamMarshaller.h"
47#include "debug.h"
48#include "escaping.h"
49#include "util.h"
50
51#include "D4Attributes.h"
52#include "D4Group.h"
53#include "D4Maps.h"
54#include "DMR.h"
55#include "XMLWriter.h"
56
57#include "DapIndent.h"
58
59using namespace std;
60
61namespace libdap {
62
63void Grid::m_duplicate(const Grid &s) { d_is_array_set = s.d_is_array_set; }
64
74Grid::Grid(const string &n) : Constructor(n, dods_grid_c), d_is_array_set(false) {}
75
87Grid::Grid(const string &n, const string &d) : Constructor(n, d, dods_grid_c), d_is_array_set(false) {}
88
90Grid::Grid(const Grid &rhs) : Constructor(rhs) { m_duplicate(rhs); }
91
93 // d_array_var = 0; // Weak pointer; object will be freed by Constructor
94}
95
96BaseType *Grid::ptr_duplicate() { return new Grid(*this); }
97
99 if (this == &rhs)
100 return *this;
102 m_duplicate(rhs);
103 return *this;
104}
105
110 DBG(cerr << __func__ << "() - BEGIN (name:" << name() << ")(type:" << type_name() << ")(root:'" << root->name()
111 << "':" << (void *)root << ")(container:'" << container->name() << "':" << (void *)container << ")"
112 << endl;);
113
114 vector<Array *> d4_map_arrays;
115
116 // We do the Map Arrays first because some people expect to see them
117 // declared prior to the coverage array the utilizes them - even though that
118 // is not a requirement of DAP4 I did it here to make people happier.
119 // We add the maps arrays to the current container if needed and make a
120 // vector of them so that we can add D4Map objects to our Precious down
121 // below.
122 for (Map_iter i = map_begin(), e = map_end(); i != e; ++i) {
123 DBG(cerr << __func__ << "() - Processing Map Array: '" << (*i)->name() << "' (" << (void *)(*i) << ")"
124 << endl;);
125 // Only add the map/array if it's not already present in the target DAP2 container.
126 // Given the scoping rules for DAP2 and the assumption the DDS is valid, testing for
127 // the same name is good enough. The point here is to be sure to only use the
128 // existing maps. This is an important issue when there are multiple Grids in the same
129 // dataset that utilize the same Map arrays data.
130 Array *the_map_array;
131 Array *container_map_array = static_cast<Array *>(container->var((*i)->name()));
132 if (!container_map_array) {
133 DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the current DAP4 container ("
134 << container->name() << ":" << (void *)container << "). Let's fix that..." << endl;);
135 // Not in the container, so we check root group
136 Array *root_map_array = static_cast<Array *>(root->var((*i)->name()));
137 if (!root_map_array) {
138 // Not in the root group so we transform a new array and add it to container.
139 DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the root Group ("
140 << root->name() << ":" << (void *)root << "). Let's fix that..." << endl;);
141 // transform it and add it to the container
142 (*i)->transform_to_dap4(root, container);
143 // Recover the new dap4 version from the container.
144 the_map_array = static_cast<Array *>(container->var((*i)->name()));
145 DBG(cerr << __func__ << "() - Transformed array '" << the_map_array->name() << "' to DAP4 Array ("
146 << (void *)the_map_array << ") added to container: '" << container->name() << "'" << endl;);
147 } else {
148 the_map_array = root_map_array;
149 DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' ("
150 << (void *)the_map_array << ") present in the root group (" << root->name() << ":"
151 << (void *)root << ")" << endl;);
152 }
153 } else {
154 the_map_array = container_map_array;
155 DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' ("
156 << (void *)the_map_array << ") present in the current DAP4 container (" << container->name() << ":"
157 << (void *)container << ")" << endl;);
158 }
159 // We'll use these (below) to make D4Map objects for the coverage
160 d4_map_arrays.push_back(the_map_array);
161 }
162
163 // Adds the coverage array to the container.
164 array_var()->transform_to_dap4(root, container);
165 // Get the new coverage array
166 BaseType *btp = container->var(array_var()->name());
167 Array *coverage = static_cast<Array *>(btp);
168 DBG(cerr << __func__ << "() - Transformed and added DAP4 coverage Array '" << coverage->name()
169 << "' to parent container: '" << container->name() << "'" << endl;);
170
172
173 DBG(cerr << __func__ << "() - " << "Coverage Array '" << coverage->name() << "' attributes: " << endl;
174 XMLWriter xmlw; coverage->get_attr_table().print_dap4(xmlw); cerr << xmlw.get_doc() << endl;);
175
176 // Add the D4Maps
177 vector<Array *>::iterator d4aItr = d4_map_arrays.begin();
178 vector<Array *>::iterator end = d4_map_arrays.end();
179 for (; d4aItr != end; d4aItr++) {
180 Array *the_map_array = *d4aItr;
181 // Here we use the Map Array that we saved the Map
182 // name and Map Array reference for our map.
183 // Removed this line in favor of the following one while re-working the D4Maps design.
184 // jhrg 9/16/22
185 // D4Map *d4_map = new D4Map(the_map_array->FQN(), the_map_array, coverage); // bind the 'map' to the coverage
186 D4Map *d4_map = new D4Map(the_map_array->FQN(), the_map_array);
187 coverage->maps()->add_map(d4_map); // bind the coverage to the map
188 // Clear the vector entry to ensure that ~Array doesn't
189 // get called when the (stack declared) vector goes out of scope.
190 *d4aItr = 0;
191 DBG(cerr << __func__ << "() - Added DAP4 Map Array: '" << d4_map->name() << "' (" << (void *)d4_map->array()
192 << ") to coverage: '" << coverage->name() << "'" << endl;);
193 }
194 DBG(cerr << __func__ << "() - END (grid:" << name() << ")" << endl;);
195}
196
202bool Grid::is_dap2_only_type() { return true; }
203
216void Grid::add_var(BaseType *bt, Part part) {
217 if (!bt)
218 throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
219
220 if (bt->is_dap4())
221 throw Error(string("A method usable only with DAP2 variables was called on a DAP4 variable (")
222 .append(name())
223 .append(")."),
224 __FILE__, __LINE__);
225
226 if (part == array && d_is_array_set /*get_array()*/) {
227 // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
228 throw InternalErr(__FILE__, __LINE__,
229 "Error: Grid::add_var called with part==Array, but the array was already set!");
230 }
231
232 // avoid obvious broken semantics
233 if (!dynamic_cast<Array *>(bt)) {
234 throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
235 }
236
237 // Set to the clone of bt if we get that far.
238 BaseType *bt_clone = 0;
239
240 switch (part) {
241
242 case array: {
243 // Add it as a copy to preserve old semantics. This sets parent too.
244 bt_clone = bt->ptr_duplicate();
245 set_array(static_cast<Array *>(bt_clone));
246 } break;
247
248 case maps: {
249 bt_clone = bt->ptr_duplicate();
250 bt_clone->set_parent(this);
251 d_vars.push_back(bt_clone);
252 } break;
253
254 default: {
255 if (!d_is_array_set ) {
256 // Add it as a copy to preserve old semantics. This sets parent too.
257 bt_clone = bt->ptr_duplicate();
258 set_array(static_cast<Array *>(bt_clone));
259 } else {
260 bt_clone = bt->ptr_duplicate();
261 bt_clone->set_parent(this);
262 d_vars.push_back(bt_clone);
263 }
264 } break;
265 }
266}
267
284 if (!bt)
285 throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
286
287 if (bt->is_dap4())
288 throw Error(string("A method usable only with DAP2 variables was called on a DAP4 variable (")
289 .append(name())
290 .append(")."),
291 __FILE__, __LINE__);
292
293 if (part == array && d_is_array_set /*get_array()*/) {
294 // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
295 throw InternalErr(__FILE__, __LINE__,
296 "Error: Grid::add_var called with part==Array, but the array was already set!");
297 }
298
299 // avoid obvious broken semantics
300 if (!dynamic_cast<Array *>(bt)) {
301 throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
302 }
303
304 bt->set_parent(this);
305
306 switch (part) {
307
308 case array: {
309 // Refactored to use new set_array ([mjohnson 11 nov 2009])
310 set_array(static_cast<Array *>(bt));
311 } break;
312
313 case maps: {
314 // FIXME Why is this commented out?
315 // bt->set_parent(this);
316 d_vars.push_back(bt);
317 } break;
318
319 default: {
320 if (!d_is_array_set ) {
321 // Refactored to use new set_array ([mjohnson 11 nov 2009])
322 // avoid obvious broken semantics
323 set_array(static_cast<Array *>(bt));
324 } else {
325 d_vars.push_back(bt);
326 }
327 } break;
328 }
329}
330
344void Grid::set_array(Array *p_new_arr) {
345 if (!p_new_arr) {
346 throw InternalErr(__FILE__, __LINE__, "Grid::set_array(): Cannot set to null!");
347 }
348
349 // Make sure not same memory, this would be evil.
350 if (p_new_arr == get_array()) {
351 return;
352 }
353
354 p_new_arr->set_parent(this);
355
356 // Three cases: 1. There are no variables set for this grid at all
357 // 2. There are maps but no array
358 // 3. There is already an array set (and maybe maps).
359 // NB: d_array_var is a weak pointer to the Grid's Array
360 if (d_vars.size() == 0) {
361 d_vars.push_back(p_new_arr);
362 } else if (!d_is_array_set ) {
363 d_vars.insert(d_vars.begin(), p_new_arr);
364 } else {
365 // clean out old array
366 delete get_array();
367 d_vars[0] = p_new_arr;
368 }
369
370 d_is_array_set = true;
371}
372
399Array *Grid::add_map(Array *p_new_map, bool add_as_copy) {
400 if (!p_new_map)
401 throw InternalErr(__FILE__, __LINE__, "Grid::add_map(): cannot have p_new_map null!");
402
403 if (add_as_copy)
404 p_new_map = static_cast<Array *>(p_new_map->ptr_duplicate());
405
406 p_new_map->set_parent(this);
407
408 d_vars.push_back(p_new_map);
409
410 // return the one that got put into the Grid.
411 return p_new_map;
412}
413
426Array *Grid::prepend_map(Array *p_new_map, bool add_copy) {
427 if (add_copy) {
428 p_new_map = static_cast<Array *>(p_new_map->ptr_duplicate());
429 }
430
431 p_new_map->set_parent(this);
432 d_vars.insert(map_begin(), p_new_map);
433
434 return p_new_map;
435}
436
440BaseType *Grid::array_var() { return d_is_array_set ? *d_vars.begin() : nullptr; }
441
445Array *Grid::get_array() { return dynamic_cast<Array *>(array_var()); }
446
449 // The maps are stored in the second and subsequent elements of the
450 // d_var vector<BaseType*> of Constructor _unless_ the Array part
451 // has yet to be set. In the latter case, there are only maps in
452 // d_vars
453 return d_is_array_set ? d_vars.begin() + 1 : d_vars.begin();
454}
455
459
462 // see above
463 return d_vars.rbegin();
464}
465
468Grid::Map_riter Grid::map_rend() { return d_is_array_set ? d_vars.rend() - 1 : d_vars.rend(); }
469
473Grid::Map_iter Grid::get_map_iter(int i) { return d_is_array_set ? d_vars.begin() + 1 + i : d_vars.begin() + i; }
474
490int Grid::components(bool constrained) {
491 int comp;
492
493 if (constrained) {
494 comp = get_array()->send_p() ? 1 : 0;
495
496 for (Map_iter i = map_begin(); i != map_end(); i++) {
497 if ((*i)->send_p()) {
498 comp++;
499 }
500 }
501 } else {
502 comp = d_vars.size();
503 }
504
505 return comp;
506}
507
514 DBG(cerr << __func__ << "() - BEGIN " << type_name() << " " << name()
515 << " (at_container:" << at_container->get_name() << ":" << (void *)at_container << ")" << endl;);
516
517 // The variable 'at' should be the attribute table for the Grid
518 AttrTable *at = at_container->get_attr_table(name());
519 if (at) {
520 DBG(cerr << __func__ << "() - Found AttrTable (" << at->get_name() << ":" << (void *)at << ")" << endl;);
521 at->set_is_global_attribute(false);
522
523 // Removing this is left over from a previous version, unknown date.
524 // If the line is added back, some of the DMR round trip tests fail
525 // and the dapreader behavior is changed - tests that build responses
526 // from .dods and .das files fail when they include Grids. jhrg 5/23/18
527 //
528 // See also HYARX-766
529 // array_var()->transfer_attributes(at);
530
531 // If the AttrTable with the name of this Grid (which is also the
532 // name of the Grid's Array) contains a child AttrTable with that
533 // name, mark the attributes as 'not global' and ignore them. This
534 // code has been here for some time; I just added this comment. jhrg 5/23/18
535 AttrTable *dvat = at->get_attr_table(array_var()->name());
536 if (dvat) {
537 dvat->set_is_global_attribute(false);
538 }
539
540 Map_iter map = map_begin();
541 while (map != map_end()) {
542 (*map)->transfer_attributes(at);
543 map++;
544 }
545
546 // Trick: If an attribute that's within the container 'at' still has its
547 // is_global_attribute property set, then it's not really a global attr
548 // but instead an attribute that belongs to this Grid.
549 AttrTable::Attr_iter at_p = at->attr_begin();
550 while (at_p != at->attr_end()) {
551 if (at->is_global_attribute(at_p)) {
552 DBG(cerr << __func__ << "() - " << "Adding unclaimed Attribute (" << at->get_type(at_p) << ":"
553 << at->get_name(at_p) << ":" << (void *)(*map) << ") from AttrTable (" << at->get_name() << ":"
554 << (void *)at << ")" << " to the variable " << type_name() << " " << name() << endl;);
555
556 if (at->get_attr_type(at_p) == Attr_container)
558 else
559 get_attr_table().append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p),
560 (*at_p)->is_utf8_str);
561 }
562
563 at_p++;
564 }
565 } else {
566 DBG(cerr << __func__ << "() - No AttrTable named '" << name() << "' was found in at_container ("
567 << at_container->get_name() << ":" << (void *)at << ")" << endl;);
568 }
569 DBG(cerr << __func__ << "() - END " << type_name() << " " << name() << " (at_container:" << at_container->get_name()
570 << ":" << (void *)at_container << ")" << endl;);
571}
572
573// When projected (using whatever the current constraint provides in the way
574// of a projection), is the object still a Grid?
575
593 // For each dimension in the Array part, check the corresponding Map
594 // vector to make sure it is present in the projected Grid. If for each
595 // projected dimension in the Array component, there is a matching Map
596 // vector, then the Grid is valid.
597 bool valid = true;
598 Array *a = get_array();
599
600 // Don't bother checking if the Array component is not included.
601 if (!a->send_p())
602 return false;
603
604 // If only one part is being sent, it's clearly not a grid (it must be
605 // the array part of the Grid that's being sent (given that the above
606 // test passed and the array is being sent).
607 if (components(true) == 1)
608 return false;
609
610 Array::Dim_iter d = a->dim_begin();
611 Map_iter m = map_begin();
612
613 while (valid && d != a->dim_end() && m != map_end()) {
614 Array &map = dynamic_cast<Array &>(**m);
615 if (a->dimension_size(d, true) && map.send_p()) {
616 // Check the matching Map vector; the Map projection must equal
617 // the Array dimension projection
618 Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
619 valid = map.dimension_start(fd, true) == a->dimension_start(d, true) &&
620 map.dimension_stop(fd, true) == a->dimension_stop(d, true) &&
621 map.dimension_stride(fd, true) == a->dimension_stride(d, true);
622 } else {
623 valid = false;
624 }
625
626 d++, m++;
627 }
628
629 return valid;
630}
631
635 for (Map_iter m = map_begin(); m != map_end(); ++m)
636 dynamic_cast<Array &>(*(*m)).clear_constraint();
637}
638
639void Grid::print_decl(FILE *out, string space, bool print_semi, bool constraint_info, bool constrained) {
640 ostringstream oss;
641 print_decl(oss, space, print_semi, constraint_info, constrained);
642 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
643}
644
645void Grid::print_decl(ostream &out, string space, bool print_semi, bool constraint_info, bool constrained) {
646 if (constrained && !send_p())
647 return;
648
649 // See comment for the FILE* version of this method.
650 if (constrained && !projection_yields_grid()) {
651 out << space << "Structure {\n";
652
653 get_array()->print_decl(out, space + " ", true, constraint_info, constrained);
654
655 for (Map_citer i = map_begin(); i != map_end(); i++) {
656 (*i)->print_decl(out, space + " ", true, constraint_info, constrained);
657 }
658
659 out << space << "} " << id2www(name());
660 } else {
661 // The number of elements in the (projected) Grid must be such that
662 // we have a valid Grid object; send it as such.
663 out << space << type_name() << " {\n";
664
665 out << space << " Array:\n";
666 get_array()->print_decl(out, space + " ", true, constraint_info, constrained);
667
668 out << space << " Maps:\n";
669 for (Map_citer i = map_begin(); i != map_end(); i++) {
670 (*i)->print_decl(out, space + " ", true, constraint_info, constrained);
671 }
672
673 out << space << "} " << id2www(name());
674 }
675
676 if (constraint_info) {
677 if (send_p())
678 out << ": Send True";
679 else
680 out << ": Send False";
681 }
682
683 if (print_semi)
684 out << ";\n";
685
686 return;
687}
688
692void Grid::print_xml(FILE *out, string space, bool constrained) {
693 XMLWriter xml(space);
694 print_xml_writer(xml, constrained);
695 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
696}
697
701void Grid::print_xml(ostream &out, string space, bool constrained) {
702 XMLWriter xml(space);
703 print_xml_writer(xml, constrained);
704 out << xml.get_doc();
705}
706
707void Grid::print_xml_writer(XMLWriter &xml, bool constrained) {
708 if (constrained && !send_p())
709 return;
710
711 if (constrained && !projection_yields_grid()) {
712 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"Structure") < 0)
713 throw InternalErr(__FILE__, __LINE__, "Could not write Structure element");
714
715 if (!name().empty() &&
716 xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"name", (const xmlChar *)name().c_str()) < 0)
717 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
718
720
721 get_array()->print_xml_writer(xml, constrained);
722
723 // Cannot easily use the range-based for loop here because the same container is
724 // used for the Grid Array and its Maps. jhrg 7/19/24
725 for (auto m = map_begin(); m != map_end(); ++m) {
726 auto a = dynamic_cast<Array *>(*m);
727 if (!a)
728 throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
729 a->print_xml_writer_core(xml, constrained, "Array");
730 }
731
732 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
733 throw InternalErr(__FILE__, __LINE__, "Could not end Structure element");
734 } else {
735 // The number of elements in the (projected) Grid must be such that
736 // we have a valid Grid object; send it as such.
737 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"Grid") < 0)
738 throw InternalErr(__FILE__, __LINE__, "Could not write Grid element");
739
740 if (!name().empty())
741 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"name",
742 (const xmlChar *)name().c_str()) < 0)
743 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
744
746
747 get_array()->print_xml_writer(xml, constrained);
748
749 // Cannot easily use the range-based for loop here because the same container is
750 // used for the Grid Array and its Maps. jhrg 7/19/24
751 for (auto m = map_begin(); m != map_end(); ++m) {
752 auto a = dynamic_cast<Array *>(*m);
753 if (!a)
754 throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
755 a->print_xml_writer_core(xml, constrained, "Map");
756 }
757
758 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
759 throw InternalErr(__FILE__, __LINE__, "Could not end Grid element");
760 }
761}
762
763void Grid::print_val(FILE *out, string space, bool print_decl_p) {
764 ostringstream oss;
765 print_val(oss, space, print_decl_p);
766 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
767}
768
769void Grid::print_val(ostream &out, string space, bool print_decl_p) {
770 if (print_decl_p) {
771 print_decl(out, space, false);
772 out << " = ";
773 }
774
775 // If we are printing a value on the client-side, projection_yields_grid
776 // should not be called since we don't *have* a projection without a
777 // Constraint. I think that if we are here and send_p() is not true, then
778 // the value of this function should be ignored. 4/6/2000 jhrg
779 bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
780 if (pyg || !send_p())
781 out << "{ Array: ";
782 else
783 out << "{";
784
785 get_array()->print_val(out, "", false);
786
787 if (pyg || !send_p())
788 out << " Maps: ";
789
790 for (Map_citer i = map_begin(); i != map_end(); i++, (void)(i != map_end() && out << ", ")) {
791 (*i)->print_val(out, "", false);
792 }
793
794 out << " }";
795
796 if (print_decl_p)
797 out << ";\n";
798}
799
800// Grids have ugly semantics.
801
806bool Grid::check_semantics(string &msg, bool all) {
808 return false;
809
810 msg = "";
811
812 if (!get_array()) {
813 msg += "Null grid base array in `" + name() + "'\n";
814 return false;
815 }
816
817 // Is it an array?
818 if (get_array()->type() != dods_array_c) {
819 msg += "Grid `" + name() + "'s' member `" + get_array()->name() + "' must be an array\n";
820 return false;
821 }
822
823 Array *av = (Array *)get_array(); // past test above, must be an array
824
825 // Array must be of a simple_type.
826 if (!av->var()->is_simple_type()) {
827 msg += "The field variable `" + this->name() +
828 "' must be an array of simple type elements (e.g., int32, String)\n";
829 return false;
830 }
831
832 // enough maps?
833 if ((unsigned)d_vars.size() - 1 != av->dimensions()) {
834 msg +=
835 "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
836 msg += av->name() + "'\n";
837 return false;
838 }
839
840 const string array_var_name = av->name();
841 Array::Dim_iter asi = av->dim_begin();
842 for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++, asi++) {
843
844 BaseType *mv = *mvi;
845
846 // check names
847 if (array_var_name == mv->name()) {
848 msg +=
849 "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
850 return false;
851 }
852 // check types
853 if (mv->type() != dods_array_c) {
854 msg += "Grid map variable `" + mv->name() + "' is not an array\n";
855 return false;
856 }
857
858 Array *mv_a = (Array *)mv; // downcast to (Array *)
859
860 // Array must be of a simple_type.
861 if (!mv_a->var()->is_simple_type()) {
862 msg += "The field variable `" + this->name() +
863 "' must be an array of simple type elements (e.g., int32, String)\n";
864 return false;
865 }
866
867 // check shape
868 if (mv_a->dimensions() != 1) { // maps must have one dimension
869 msg += "Grid map variable `" + mv_a->name() + "' must be only one dimension\n";
870 return false;
871 }
872 // size of map must match corresponding array dimension
873 Array::Dim_iter mv_asi = mv_a->dim_begin();
874 int mv_a_size = mv_a->dimension_size(mv_asi);
875 int av_size = av->dimension_size(asi);
876 if (mv_a_size != av_size) {
877 msg += "Grid map variable `" + mv_a->name() + "'s' size does not match the size of array variable '";
878 msg += get_array()->name() + "'s' cooresponding dimension\n";
879 return false;
880 }
881 }
882
883 if (all) {
884 if (!get_array()->check_semantics(msg, true))
885 return false;
886 for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++) {
887 if (!(*mvi)->check_semantics(msg, true)) {
888 return false;
889 }
890 }
891 }
892
893 return true;
894}
895
904void Grid::dump(ostream &strm) const {
905 strm << DapIndent::LMarg << "Grid::dump - (" << (void *)this << ")" << endl;
907 Constructor::dump(strm);
908
910}
911
912} // namespace libdap
A multidimensional array of identical data types.
Definition Array.h:121
virtual int dimension_start(Dim_iter i, bool constrained=false)
Return the start index of a dimension.
Definition Array.cc:761
virtual void clear_constraint()
Clears the projection; add each projected dimension explicitly using add_constraint.
Definition Array.cc:571
Dim_iter dim_end()
Definition Array.cc:692
virtual int dimension_stop(Dim_iter i, bool constrained=false)
Return the stop index of the constraint.
Definition Array.cc:786
void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false) override
Prints a DDS entry for the Array.
Definition Array.cc:981
void print_val(ostream &out, string space="", bool print_decl_p=true) override
Prints the value of the variable.
Definition Array.cc:1187
BaseType * ptr_duplicate() override
Definition Array.cc:153
std::vector< dimension >::iterator Dim_iter
Definition Array.h:225
virtual D4Maps * maps()
Definition Array.cc:860
virtual int dimension_size(Dim_iter i, bool constrained=false)
Returns the size of the dimension.
Definition Array.cc:723
void print_xml_writer(XMLWriter &xml, bool constrained=false) override
Definition Array.cc:1059
Dim_iter dim_begin()
Definition Array.cc:689
virtual unsigned int dimensions(bool constrained=false)
Return the total number of dimensions in the array.
Definition Array.cc:704
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:150
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition AttrTable.cc:517
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition AttrTable.cc:699
virtual Attr_iter attr_end()
Definition AttrTable.cc:798
virtual string get_type(const string &name)
Get the type name of an attribute within this attribute table.
Definition AttrTable.cc:702
virtual bool is_global_attribute() const
Definition AttrTable.h:300
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition AttrTable.cc:738
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition AttrTable.cc:308
virtual Attr_iter attr_begin()
Definition AttrTable.cc:793
void print_dap4(XMLWriter &xml)
virtual string get_name() const
Get the name of this attribute table.
Definition AttrTable.cc:243
virtual void set_is_global_attribute(bool ga)
Definition AttrTable.h:301
void print_xml_writer(XMLWriter &xml)
std::vector< entry * >::iterator Attr_iter
Definition AttrTable.h:258
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition AttrTable.cc:709
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:335
virtual AttrTable & get_attr_table()
Definition BaseType.cc:498
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:296
virtual void set_parent(BaseType *parent)
Definition BaseType.cc:622
virtual bool is_dap4() const
Definition BaseType.h:181
virtual D4Attributes * attributes()
Definition BaseType.cc:507
virtual std::string FQN() const
Definition BaseType.cc:304
virtual bool send_p()
Should this variable be sent?
Definition BaseType.cc:478
virtual bool is_simple_type() const
Returns true if the instance is a numeric, string or URL type variable.
Definition BaseType.cc:347
virtual BaseType * ptr_duplicate()=0
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition BaseType.cc:200
virtual bool check_semantics(string &msg, bool all=false)
Compare an object's current state with the semantics of its type.
Definition BaseType.cc:1056
virtual Type type() const
Returns the type of the class instance.
Definition BaseType.cc:329
BaseType * var(const string &name, bool exact_match=true, btp_stack *s=nullptr) override
btp_stack no longer needed; use back pointers (BaseType::get_parent())
std::vector< BaseType * > d_vars
Definition Constructor.h:47
Constructor & operator=(const Constructor &rhs)
Definition Constructor.h:70
Constructor(const string &name, const Type &type, bool is_dap4=false)
Definition Constructor.h:52
void dump(ostream &strm) const override
dumps information about this object
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
Array * array(D4Group *root)
This will always return the correct pointer for a valid data set.
Definition D4Maps.cc:36
const string & name() const
Definition D4Maps.h:88
void add_map(D4Map *map)
Definition D4Maps.h:156
static ostream & LMarg(ostream &strm)
Definition DapIndent.cc:61
static void Indent()
Definition DapIndent.cc:44
static void UnIndent()
Definition DapIndent.cc:46
A class for error processing.
Definition Error.h:92
virtual BaseType * ptr_duplicate()
Definition Grid.cc:96
std::vector< BaseType * >::const_iterator Map_citer
Definition Grid.h:135
BaseType * array_var()
Returns the Grid Array.
Definition Grid.cc:440
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition Grid.cc:109
virtual void print_xml(ostream &out, string space=" ", bool constrained=false)
Definition Grid.cc:701
Map_iter map_begin()
Returns an iterator referencing the first Map vector.
Definition Grid.cc:448
Map_iter get_map_iter(int i)
Definition Grid.cc:473
virtual void set_array(Array *p_new_arr)
Definition Grid.cc:344
virtual void clear_constraint()
Definition Grid.cc:633
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition Grid.cc:769
virtual void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Print an ASCII representation of the variable structure.
Definition Grid.cc:645
virtual Array * prepend_map(Array *p_new_map, bool add_copy)
Definition Grid.cc:426
std::vector< BaseType * >::reverse_iterator Map_riter
Definition Grid.h:137
virtual ~Grid()
Definition Grid.cc:92
Grid(const string &n)
The Grid constructor.
Definition Grid.cc:74
void m_duplicate(const Grid &s)
Definition Grid.cc:63
std::vector< BaseType * >::iterator Map_iter
Definition Grid.h:136
Array * get_array()
Returns the Grid Array. This method returns the array using an Array*, so no cast is required.
Definition Grid.cc:445
virtual void transfer_attributes(AttrTable *at_container)
Definition Grid.cc:513
virtual bool projection_yields_grid()
Definition Grid.cc:592
Map_iter map_end()
Definition Grid.cc:458
Map_riter map_rend()
Definition Grid.cc:468
virtual void dump(ostream &strm) const
dumps information about this object
Definition Grid.cc:904
virtual Array * add_map(Array *p_new_map, bool add_copy)
Definition Grid.cc:399
virtual int components(bool constrained=false)
Returns the number of components in the Grid object.
Definition Grid.cc:490
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition Grid.cc:707
virtual bool check_semantics(string &msg, bool all=false)
Return true if this Grid is well formed.
Definition Grid.cc:806
virtual void add_var(BaseType *bt, Part part)
Definition Grid.cc:216
Grid & operator=(const Grid &rhs)
Definition Grid.cc:98
virtual void add_var_nocopy(BaseType *bt, Part part)
Definition Grid.cc:283
Map_riter map_rbegin()
Returns an iterator referencing the first Map vector.
Definition Grid.cc:461
virtual bool is_dap2_only_type()
Definition Grid.cc:202
A class for software fault reporting.
Definition InternalErr.h:61
BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=nullptr) override
Definition Vector.cc:469
unsigned int get_doc_size()
Definition XMLWriter.cc:123
const char * get_doc()
Definition XMLWriter.cc:104
xmlTextWriterPtr get_writer() const
Definition XMLWriter.h:55
STL iterator class.
#define DBG(x)
Definition debug.h:58
top level DAP object to house generic methods
Definition AISConnect.cc:30
@ dods_grid_c
Definition Type.h:111
@ dods_array_c
Definition Type.h:107
Part
Names the parts of multi-section constructor data types.
Definition Type.h:48
@ maps
Definition Type.h:51
@ array
Definition Type.h:50
@ Attr_container
Definition AttrTable.h:80
string id2www(string in, const string &allowable)
Definition escaping.cc:143