libdap Updated for version 3.20.11
libdap4 is an implementation of OPeNDAP's DAP protocol.
Grid.cc
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 <sstream>
39#include <functional>
40#include <algorithm>
41
42#include "Grid.h"
43#include "DDS.h"
44#include "Array.h" // for downcasts
45#include "util.h"
46#include "InternalErr.h"
47#include "escaping.h"
48#include "XDRStreamMarshaller.h"
49#include "debug.h"
50
51#include "XMLWriter.h"
52#include "DMR.h"
53#include "D4Group.h"
54#include "D4Maps.h"
55#include "D4Attributes.h"
56
57#include "DapIndent.h"
58
59using namespace std;
60
61namespace libdap {
62
63void
64Grid::m_duplicate(const Grid &s)
65{
66 d_is_array_set = s.d_is_array_set;
67}
68
78Grid::Grid(const string &n) : Constructor(n, dods_grid_c), d_is_array_set(false)
79{}
80
92Grid::Grid(const string &n, const string &d)
93 : Constructor(n, d, dods_grid_c), d_is_array_set(false)
94{}
95
97Grid::Grid(const Grid &rhs) : Constructor(rhs)
98{
99 m_duplicate(rhs);
100}
101
102Grid::~Grid()
103{
104 //d_array_var = 0; // Weak pointer; object will be freed by Constructor
105}
106
107BaseType *
109{
110 return new Grid(*this);
111}
112
113Grid &
114Grid::operator=(const Grid &rhs)
115{
116 if (this == &rhs)
117 return *this;
118 Constructor::operator=(rhs);
119 m_duplicate(rhs);
120 return *this;
121}
122
126void
128{
129 DBG(cerr << __func__ << "() - BEGIN (name:"<< name() <<
130 ")(type:"<< type_name()<<
131 ")(root:'"<< root->name()<<"':"<<(void*)root <<
132 ")(container:'"<< container->name()<<"':"<< (void *) container<< ")"
133 << endl;);
134
135 vector<Array*> d4_map_arrays;
136
137 // We do the Map Arrays first because some people expect to see them
138 // declared prior to the coverage array the utilizes them - even though that
139 // is not a requirement of DAP4 I did it here to make people happier.
140 // We add the maps arrays to the current container if needed and make a
141 // vector of them so that we can add D4Map objects to our Precious down
142 // below.
143 for (Map_iter i = map_begin(), e = map_end(); i != e; ++i) {
144 DBG(cerr << __func__ << "() - Processing Map Array: '"<< (*i)->name() << "' ("<< (void *)(*i)<< ")" << endl;);
145 // Only add the map/array if it's not already present in the target DAP2 container.
146 // Given the scoping rules for DAP2 and the assumption the DDS is valid, testing for
147 // the same name is good enough. The point here is to be sure to only use the
148 // existing maps. This is an important issue when there are multiple Grids in the same
149 // dataset that utilize the same Map arrays data.
150 Array *the_map_array;
151 Array *container_map_array = static_cast<Array*>(container->var((*i)->name()));
152 if(!container_map_array){
153 DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the current DAP4 container ("<<container->name()<< ":"<<(void*)container<< "). Let's fix that..." << endl;);
154 // Not in the container, so we check root group
155 Array *root_map_array = static_cast<Array*>(root->var((*i)->name()));
156 if (!root_map_array) {
157 // Not in the root group so we transform a new array and add it to container.
158 DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the root Group ("<<root->name()<< ":"<<(void*)root<< "). Let's fix that..." << endl;);
159 // transform it and add it to the container
160 (*i)->transform_to_dap4(root, container);
161 // Recover the new dap4 version from the container.
162 the_map_array = static_cast<Array*>(container->var((*i)->name()));
163 DBG(cerr << __func__ << "() - Transformed array '"<< the_map_array->name() <<
164 "' to DAP4 Array (" << (void *) the_map_array << ") added to container: '"<<
165 container->name() <<"'" << endl;);
166 }
167 else {
168 the_map_array = root_map_array;
169 DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' (" <<
170 (void *) the_map_array << ") present in the root group ("<<root->name()<< ":"<<(void*)root <<
171 ")"<< endl;);
172 }
173 }
174 else {
175 the_map_array = container_map_array;
176 DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' (" <<
177 (void *) the_map_array << ") present in the current DAP4 container ("<<container->name( )<< ":"<<
178 (void*)container<< ")" << endl;);
179 }
180 // We'll use these (below) to make D4Map objects for the coverage
181 d4_map_arrays.push_back(the_map_array);
182 }
183
184 // Adds the coverage array to the container.
185 array_var()->transform_to_dap4(root, container);
186 // Get the new coverage array
187 BaseType *btp = container->var(array_var()->name());
188 Array *coverage = static_cast<Array*>(btp);
189 DBG(cerr << __func__ << "() - Transformed and added DAP4 coverage Array '"<< coverage->name() <<
190 "' to parent container: '" << container->name() << "'" << endl;);
191
193
194 DBG(cerr << __func__ << "() - " << "Coverage Array '"<< coverage->name() << "' attributes: " << endl;
195 XMLWriter xmlw;
196 coverage->get_attr_table().print_dap4(xmlw);
197 cerr << xmlw.get_doc() << endl;);
198
199 // Add the D4Maps
200 vector<Array*>::iterator d4aItr=d4_map_arrays.begin();
201 vector<Array*>::iterator end=d4_map_arrays.end();
202 for( ; d4aItr!=end ; d4aItr++){
203 Array *the_map_array = *d4aItr;
204 // Here we use the Map Array that we saved the Map
205 // name and Map Array reference for our map.
206 D4Map *d4_map = new D4Map(the_map_array->FQN(), the_map_array, coverage); // bind the 'map' to the coverage
207 coverage->maps()->add_map(d4_map); // bind the coverage to the map
208 // Clear the vector entry to ensure that ~Array doesn't
209 // get called when the (stack declared) vector goes out of scope.
210 *d4aItr = 0;
211 DBG(cerr << __func__ << "() - Added DAP4 Map Array: '"<< d4_map->name() <<
212 "' (" << (void *) d4_map->array() << ") to coverage: '" << coverage->name() << "'" << endl;);
213
214 }
215 DBG(cerr << __func__ << "() - END (grid:" << name() << ")" << endl;);
216}
217
218
224bool
226{
227 return true;
228}
229
242void
244{
245 if (!bt)
246 throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
247
248 if (part == array && d_is_array_set/*get_array()*/) {
249 // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
250 throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
251 }
252
253 // avoid obvious broken semantics
254 if (!dynamic_cast<Array*>(bt)) {
255 throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
256 }
257
258 // Set to the clone of bt if we get that far.
259 BaseType* bt_clone = 0;
260
261 switch (part) {
262
263 case array: {
264 // Add it as a copy to preserve old semantics. This sets parent too.
265 bt_clone = bt->ptr_duplicate();
266 set_array(static_cast<Array*>(bt_clone));
267 }
268 break;
269
270 case maps: {
271 bt_clone = bt->ptr_duplicate();
272 bt_clone->set_parent(this);
273 d_vars.push_back(bt_clone);
274 }
275 break;
276
277 default: {
278 if (!d_is_array_set) {
279 // Add it as a copy to preserve old semantics. This sets parent too.
280 bt_clone = bt->ptr_duplicate();
281 set_array(static_cast<Array*>(bt_clone));
282 }
283 else {
284 bt_clone = bt->ptr_duplicate();
285 bt_clone->set_parent(this);
286 d_vars.push_back(bt_clone);
287 }
288 }
289 break;
290 }
291}
292
308void
310{
311 if (!bt)
312 throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
313
314 if (part == array && d_is_array_set/*get_array()*/) {
315 // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
316 throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
317 }
318
319 // avoid obvious broken semantics
320 if (!dynamic_cast<Array*>(bt)) {
321 throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
322 }
323
324 bt->set_parent(this);
325
326 switch (part) {
327
328 case array: {
329 // Refactored to use new set_array ([mjohnson 11 nov 2009])
330 set_array(static_cast<Array*>(bt));
331 }
332 break;
333
334 case maps: {
335 // FIXME Why is this commented out?
336 //bt->set_parent(this);
337 d_vars.push_back(bt);
338 }
339 break;
340
341 default: {
342 if (!d_is_array_set) {
343 // Refactored to use new set_array ([mjohnson 11 nov 2009])
344 // avoid obvious broken semantics
345 set_array(static_cast<Array*>(bt));
346 }
347 else {
348 d_vars.push_back(bt);
349 }
350 }
351 break;
352 }
353}
354
368void Grid::set_array(Array* p_new_arr)
369{
370 if (!p_new_arr) {
371 throw InternalErr(__FILE__, __LINE__, "Grid::set_array(): Cannot set to null!");
372 }
373
374 // Make sure not same memory, this would be evil.
375 if (p_new_arr == get_array()) {
376 return;
377 }
378
379 p_new_arr->set_parent(this);
380
381 // Three cases: 1. There are no variables set for this grid at all
382 // 2. There are maps but no array
383 // 3. There is already an array set (and maybe maps).
384 // NB: d_array_var is a weak pointer to the Grid's Array
385 if (d_vars.size() == 0) {
386 d_vars.push_back(p_new_arr);
387 }
388 else if (!d_is_array_set) {
389 d_vars.insert(d_vars.begin(), p_new_arr);
390 }
391 else {
392 // clean out old array
393 delete get_array();
394 d_vars[0] = p_new_arr;
395 }
396
397 d_is_array_set = true;
398#if 0
399 // store the array pointer locally
400 d_array_var = p_new_arr;
401
402 // Set the parent
403 d_array_var->set_parent(this);
404#endif
405}
406
433Array*
434Grid::add_map(Array* p_new_map, bool add_as_copy)
435{
436 if (!p_new_map)
437 throw InternalErr(__FILE__, __LINE__, "Grid::add_map(): cannot have p_new_map null!");
438
439 if (add_as_copy)
440 p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
441
442 p_new_map->set_parent(this);
443
444 d_vars.push_back(p_new_map);
445
446 // return the one that got put into the Grid.
447 return p_new_map;
448}
449
462Array*
463Grid::prepend_map(Array* p_new_map, bool add_copy)
464{
465 if (add_copy)
466 {
467 p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
468 }
469
470 p_new_map->set_parent(this);
471 d_vars.insert(map_begin(), p_new_map);
472
473 return p_new_map;
474}
475
479BaseType *
481{
482 return d_is_array_set ? *d_vars.begin() : nullptr;
483}
484
488Array *
490{
491 return dynamic_cast<Array*>(array_var());
492}
493
495Grid::Map_iter
497{
498 // The maps are stored in the second and subsequent elements of the
499 // d_var vector<BaseType*> of Constructor _unless_ the Array part
500 // has yet to be set. In the latter case, there are only maps in
501 // d_vars
502 return d_is_array_set ? d_vars.begin() + 1: d_vars.begin();
503}
504
507Grid::Map_iter
509{
510 return d_vars.end();
511}
512
514Grid::Map_riter
516{
517 // see above
518 return d_vars.rbegin();
519}
520
523Grid::Map_riter
525{
526 return d_is_array_set ? d_vars.rend() - 1: d_vars.rend();
527}
528
532Grid::Map_iter
534{
535 return d_is_array_set ? d_vars.begin() + 1 + i : d_vars.begin() + i;
536}
537
553int
554Grid::components(bool constrained)
555{
556 int comp;
557
558 if (constrained) {
559 comp = get_array()->send_p() ? 1 : 0;
560
561 for (Map_iter i = map_begin(); i != map_end(); i++) {
562 if ((*i)->send_p()) {
563 comp++;
564 }
565 }
566 }
567 else {
568 comp = d_vars.size();
569 }
570
571 return comp;
572}
573
580{
581 DBG( cerr << __func__ << "() - BEGIN "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
582
583 // The variable 'at' should be the attribute table for the Grid
584 AttrTable *at = at_container->get_attr_table(name());
585 if (at) {
586 DBG( cerr << __func__ << "() - Found AttrTable ("<< at->get_name() << ":" << (void*)at<< ")" << endl;);
587 at->set_is_global_attribute(false);
588
589#if 0
590 // Removing this is left over from a previous version, unknown date.
591 // If the line is added back, some of the DMR round trip tests fail
592 // and the dapreader behavior is changed - tests that build responses
593 // from .dods and .das files fail when they include Grids. jhrg 5/23/18
594 //
595 // See also HYARX-766
597#endif
598
599 // If the AttrTable with the name of this Grid (which is also the
600 // name of the Grid's Array) contains a child AttrTable with that
601 // name, mark the attributes as 'not global' and ignore them. This
602 // code has been here for some time; I just added this comment. jhrg 5/23/18
603 AttrTable *dvat = at->get_attr_table(array_var()->name());
604 if (dvat) {
605 dvat->set_is_global_attribute(false);
606 }
607
608 Map_iter map = map_begin();
609 while (map != map_end()) {
610 (*map)->transfer_attributes(at);
611 map++;
612 }
613
614 // Trick: If an attribute that's within the container 'at' still has its
615 // is_global_attribute property set, then it's not really a global attr
616 // but instead an attribute that belongs to this Grid.
617 AttrTable::Attr_iter at_p = at->attr_begin();
618 while (at_p != at->attr_end()) {
619 if (at->is_global_attribute(at_p)) {
620 DBG( cerr << __func__ << "() - " <<
621 "Adding unclaimed Attribute ("<<
622 at->get_type(at_p)<< ":" << at->get_name(at_p) << ":" << (void*)(*map)<<
623 ") from AttrTable (" << at->get_name() << ":" << (void*)at << ")" <<
624 " to the variable " << type_name() << " " << name() << endl;);
625
626 if (at->get_attr_type(at_p) == Attr_container)
628 else
629 get_attr_table().append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p));
630 }
631
632 at_p++;
633 }
634 }
635 else {
636 DBG( cerr << __func__ << "() - No AttrTable named '"<< name() << "' was found in at_container ("<<at_container->get_name()<<":" << (void*)at<< ")" << endl;);
637 }
638 DBG( cerr << __func__ << "() - END "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
639}
640
641// When projected (using whatever the current constraint provides in the way
642// of a projection), is the object still a Grid?
643
660bool
662{
663 // For each dimension in the Array part, check the corresponding Map
664 // vector to make sure it is present in the projected Grid. If for each
665 // projected dimension in the Array component, there is a matching Map
666 // vector, then the Grid is valid.
667 bool valid = true;
668 Array *a = get_array();
669
670 // Don't bother checking if the Array component is not included.
671 if (!a->send_p())
672 return false;
673
674 // If only one part is being sent, it's clearly not a grid (it must be
675 // the array part of the Grid that's being sent (given that the above
676 // test passed and the array is being sent).
677 if (components(true) == 1)
678 return false;
679
680 Array::Dim_iter d = a->dim_begin() ;
681 Map_iter m = map_begin() ;
682
683 while (valid && d != a->dim_end() && m != map_end()) {
684 Array &map = dynamic_cast<Array&>(**m);
685 if (a->dimension_size(d, true) && map.send_p()) {
686 // Check the matching Map vector; the Map projection must equal
687 // the Array dimension projection
688 Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
689 valid = map.dimension_start(fd, true) == a->dimension_start(d, true)
690 && map.dimension_stop(fd, true) == a->dimension_stop(d, true)
691 && map.dimension_stride(fd, true) == a->dimension_stride(d, true);
692 }
693 else {
694 valid = false;
695 }
696
697 d++, m++;
698 }
699
700 return valid;
701}
702
704void
706{
708 for (Map_iter m = map_begin(); m != map_end(); ++m)
709 dynamic_cast<Array&>(*(*m)).clear_constraint();
710}
711
712void
713Grid::print_decl(FILE *out, string space, bool print_semi,
714 bool constraint_info, bool constrained)
715{
716 ostringstream oss;
717 print_decl(oss, space, print_semi, constraint_info, constrained);
718 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
719}
720
721void
722Grid::print_decl(ostream &out, string space, bool print_semi,
723 bool constraint_info, bool constrained)
724{
725 if (constrained && !send_p())
726 return;
727
728 // See comment for the FILE* version of this method.
729 if (constrained && !projection_yields_grid()) {
730 out << space << "Structure {\n" ;
731
732 get_array()->print_decl(out, space + " ", true, constraint_info,
733 constrained);
734
735 for (Map_citer i = map_begin(); i != map_end(); i++) {
736 (*i)->print_decl(out, space + " ", true,
737 constraint_info, constrained);
738 }
739
740 out << space << "} " << id2www(name()) ;
741 }
742 else {
743 // The number of elements in the (projected) Grid must be such that
744 // we have a valid Grid object; send it as such.
745 out << space << type_name() << " {\n" ;
746
747 out << space << " Array:\n" ;
748 get_array()->print_decl(out, space + " ", true, constraint_info,
749 constrained);
750
751 out << space << " Maps:\n" ;
752 for (Map_citer i = map_begin(); i != map_end(); i++) {
753 (*i)->print_decl(out, space + " ", true,
754 constraint_info, constrained);
755 }
756
757 out << space << "} " << id2www(name()) ;
758 }
759
760 if (constraint_info) {
761 if (send_p())
762 out << ": Send True";
763 else
764 out << ": Send False";
765 }
766
767 if (print_semi)
768 out << ";\n" ;
769
770 return;
771}
772
776void
777Grid::print_xml(FILE *out, string space, bool constrained)
778{
779 XMLWriter xml(space);
780 print_xml_writer(xml, constrained);
781 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
782}
783
787void
788Grid::print_xml(ostream &out, string space, bool constrained)
789{
790 XMLWriter xml(space);
791 print_xml_writer(xml, constrained);
792 out << xml.get_doc();
793}
794
795
796class PrintGridFieldXMLWriter : public unary_function<BaseType *, void>
797{
798 XMLWriter &d_xml;
799 bool d_constrained;
800 string d_tag;
801public:
802 PrintGridFieldXMLWriter(XMLWriter &x, bool c, const string &t = "Map")
803 : d_xml(x), d_constrained(c), d_tag(t)
804 {}
805
806 void operator()(BaseType *btp)
807 {
808 Array *a = dynamic_cast<Array*>(btp);
809 if (!a)
810 throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
811 a->print_xml_writer_core(d_xml, d_constrained, d_tag);
812 }
813};
814
815void
816Grid::print_xml_writer(XMLWriter &xml, bool constrained)
817{
818 if (constrained && !send_p())
819 return;
820
821 if (constrained && !projection_yields_grid()) {
822 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Structure") < 0)
823 throw InternalErr(__FILE__, __LINE__, "Could not write Structure element");
824
825 if (!name().empty())
826 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
827 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
828
830
831 get_array()->print_xml_writer(xml, constrained);
832
833 for_each(map_begin(), map_end(),
834 PrintGridFieldXMLWriter(xml, constrained, "Array"));
835
836 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
837 throw InternalErr(__FILE__, __LINE__, "Could not end Structure element");
838 }
839 else {
840 // The number of elements in the (projected) Grid must be such that
841 // we have a valid Grid object; send it as such.
842 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Grid") < 0)
843 throw InternalErr(__FILE__, __LINE__, "Could not write Grid element");
844
845 if (!name().empty())
846 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
847 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
848
850
851 get_array()->print_xml_writer(xml, constrained);
852
853 for_each(map_begin(), map_end(),
854 PrintGridFieldXMLWriter(xml, constrained, "Map"));
855
856 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
857 throw InternalErr(__FILE__, __LINE__, "Could not end Grid element");
858 }
859}
860
861void
862Grid::print_val(FILE *out, string space, bool print_decl_p)
863{
864 ostringstream oss;
865 print_val(oss, space, print_decl_p);
866 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
867}
868
869void Grid::print_val(ostream &out, string space, bool print_decl_p)
870{
871 if (print_decl_p) {
872 print_decl(out, space, false);
873 out << " = ";
874 }
875
876 // If we are printing a value on the client-side, projection_yields_grid
877 // should not be called since we don't *have* a projection without a
878 // Constraint. I think that if we are here and send_p() is not true, then
879 // the value of this function should be ignored. 4/6/2000 jhrg
880 bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
881 if (pyg || !send_p())
882 out << "{ Array: ";
883 else
884 out << "{";
885
886 get_array()->print_val(out, "", false);
887
888 if (pyg || !send_p()) out << " Maps: ";
889
890 for (Map_citer i = map_begin(); i != map_end(); i++, (void) (i != map_end() && out << ", ")) {
891 (*i)->print_val(out, "", false);
892 }
893
894 out << " }";
895
896 if (print_decl_p) out << ";\n";
897}
898
899// Grids have ugly semantics.
900
905bool
906Grid::check_semantics(string &msg, bool all)
907{
909 return false;
910
911 msg = "";
912
913 if (!get_array()) {
914 msg += "Null grid base array in `" + name() + "'\n";
915 return false;
916 }
917
918 // Is it an array?
919 if (get_array()->type() != dods_array_c) {
920 msg += "Grid `" + name() + "'s' member `" + get_array()->name() + "' must be an array\n";
921 return false;
922 }
923
924 Array *av = (Array *)get_array(); // past test above, must be an array
925
926 // Array must be of a simple_type.
927 if (!av->var()->is_simple_type()) {
928 msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
929 return false;
930 }
931
932 // enough maps?
933 if ((unsigned)d_vars.size()-1 != av->dimensions()) {
934 msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
935 msg += av->name() + "'\n";
936 return false;
937 }
938
939 const string array_var_name = av->name();
940 Array::Dim_iter asi = av->dim_begin() ;
941 for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++, asi++) {
942
943 BaseType *mv = *mvi;
944
945 // check names
946 if (array_var_name == mv->name()) {
947 msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
948 return false;
949 }
950 // check types
951 if (mv->type() != dods_array_c) {
952 msg += "Grid map variable `" + mv->name() + "' is not an array\n";
953 return false;
954 }
955
956 Array *mv_a = (Array *)mv; // downcast to (Array *)
957
958 // Array must be of a simple_type.
959 if (!mv_a->var()->is_simple_type()) {
960 msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
961 return false;
962 }
963
964 // check shape
965 if (mv_a->dimensions() != 1) {// maps must have one dimension
966 msg += "Grid map variable `" + mv_a->name() + "' must be only one dimension\n";
967 return false;
968 }
969 // size of map must match corresponding array dimension
970 Array::Dim_iter mv_asi = mv_a->dim_begin() ;
971 int mv_a_size = mv_a->dimension_size(mv_asi) ;
972 int av_size = av->dimension_size(asi) ;
973 if (mv_a_size != av_size) {
974 msg += "Grid map variable `" + mv_a->name() + "'s' size does not match the size of array variable '";
975 msg += get_array()->name() + "'s' cooresponding dimension\n";
976 return false;
977 }
978 }
979
980 if (all) {
981 if (!get_array()->check_semantics(msg, true))
982 return false;
983 for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++) {
984 if (!(*mvi)->check_semantics(msg, true)) {
985 return false;
986 }
987 }
988 }
989
990 return true;
991}
992
1001void
1002Grid::dump(ostream &strm) const
1003{
1004 strm << DapIndent::LMarg << "Grid::dump - ("
1005 << (void *)this << ")" << endl ;
1006 DapIndent::Indent() ;
1007 Constructor::dump(strm) ;
1008
1009 DapIndent::UnIndent() ;
1010}
1011
1012} // namespace libdap
1013
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
Dim_iter dim_end()
Definition: Array.cc:687
virtual BaseType * ptr_duplicate()
Definition: Array.cc:169
virtual int dimension_stop(Dim_iter i, bool constrained=false)
Return the stop index of the constraint.
Definition: Array.cc:779
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
std::vector< dimension >::iterator Dim_iter
Definition: Array.h:206
virtual int dimension_size(Dim_iter i, bool constrained=false)
Returns the size of the dimension.
Definition: Array.cc:724
Dim_iter dim_begin()
Definition: Array.cc:681
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 AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition: AttrTable.cc:607
virtual Attr_iter attr_end()
Definition: AttrTable.cc:719
virtual string get_type(const string &name)
Get the type name of an attribute within this attribute table.
Definition: AttrTable.cc:613
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition: AttrTable.cc:653
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition: AttrTable.cc:307
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:711
void print_dap4(XMLWriter &xml)
Definition: AttrTable.cc:1498
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 AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition: AttrTable.cc:621
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 set_parent(BaseType *parent)
Definition: BaseType.cc:729
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 is_simple_type() const
Returns true if the instance is a numeric, string or URL type variable.
Definition: BaseType.cc:389
virtual BaseType * ptr_duplicate()=0
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: BaseType.cc:212
virtual void transfer_attributes(AttrTable *at)
Definition: BaseType.cc:640
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
virtual Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:361
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())
Definition: Constructor.cc:185
void dump(ostream &strm) const override
dumps information about this object
Definition: Constructor.cc:767
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
void add_map(D4Map *map)
Definition: D4Maps.h:115
Holds the Grid data type.
Definition: Grid.h:123
virtual BaseType * ptr_duplicate()
Definition: Grid.cc:108
BaseType * array_var()
Returns the Grid Array.
Definition: Grid.cc:480
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: Grid.cc:127
virtual void print_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Grid.cc:788
Map_iter map_begin()
Returns an iterator referencing the first Map vector.
Definition: Grid.cc:496
Map_iter get_map_iter(int i)
Definition: Grid.cc:533
virtual void set_array(Array *p_new_arr)
Definition: Grid.cc:368
virtual void clear_constraint()
Definition: Grid.cc:705
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: Grid.cc:869
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:722
virtual Array * prepend_map(Array *p_new_map, bool add_copy)
Definition: Grid.cc:463
Grid(const string &n)
The Grid constructor.
Definition: Grid.cc:78
Array * get_array()
Returns the Grid Array. This method returns the array using an Array*, so no cast is required.
Definition: Grid.cc:489
virtual void transfer_attributes(AttrTable *at_container)
Definition: Grid.cc:579
virtual bool projection_yields_grid()
Definition: Grid.cc:661
Map_iter map_end()
Definition: Grid.cc:508
Map_riter map_rend()
Definition: Grid.cc:524
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Grid.cc:1002
virtual Array * add_map(Array *p_new_map, bool add_copy)
Definition: Grid.cc:434
virtual int components(bool constrained=false)
Returns the number of components in the Grid object.
Definition: Grid.cc:554
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: Grid.cc:816
virtual bool check_semantics(string &msg, bool all=false)
Return true if this Grid is well formed.
Definition: Grid.cc:906
virtual void add_var(BaseType *bt, Part part)
Definition: Grid.cc:243
virtual void add_var_nocopy(BaseType *bt, Part part)
Definition: Grid.cc:309
Map_riter map_rbegin()
Returns an iterator referencing the first Map vector.
Definition: Grid.cc:515
virtual bool is_dap2_only_type()
Definition: Grid.cc:225
A class for software fault reporting.
Definition: InternalErr.h:65
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
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