libdap Updated for version 3.21.0
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
192 coverage->attributes()->transform_to_dap4(get_attr_table());
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 // Removed this line in favor of the following one while re-working the D4Maps design.
207 // jhrg 9/16/22
208 // D4Map *d4_map = new D4Map(the_map_array->FQN(), the_map_array, coverage); // bind the 'map' to the coverage
209 D4Map *d4_map = new D4Map(the_map_array->FQN(), the_map_array);
210 coverage->maps()->add_map(d4_map); // bind the coverage to the map
211 // Clear the vector entry to ensure that ~Array doesn't
212 // get called when the (stack declared) vector goes out of scope.
213 *d4aItr = 0;
214 DBG(cerr << __func__ << "() - Added DAP4 Map Array: '"<< d4_map->name() <<
215 "' (" << (void *) d4_map->array() << ") to coverage: '" << coverage->name() << "'" << endl;);
216
217 }
218 DBG(cerr << __func__ << "() - END (grid:" << name() << ")" << endl;);
219}
220
221
227bool
229{
230 return true;
231}
232
245void
247{
248 if (!bt)
249 throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
250
251 if (bt->is_dap4())
252 throw Error(string("A method usable only with DAP2 variables was called on a DAP4 variable (").append(name()).append(")."), __FILE__, __LINE__);
253
254 if (part == array && d_is_array_set/*get_array()*/) {
255 // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
256 throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
257 }
258
259 // avoid obvious broken semantics
260 if (!dynamic_cast<Array*>(bt)) {
261 throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
262 }
263
264 // Set to the clone of bt if we get that far.
265 BaseType* bt_clone = 0;
266
267 switch (part) {
268
269 case array: {
270 // Add it as a copy to preserve old semantics. This sets parent too.
271 bt_clone = bt->ptr_duplicate();
272 set_array(static_cast<Array*>(bt_clone));
273 }
274 break;
275
276 case maps: {
277 bt_clone = bt->ptr_duplicate();
278 bt_clone->set_parent(this);
279 d_vars.push_back(bt_clone);
280 }
281 break;
282
283 default: {
284 if (!d_is_array_set) {
285 // Add it as a copy to preserve old semantics. This sets parent too.
286 bt_clone = bt->ptr_duplicate();
287 set_array(static_cast<Array*>(bt_clone));
288 }
289 else {
290 bt_clone = bt->ptr_duplicate();
291 bt_clone->set_parent(this);
292 d_vars.push_back(bt_clone);
293 }
294 }
295 break;
296 }
297}
298
314void
316{
317 if (!bt)
318 throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
319
320 if (bt->is_dap4())
321 throw Error(string("A method usable only with DAP2 variables was called on a DAP4 variable (").append(name()).append(")."), __FILE__, __LINE__);
322
323 if (part == array && d_is_array_set/*get_array()*/) {
324 // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
325 throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
326 }
327
328 // avoid obvious broken semantics
329 if (!dynamic_cast<Array*>(bt)) {
330 throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
331 }
332
333 bt->set_parent(this);
334
335 switch (part) {
336
337 case array: {
338 // Refactored to use new set_array ([mjohnson 11 nov 2009])
339 set_array(static_cast<Array*>(bt));
340 }
341 break;
342
343 case maps: {
344 // FIXME Why is this commented out?
345 //bt->set_parent(this);
346 d_vars.push_back(bt);
347 }
348 break;
349
350 default: {
351 if (!d_is_array_set) {
352 // Refactored to use new set_array ([mjohnson 11 nov 2009])
353 // avoid obvious broken semantics
354 set_array(static_cast<Array*>(bt));
355 }
356 else {
357 d_vars.push_back(bt);
358 }
359 }
360 break;
361 }
362}
363
377void Grid::set_array(Array* p_new_arr)
378{
379 if (!p_new_arr) {
380 throw InternalErr(__FILE__, __LINE__, "Grid::set_array(): Cannot set to null!");
381 }
382
383 // Make sure not same memory, this would be evil.
384 if (p_new_arr == get_array()) {
385 return;
386 }
387
388 p_new_arr->set_parent(this);
389
390 // Three cases: 1. There are no variables set for this grid at all
391 // 2. There are maps but no array
392 // 3. There is already an array set (and maybe maps).
393 // NB: d_array_var is a weak pointer to the Grid's Array
394 if (d_vars.size() == 0) {
395 d_vars.push_back(p_new_arr);
396 }
397 else if (!d_is_array_set) {
398 d_vars.insert(d_vars.begin(), p_new_arr);
399 }
400 else {
401 // clean out old array
402 delete get_array();
403 d_vars[0] = p_new_arr;
404 }
405
406 d_is_array_set = true;
407#if 0
408 // store the array pointer locally
409 d_array_var = p_new_arr;
410
411 // Set the parent
412 d_array_var->set_parent(this);
413#endif
414}
415
442Array*
443Grid::add_map(Array* p_new_map, bool add_as_copy)
444{
445 if (!p_new_map)
446 throw InternalErr(__FILE__, __LINE__, "Grid::add_map(): cannot have p_new_map null!");
447
448 if (add_as_copy)
449 p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
450
451 p_new_map->set_parent(this);
452
453 d_vars.push_back(p_new_map);
454
455 // return the one that got put into the Grid.
456 return p_new_map;
457}
458
471Array*
472Grid::prepend_map(Array* p_new_map, bool add_copy)
473{
474 if (add_copy)
475 {
476 p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
477 }
478
479 p_new_map->set_parent(this);
480 d_vars.insert(map_begin(), p_new_map);
481
482 return p_new_map;
483}
484
488BaseType *
490{
491 return d_is_array_set ? *d_vars.begin() : nullptr;
492}
493
497Array *
499{
500 return dynamic_cast<Array*>(array_var());
501}
502
504Grid::Map_iter
506{
507 // The maps are stored in the second and subsequent elements of the
508 // d_var vector<BaseType*> of Constructor _unless_ the Array part
509 // has yet to be set. In the latter case, there are only maps in
510 // d_vars
511 return d_is_array_set ? d_vars.begin() + 1: d_vars.begin();
512}
513
516Grid::Map_iter
518{
519 return d_vars.end();
520}
521
523Grid::Map_riter
525{
526 // see above
527 return d_vars.rbegin();
528}
529
532Grid::Map_riter
534{
535 return d_is_array_set ? d_vars.rend() - 1: d_vars.rend();
536}
537
541Grid::Map_iter
543{
544 return d_is_array_set ? d_vars.begin() + 1 + i : d_vars.begin() + i;
545}
546
562int
563Grid::components(bool constrained)
564{
565 int comp;
566
567 if (constrained) {
568 comp = get_array()->send_p() ? 1 : 0;
569
570 for (Map_iter i = map_begin(); i != map_end(); i++) {
571 if ((*i)->send_p()) {
572 comp++;
573 }
574 }
575 }
576 else {
577 comp = d_vars.size();
578 }
579
580 return comp;
581}
582
589{
590 DBG( cerr << __func__ << "() - BEGIN "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
591
592 // The variable 'at' should be the attribute table for the Grid
593 AttrTable *at = at_container->get_attr_table(name());
594 if (at) {
595 DBG( cerr << __func__ << "() - Found AttrTable ("<< at->get_name() << ":" << (void*)at<< ")" << endl;);
596 at->set_is_global_attribute(false);
597
598#if 0
599 // Removing this is left over from a previous version, unknown date.
600 // If the line is added back, some of the DMR round trip tests fail
601 // and the dapreader behavior is changed - tests that build responses
602 // from .dods and .das files fail when they include Grids. jhrg 5/23/18
603 //
604 // See also HYARX-766
606#endif
607
608 // If the AttrTable with the name of this Grid (which is also the
609 // name of the Grid's Array) contains a child AttrTable with that
610 // name, mark the attributes as 'not global' and ignore them. This
611 // code has been here for some time; I just added this comment. jhrg 5/23/18
612 AttrTable *dvat = at->get_attr_table(array_var()->name());
613 if (dvat) {
614 dvat->set_is_global_attribute(false);
615 }
616
617 Map_iter map = map_begin();
618 while (map != map_end()) {
619 (*map)->transfer_attributes(at);
620 map++;
621 }
622
623 // Trick: If an attribute that's within the container 'at' still has its
624 // is_global_attribute property set, then it's not really a global attr
625 // but instead an attribute that belongs to this Grid.
626 AttrTable::Attr_iter at_p = at->attr_begin();
627 while (at_p != at->attr_end()) {
628 if (at->is_global_attribute(at_p)) {
629 DBG( cerr << __func__ << "() - " <<
630 "Adding unclaimed Attribute ("<<
631 at->get_type(at_p)<< ":" << at->get_name(at_p) << ":" << (void*)(*map)<<
632 ") from AttrTable (" << at->get_name() << ":" << (void*)at << ")" <<
633 " to the variable " << type_name() << " " << name() << endl;);
634
635 if (at->get_attr_type(at_p) == Attr_container)
636 get_attr_table().append_container(new AttrTable(*at->get_attr_table(at_p)), at->get_name(at_p));
637 else
638 get_attr_table().append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p),(*at_p)->is_utf8_str);
639 }
640
641 at_p++;
642 }
643 }
644 else {
645 DBG( cerr << __func__ << "() - No AttrTable named '"<< name() << "' was found in at_container ("<<at_container->get_name()<<":" << (void*)at<< ")" << endl;);
646 }
647 DBG( cerr << __func__ << "() - END "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
648}
649
650// When projected (using whatever the current constraint provides in the way
651// of a projection), is the object still a Grid?
652
669bool
671{
672 // For each dimension in the Array part, check the corresponding Map
673 // vector to make sure it is present in the projected Grid. If for each
674 // projected dimension in the Array component, there is a matching Map
675 // vector, then the Grid is valid.
676 bool valid = true;
677 Array *a = get_array();
678
679 // Don't bother checking if the Array component is not included.
680 if (!a->send_p())
681 return false;
682
683 // If only one part is being sent, it's clearly not a grid (it must be
684 // the array part of the Grid that's being sent (given that the above
685 // test passed and the array is being sent).
686 if (components(true) == 1)
687 return false;
688
689 Array::Dim_iter d = a->dim_begin() ;
690 Map_iter m = map_begin() ;
691
692 while (valid && d != a->dim_end() && m != map_end()) {
693 Array &map = dynamic_cast<Array&>(**m);
694 if (a->dimension_size(d, true) && map.send_p()) {
695 // Check the matching Map vector; the Map projection must equal
696 // the Array dimension projection
697 Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
698 valid = map.dimension_start(fd, true) == a->dimension_start(d, true)
699 && map.dimension_stop(fd, true) == a->dimension_stop(d, true)
700 && map.dimension_stride(fd, true) == a->dimension_stride(d, true);
701 }
702 else {
703 valid = false;
704 }
705
706 d++, m++;
707 }
708
709 return valid;
710}
711
713void
715{
717 for (Map_iter m = map_begin(); m != map_end(); ++m)
718 dynamic_cast<Array&>(*(*m)).clear_constraint();
719}
720
721void
722Grid::print_decl(FILE *out, string space, bool print_semi,
723 bool constraint_info, bool constrained)
724{
725 ostringstream oss;
726 print_decl(oss, space, print_semi, constraint_info, constrained);
727 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
728}
729
730void
731Grid::print_decl(ostream &out, string space, bool print_semi,
732 bool constraint_info, bool constrained)
733{
734 if (constrained && !send_p())
735 return;
736
737 // See comment for the FILE* version of this method.
738 if (constrained && !projection_yields_grid()) {
739 out << space << "Structure {\n" ;
740
741 get_array()->print_decl(out, space + " ", true, constraint_info,
742 constrained);
743
744 for (Map_citer i = map_begin(); i != map_end(); i++) {
745 (*i)->print_decl(out, space + " ", true,
746 constraint_info, constrained);
747 }
748
749 out << space << "} " << id2www(name()) ;
750 }
751 else {
752 // The number of elements in the (projected) Grid must be such that
753 // we have a valid Grid object; send it as such.
754 out << space << type_name() << " {\n" ;
755
756 out << space << " Array:\n" ;
757 get_array()->print_decl(out, space + " ", true, constraint_info,
758 constrained);
759
760 out << space << " Maps:\n" ;
761 for (Map_citer i = map_begin(); i != map_end(); i++) {
762 (*i)->print_decl(out, space + " ", true,
763 constraint_info, constrained);
764 }
765
766 out << space << "} " << id2www(name()) ;
767 }
768
769 if (constraint_info) {
770 if (send_p())
771 out << ": Send True";
772 else
773 out << ": Send False";
774 }
775
776 if (print_semi)
777 out << ";\n" ;
778
779 return;
780}
781
785void
786Grid::print_xml(FILE *out, string space, bool constrained)
787{
788 XMLWriter xml(space);
789 print_xml_writer(xml, constrained);
790 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
791}
792
796void
797Grid::print_xml(ostream &out, string space, bool constrained)
798{
799 XMLWriter xml(space);
800 print_xml_writer(xml, constrained);
801 out << xml.get_doc();
802}
803
804
805class PrintGridFieldXMLWriter : public unary_function<BaseType *, void>
806{
807 XMLWriter &d_xml;
808 bool d_constrained;
809 string d_tag;
810public:
811 PrintGridFieldXMLWriter(XMLWriter &x, bool c, const string &t = "Map")
812 : d_xml(x), d_constrained(c), d_tag(t)
813 {}
814
815 void operator()(BaseType *btp)
816 {
817 Array *a = dynamic_cast<Array*>(btp);
818 if (!a)
819 throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
820 a->print_xml_writer_core(d_xml, d_constrained, d_tag);
821 }
822};
823
824void
825Grid::print_xml_writer(XMLWriter &xml, bool constrained)
826{
827 if (constrained && !send_p())
828 return;
829
830 if (constrained && !projection_yields_grid()) {
831 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Structure") < 0)
832 throw InternalErr(__FILE__, __LINE__, "Could not write Structure element");
833
834 if (!name().empty())
835 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
836 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
837
838 get_attr_table().print_xml_writer(xml);
839
840 get_array()->print_xml_writer(xml, constrained);
841
842 for_each(map_begin(), map_end(),
843 PrintGridFieldXMLWriter(xml, constrained, "Array"));
844
845 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
846 throw InternalErr(__FILE__, __LINE__, "Could not end Structure element");
847 }
848 else {
849 // The number of elements in the (projected) Grid must be such that
850 // we have a valid Grid object; send it as such.
851 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Grid") < 0)
852 throw InternalErr(__FILE__, __LINE__, "Could not write Grid element");
853
854 if (!name().empty())
855 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
856 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
857
858 get_attr_table().print_xml_writer(xml);
859
860 get_array()->print_xml_writer(xml, constrained);
861
862 for_each(map_begin(), map_end(),
863 PrintGridFieldXMLWriter(xml, constrained, "Map"));
864
865 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
866 throw InternalErr(__FILE__, __LINE__, "Could not end Grid element");
867 }
868}
869
870void
871Grid::print_val(FILE *out, string space, bool print_decl_p)
872{
873 ostringstream oss;
874 print_val(oss, space, print_decl_p);
875 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
876}
877
878void Grid::print_val(ostream &out, string space, bool print_decl_p)
879{
880 if (print_decl_p) {
881 print_decl(out, space, false);
882 out << " = ";
883 }
884
885 // If we are printing a value on the client-side, projection_yields_grid
886 // should not be called since we don't *have* a projection without a
887 // Constraint. I think that if we are here and send_p() is not true, then
888 // the value of this function should be ignored. 4/6/2000 jhrg
889 bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
890 if (pyg || !send_p())
891 out << "{ Array: ";
892 else
893 out << "{";
894
895 get_array()->print_val(out, "", false);
896
897 if (pyg || !send_p()) out << " Maps: ";
898
899 for (Map_citer i = map_begin(); i != map_end(); i++, (void) (i != map_end() && out << ", ")) {
900 (*i)->print_val(out, "", false);
901 }
902
903 out << " }";
904
905 if (print_decl_p) out << ";\n";
906}
907
908// Grids have ugly semantics.
909
914bool
915Grid::check_semantics(string &msg, bool all)
916{
918 return false;
919
920 msg = "";
921
922 if (!get_array()) {
923 msg += "Null grid base array in `" + name() + "'\n";
924 return false;
925 }
926
927 // Is it an array?
928 if (get_array()->type() != dods_array_c) {
929 msg += "Grid `" + name() + "'s' member `" + get_array()->name() + "' must be an array\n";
930 return false;
931 }
932
933 Array *av = (Array *)get_array(); // past test above, must be an array
934
935 // Array must be of a simple_type.
936 if (!av->var()->is_simple_type()) {
937 msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
938 return false;
939 }
940
941 // enough maps?
942 if ((unsigned)d_vars.size()-1 != av->dimensions()) {
943 msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
944 msg += av->name() + "'\n";
945 return false;
946 }
947
948 const string array_var_name = av->name();
949 Array::Dim_iter asi = av->dim_begin() ;
950 for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++, asi++) {
951
952 BaseType *mv = *mvi;
953
954 // check names
955 if (array_var_name == mv->name()) {
956 msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
957 return false;
958 }
959 // check types
960 if (mv->type() != dods_array_c) {
961 msg += "Grid map variable `" + mv->name() + "' is not an array\n";
962 return false;
963 }
964
965 Array *mv_a = (Array *)mv; // downcast to (Array *)
966
967 // Array must be of a simple_type.
968 if (!mv_a->var()->is_simple_type()) {
969 msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
970 return false;
971 }
972
973 // check shape
974 if (mv_a->dimensions() != 1) {// maps must have one dimension
975 msg += "Grid map variable `" + mv_a->name() + "' must be only one dimension\n";
976 return false;
977 }
978 // size of map must match corresponding array dimension
979 Array::Dim_iter mv_asi = mv_a->dim_begin() ;
980 int mv_a_size = mv_a->dimension_size(mv_asi) ;
981 int av_size = av->dimension_size(asi) ;
982 if (mv_a_size != av_size) {
983 msg += "Grid map variable `" + mv_a->name() + "'s' size does not match the size of array variable '";
984 msg += get_array()->name() + "'s' cooresponding dimension\n";
985 return false;
986 }
987 }
988
989 if (all) {
990 if (!get_array()->check_semantics(msg, true))
991 return false;
992 for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++) {
993 if (!(*mvi)->check_semantics(msg, true)) {
994 return false;
995 }
996 }
997 }
998
999 return true;
1000}
1001
1010void
1011Grid::dump(ostream &strm) const
1012{
1013 strm << DapIndent::LMarg << "Grid::dump - ("
1014 << (void *)this << ")" << endl ;
1015 DapIndent::Indent() ;
1016 Constructor::dump(strm) ;
1017
1018 DapIndent::UnIndent() ;
1019}
1020
1021} // namespace libdap
1022
A multidimensional array of identical data types.
Definition Array.h:123
virtual void clear_constraint()
Clears the projection; add each projected dimension explicitly using add_constraint.
Definition Array.cc:639
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:1163
void print_val(ostream &out, string space="", bool print_decl_p=true) override
Prints the value of the variable.
Definition Array.cc:1395
std::vector< dimension >::iterator Dim_iter
Definition Array.h:241
void print_xml_writer(XMLWriter &xml, bool constrained=false) override
Definition Array.cc:1248
Dim_iter dim_begin()
Definition Array.cc:762
virtual unsigned int dimensions(bool constrained=false)
Return the total number of dimensions in the array.
Definition Array.cc:783
Contains the attributes for a dataset.
Definition AttrTable.h:154
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition AttrTable.cc:751
virtual string get_name() const
Get the name of this attribute table.
Definition AttrTable.cc:266
The basic data type for the DODS DAP types.
Definition BaseType.h:120
virtual string type_name() const
Returns the type of the class instance as a string.
Definition BaseType.cc:376
virtual AttrTable & get_attr_table()
Definition BaseType.cc:579
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:317
virtual void set_parent(BaseType *parent)
Definition BaseType.cc:730
virtual bool send_p()
Should this variable be sent?
Definition BaseType.cc:551
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:641
virtual bool check_semantics(string &msg, bool all=false)
Compare an object's current state with the semantics of its type.
Definition BaseType.cc:1215
virtual Type type() const
Returns the type of the class instance.
Definition BaseType.cc:362
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())
void dump(ostream &strm) const override
dumps information about this object
A class for error processing.
Definition Error.h:94
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:489
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:797
Map_iter map_begin()
Returns an iterator referencing the first Map vector.
Definition Grid.cc:505
Map_iter get_map_iter(int i)
Definition Grid.cc:542
virtual void set_array(Array *p_new_arr)
Definition Grid.cc:377
virtual void clear_constraint()
Definition Grid.cc:714
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition Grid.cc:878
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:731
virtual Array * prepend_map(Array *p_new_map, bool add_copy)
Definition Grid.cc:472
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:498
virtual void transfer_attributes(AttrTable *at_container)
Definition Grid.cc:588
virtual bool projection_yields_grid()
Definition Grid.cc:670
Map_iter map_end()
Definition Grid.cc:517
Map_riter map_rend()
Definition Grid.cc:533
virtual void dump(ostream &strm) const
dumps information about this object
Definition Grid.cc:1011
virtual Array * add_map(Array *p_new_map, bool add_copy)
Definition Grid.cc:443
virtual int components(bool constrained=false)
Returns the number of components in the Grid object.
Definition Grid.cc:563
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition Grid.cc:825
virtual bool check_semantics(string &msg, bool all=false)
Return true if this Grid is well formed.
Definition Grid.cc:915
virtual void add_var(BaseType *bt, Part part)
Definition Grid.cc:246
virtual void add_var_nocopy(BaseType *bt, Part part)
Definition Grid.cc:315
Map_riter map_rbegin()
Returns an iterator referencing the first Map vector.
Definition Grid.cc:524
virtual bool is_dap2_only_type()
Definition Grid.cc:228
A class for software fault reporting.
Definition InternalErr.h:65
top level DAP object to house generic methods
Definition AISConnect.cc:30
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