libdap Updated for version 3.20.8
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// #define DODS_DEBUG
39
40#include <sstream>
41#include <functional>
42#include <algorithm>
43
44#include "Grid.h"
45#include "DDS.h"
46#include "Array.h" // for downcasts
47#include "util.h"
48#include "InternalErr.h"
49#include "escaping.h"
50#include "XDRStreamMarshaller.h"
51#include "debug.h"
52
53#include "XMLWriter.h"
54#include "DMR.h"
55#include "D4Group.h"
56#include "D4Maps.h"
57#include "D4Attributes.h"
58
59#include "DapIndent.h"
60
61using namespace std;
62
63namespace libdap {
64
65void
66Grid::m_duplicate(const Grid &s)
67{
68 // TODO revisit this code once/if the class is switched from using it's
69 // own vars to those in Constructor. jhrg 4/3/13
70
71 // copy the weak pointer - Constructor will take care of copying
72 // the 'strong' pointers.
73 //d_array_var = s.d_array_var;
74 d_is_array_set = s.d_is_array_set;
75}
76
86Grid::Grid(const string &n) : Constructor(n, dods_grid_c), d_is_array_set(false)
87{}
88
100Grid::Grid(const string &n, const string &d)
101 : Constructor(n, d, dods_grid_c), d_is_array_set(false)
102{}
103
105Grid::Grid(const Grid &rhs) : Constructor(rhs)
106{
107 m_duplicate(rhs);
108}
109
110Grid::~Grid()
111{
112 //d_array_var = 0; // Weak pointer; object will be freed by Constructor
113}
114
115BaseType *
117{
118 return new Grid(*this);
119}
120
121Grid &
122Grid::operator=(const Grid &rhs)
123{
124 if (this == &rhs)
125 return *this;
126
127 // Removed this; it makes this operator= work differently than the rest
128#if 0
129 delete d_array_var; d_array_var = 0;
130
131 for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
132 BaseType *btp = *i ;
133 delete btp ;
134 }
135#endif
136
137 dynamic_cast<Constructor &>(*this) = rhs;
138
139 m_duplicate(rhs);
140
141 return *this;
142}
143
147void
149{
150 DBG(cerr << __func__ << "() - BEGIN (name:"<< name() <<
151 ")(type:"<< type_name()<<
152 ")(root:'"<< root->name()<<"':"<<(void*)root <<
153 ")(container:'"<< container->name()<<"':"<< (void *) container<< ")"
154 << endl;);
155
156 vector<Array*> d4_map_arrays;
157
158 // We do the Map Arrays first because some people expect to see them
159 // delclared prior to the coverage array the utilizes them - even though that
160 // is not a requirement of DAP4 I did it here to make people happier.
161 // We add the maps arrays to the current container if needed and make a
162 // a vector of them so we can add D4Map objects to our Precious down
163 // below.
164 for (Map_iter i = map_begin(), e = map_end(); i != e; ++i) {
165 DBG(cerr << __func__ << "() - Processing Map Array: '"<< (*i)->name() << "' ("<< (void *)(*i)<< ")" << endl;);
166 // Only add the map/array if it's not already present in the target DAP2 container.
167 // Given the scoping rules for DAP2 and the assumption the DDS is valid, testing for
168 // the same name is good enough. The point here is to be sure to only use the
169 // existing maps. This is an important issue when there are multiple Grids in the same
170 // dataset that utilize the same Map arrays data.
171 Array *the_map_array;;
172 Array *container_map_array = static_cast<Array*>(container->var((*i)->name()));
173 if(!container_map_array){
174 DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the current DAP4 container ("<<container->name()<< ":"<<(void*)container<< "). Let's fix that..." << endl;);
175 // Not in the container, so we check root group
176 Array *root_map_array = static_cast<Array*>(root->var((*i)->name()));
177 if (!root_map_array) {
178 // Not in the root group so we transform a new array and add it to container.
179 DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the root Group ("<<root->name()<< ":"<<(void*)root<< "). Let's fix that..." << endl;);
180 // transform it and add it to the container
181 (*i)->transform_to_dap4(root, container);
182 // Recover the new dap4 version from the container.
183 the_map_array = static_cast<Array*>(container->var((*i)->name()));
184 DBG(cerr << __func__ << "() - Transformed array '"<< the_map_array->name() <<
185 "' to DAP4 Array (" << (void *) the_map_array << ") added to container: '"<<
186 container->name() <<"'" << endl;);
187 }
188 else {
189 the_map_array = root_map_array;
190 DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' (" <<
191 (void *) the_map_array << ") present in the root group ("<<root->name()<< ":"<<(void*)root <<
192 ")"<< endl;);
193 }
194 }
195 else {
196 the_map_array = container_map_array;
197 DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' (" <<
198 (void *) the_map_array << ") present in the current DAP4 container ("<<container->name( )<< ":"<<
199 (void*)container<< ")" << endl;);
200 }
201 // We'll use these (below) to make D4Map objects for the coverage
202 d4_map_arrays.push_back(the_map_array);
203 }
204
205 // Adds the coverage array to the container.
206 array_var()->transform_to_dap4(root, container);
207 // Get the new coverage array
208 BaseType *btp = container->var(array_var()->name());
209 Array *coverage = static_cast<Array*>(btp);
210 DBG(cerr << __func__ << "() - Transformed and added DAP4 coverage Array '"<< coverage->name() <<
211 "' to parent container: '" << container->name() << "'" << endl;);
212
214
215 DBG(cerr << __func__ << "() - " << "Coverage Array '"<< coverage->name() << "' attributes: " << endl;
216 XMLWriter xmlw;
217 coverage->get_attr_table().print_dap4(xmlw);
218 cerr << xmlw.get_doc() << endl;);
219
220 // Add the D4Maps
221 vector<Array*>::iterator d4aItr=d4_map_arrays.begin();
222 vector<Array*>::iterator end=d4_map_arrays.end();
223 for( ; d4aItr!=end ; d4aItr++){
224 Array *the_map_array = *d4aItr;
225 // Here we use the Map Array that we saved the Map
226 // name and Map Array reference for our map.
227 D4Map *d4_map = new D4Map(the_map_array->FQN(), the_map_array, coverage); // bind the 'map' to the coverage
228 coverage->maps()->add_map(d4_map); // bind the coverage to the map
229 // Clear the vector entry to ensure that ~Array doesn't
230 // get called when the (stack declared) vector goes out of scope.
231 *d4aItr = 0;
232 DBG(cerr << __func__ << "() - Added DAP4 Map Array: '"<< d4_map->name() <<
233 "' (" << (void *) d4_map->array() << ") to coverage: '" << coverage->name() << "'" << endl;);
234
235 }
236 DBG(cerr << __func__ << "() - END (grid:" << name() << ")" << endl;);
237}
238
239
245bool
247{
248 return true;
249}
250
263void
265{
266 if (!bt)
267 throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
268
269 if (part == array && d_is_array_set/*get_array()*/) {
270 // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
271 throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
272 }
273
274 // avoid obvious broken semantics
275 if (!dynamic_cast<Array*>(bt)) {
276 throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
277 }
278
279 // Set to the clone of bt if we get that far.
280 BaseType* bt_clone = 0;
281
282 switch (part) {
283
284 case array: {
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 break;
290
291 case maps: {
292 bt_clone = bt->ptr_duplicate();
293 bt_clone->set_parent(this);
294 d_vars.push_back(bt_clone);
295 }
296 break;
297
298 default: {
299 if (!d_is_array_set) {
300 // Add it as a copy to preserve old semantics. This sets parent too.
301 bt_clone = bt->ptr_duplicate();
302 set_array(static_cast<Array*>(bt_clone));
303 }
304 else {
305 bt_clone = bt->ptr_duplicate();
306 bt_clone->set_parent(this);
307 d_vars.push_back(bt_clone);
308 }
309 }
310 break;
311 }
312}
313
329void
331{
332 if (!bt)
333 throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
334
335 if (part == array && d_is_array_set/*get_array()*/) {
336 // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
337 throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
338 }
339
340 // avoid obvious broken semantics
341 if (!dynamic_cast<Array*>(bt)) {
342 throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
343 }
344
345 bt->set_parent(this);
346
347 switch (part) {
348
349 case array: {
350 // Refactored to use new set_array ([mjohnson 11 nov 2009])
351 set_array(static_cast<Array*>(bt));
352 }
353 break;
354
355 case maps: {
356 // FIXME Why is this commented out?
357 //bt->set_parent(this);
358 d_vars.push_back(bt);
359 }
360 break;
361
362 default: {
363 if (!d_is_array_set) {
364 // Refactored to use new set_array ([mjohnson 11 nov 2009])
365 // avoid obvious broken semantics
366 set_array(static_cast<Array*>(bt));
367 }
368 else {
369 d_vars.push_back(bt);
370 }
371 }
372 break;
373 }
374}
375
389void Grid::set_array(Array* p_new_arr)
390{
391 if (!p_new_arr) {
392 throw InternalErr(__FILE__, __LINE__, "Grid::set_array(): Cannot set to null!");
393 }
394
395 // Make sure not same memory, this would be evil.
396 if (p_new_arr == get_array()) {
397 return;
398 }
399
400 p_new_arr->set_parent(this);
401
402 // Three cases: 1. There are no variables set for this grid at all
403 // 2. There are maps but no array
404 // 3. There is already an array set (and maybe maps).
405 // NB: d_array_var is a weak pointer to the Grid's Array
406 if (d_vars.size() == 0) {
407 d_vars.push_back(p_new_arr);
408 }
409 else if (!d_is_array_set) {
410 d_vars.insert(d_vars.begin(), p_new_arr);
411 }
412 else {
413 // clean out old array
414 delete get_array();
415 d_vars[0] = p_new_arr;
416 }
417
418 d_is_array_set = true;
419#if 0
420 // store the array pointer locally
421 d_array_var = p_new_arr;
422
423 // Set the parent
424 d_array_var->set_parent(this);
425#endif
426}
427
454Array*
455Grid::add_map(Array* p_new_map, bool add_as_copy)
456{
457 if (!p_new_map)
458 throw InternalErr(__FILE__, __LINE__, "Grid::add_map(): cannot have p_new_map null!");
459
460 if (add_as_copy)
461 p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
462
463 p_new_map->set_parent(this);
464
465 d_vars.push_back(p_new_map);
466
467 // return the one that got put into the Grid.
468 return p_new_map;
469}
470
483Array*
484Grid::prepend_map(Array* p_new_map, bool add_copy)
485{
486 if (add_copy)
487 {
488 p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
489 }
490
491 p_new_map->set_parent(this);
492 d_vars.insert(map_begin(), p_new_map);
493
494 return p_new_map;
495}
496
500BaseType *
502{
503 //return d_array_var;
504 // FIXME Should really test that the array has not be set; maps might be added first. jhrg 5/9/13
505#if 0
506 if (d_array_var)
507 cerr << "In array_var(), d_array_var holds a " << d_array_var->type_name() << endl;
508 else
509 cerr << "In array_var(), d_array_var is null" << endl;
510#endif
511 return d_is_array_set /*d_vars.size() > 0*/ ? *d_vars.begin() : 0;
512}
513
517Array *
519{
520 return dynamic_cast<Array*>(array_var());
521}
522
524Grid::Map_iter
526{
527 // The maps are stored in the second and subsequent elements of the
528 // d_var vector<BaseType*> of Constructor _unless_ the Array part
529 // has yet to be set. In the latter case, there are only maps in
530 // d_vars
531 return d_is_array_set/*(d_array_var != 0)*/ ? d_vars.begin() + 1: d_vars.begin();
532}
533
536Grid::Map_iter
538{
539 return d_vars.end();
540}
541
543Grid::Map_riter
545{
546 // see above
547 // return d_is_array_set/*(d_array_var != 0)*/ ? d_vars.rbegin() + 1: d_vars.rbegin();
548 return d_vars.rbegin();
549}
550
553Grid::Map_riter
555{
556 return d_is_array_set ? d_vars.rend() - 1: d_vars.rend();
557}
558
562Grid::Map_iter
564{
565 // return map_begin() + i;
566 return d_is_array_set ? map_begin() + 1 + i : map_begin() + i;
567}
568
584int
585Grid::components(bool constrained)
586{
587 int comp;
588
589 if (constrained) {
590 comp = get_array()->send_p() ? 1 : 0;
591
592 for (Map_iter i = map_begin(); i != map_end(); i++) {
593 if ((*i)->send_p()) {
594 comp++;
595 }
596 }
597 }
598 else {
599 comp = d_vars.size();
600 }
601
602 return comp;
603}
604
611{
612 DBG( cerr << __func__ << "() - BEGIN "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
613
614 // The variable 'at' should be the attribute table for the Grid
615 AttrTable *at = at_container->get_attr_table(name());
616 if (at) {
617 DBG( cerr << __func__ << "() - Found AttrTable ("<< at->get_name() << ":" << (void*)at<< ")" << endl;);
618 at->set_is_global_attribute(false);
619
620#if 0
621 // Removing this is left over from a previous version, unknown date.
622 // If the line is added back, some of the DMR round trip tests fail
623 // and the dapreader behavior is changed - tests that build responses
624 // from .dods and .das files fail when they include Grids. jhrg 5/23/18
625 //
626 // See also HYARX-766
628#endif
629
630 // If the AttrTable with the name of this Grid (which is also the
631 // name of the Grid's Array) contains a child AttrTable with that
632 // name, mark the attributes as 'not global' and ignore them. This
633 // code has been here for some time; I just added this comment. jhrg 5/23/18
634 AttrTable *dvat = at->get_attr_table(array_var()->name());
635 if (dvat) {
636 dvat->set_is_global_attribute(false);
637 }
638
639 Map_iter map = map_begin();
640 while (map != map_end()) {
641 (*map)->transfer_attributes(at);
642 map++;
643 }
644
645 // Trick: If an attribute that's within the container 'at' still has its
646 // is_global_attribute property set, then it's not really a global attr
647 // but instead an attribute that belongs to this Grid.
648 AttrTable::Attr_iter at_p = at->attr_begin();
649 while (at_p != at->attr_end()) {
650 if (at->is_global_attribute(at_p)) {
651 DBG( cerr << __func__ << "() - " <<
652 "Adding unclaimed Attribute ("<<
653 at->get_type(at_p)<< ":" << at->get_name(at_p) << ":" << (void*)(*map)<<
654 ") from AttrTable (" << at->get_name() << ":" << (void*)at << ")" <<
655 " to the variable " << type_name() << " " << name() << endl;);
656
657 if (at->get_attr_type(at_p) == Attr_container)
658 get_attr_table().append_container(new AttrTable(*at->get_attr_table(at_p)), at->get_name(at_p));
659 else
660 get_attr_table().append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p));
661 }
662
663 at_p++;
664 }
665 }
666 else {
667 DBG( cerr << __func__ << "() - No AttrTable named '"<< name() << "' was found in at_container ("<<at_container->get_name()<<":" << (void*)at<< ")" << endl;);
668 }
669 DBG( cerr << __func__ << "() - END "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
670}
671
672// When projected (using whatever the current constraint provides in the way
673// of a projection), is the object still a Grid?
674
691bool
693{
694 // For each dimension in the Array part, check the corresponding Map
695 // vector to make sure it is present in the projected Grid. If for each
696 // projected dimension in the Array component, there is a matching Map
697 // vector, then the Grid is valid.
698 bool valid = true;
699 Array *a = get_array();
700
701 // Don't bother checking if the Array component is not included.
702 if (!a->send_p())
703 return false;
704
705 // If only one part is being sent, it's clearly not a grid (it must be
706 // the array part of the Grid that's being sent (given that the above
707 // test passed and the array is being sent).
708 if (components(true) == 1)
709 return false;
710
711 Array::Dim_iter d = a->dim_begin() ;
712 Map_iter m = map_begin() ;
713
714 while (valid && d != a->dim_end() && m != map_end()) {
715 Array &map = dynamic_cast<Array&>(**m);
716 if (a->dimension_size(d, true) && map.send_p()) {
717 // Check the matching Map vector; the Map projection must equal
718 // the Array dimension projection
719 Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
720 valid = map.dimension_start(fd, true) == a->dimension_start(d, true)
721 && map.dimension_stop(fd, true) == a->dimension_stop(d, true)
722 && map.dimension_stride(fd, true) == a->dimension_stride(d, true);
723 }
724 else {
725 valid = false;
726 }
727
728 d++, m++;
729 }
730
731 return valid;
732}
733
735void
737{
739 for (Map_iter m = map_begin(); m != map_end(); ++m)
740 dynamic_cast<Array&>(*(*m)).clear_constraint();
741}
742
743void
744Grid::print_decl(FILE *out, string space, bool print_semi,
745 bool constraint_info, bool constrained)
746{
747 ostringstream oss;
748 print_decl(oss, space, print_semi, constraint_info, constrained);
749 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
750}
751
752void
753Grid::print_decl(ostream &out, string space, bool print_semi,
754 bool constraint_info, bool constrained)
755{
756 if (constrained && !send_p())
757 return;
758
759 // See comment for the FILE* version of this method.
760 if (constrained && !projection_yields_grid()) {
761 out << space << "Structure {\n" ;
762
763 get_array()->print_decl(out, space + " ", true, constraint_info,
764 constrained);
765
766 for (Map_citer i = map_begin(); i != map_end(); i++) {
767 (*i)->print_decl(out, space + " ", true,
768 constraint_info, constrained);
769 }
770
771 out << space << "} " << id2www(name()) ;
772 }
773 else {
774 // The number of elements in the (projected) Grid must be such that
775 // we have a valid Grid object; send it as such.
776 out << space << type_name() << " {\n" ;
777
778 out << space << " Array:\n" ;
779 get_array()->print_decl(out, space + " ", true, constraint_info,
780 constrained);
781
782 out << space << " Maps:\n" ;
783 for (Map_citer i = map_begin(); i != map_end(); i++) {
784 (*i)->print_decl(out, space + " ", true,
785 constraint_info, constrained);
786 }
787
788 out << space << "} " << id2www(name()) ;
789 }
790
791 if (constraint_info) {
792 if (send_p())
793 out << ": Send True";
794 else
795 out << ": Send False";
796 }
797
798 if (print_semi)
799 out << ";\n" ;
800
801 return;
802}
803
807void
808Grid::print_xml(FILE *out, string space, bool constrained)
809{
810 XMLWriter xml(space);
811 print_xml_writer(xml, constrained);
812 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
813}
814
818void
819Grid::print_xml(ostream &out, string space, bool constrained)
820{
821 XMLWriter xml(space);
822 print_xml_writer(xml, constrained);
823 out << xml.get_doc();
824}
825
826
827class PrintGridFieldXMLWriter : public unary_function<BaseType *, void>
828{
829 XMLWriter &d_xml;
830 bool d_constrained;
831 string d_tag;
832public:
833 PrintGridFieldXMLWriter(XMLWriter &x, bool c, const string &t = "Map")
834 : d_xml(x), d_constrained(c), d_tag(t)
835 {}
836
837 void operator()(BaseType *btp)
838 {
839 Array *a = dynamic_cast<Array*>(btp);
840 if (!a)
841 throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
842 a->print_xml_writer_core(d_xml, d_constrained, d_tag);
843 }
844};
845
846void
847Grid::print_xml_writer(XMLWriter &xml, bool constrained)
848{
849 if (constrained && !send_p())
850 return;
851
852 if (constrained && !projection_yields_grid()) {
853 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Structure") < 0)
854 throw InternalErr(__FILE__, __LINE__, "Could not write Structure element");
855
856 if (!name().empty())
857 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
858 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
859
861
862 get_array()->print_xml_writer(xml, constrained);
863
864 for_each(map_begin(), map_end(),
865 PrintGridFieldXMLWriter(xml, constrained, "Array"));
866
867 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
868 throw InternalErr(__FILE__, __LINE__, "Could not end Structure element");
869 }
870 else {
871 // The number of elements in the (projected) Grid must be such that
872 // we have a valid Grid object; send it as such.
873 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Grid") < 0)
874 throw InternalErr(__FILE__, __LINE__, "Could not write Grid element");
875
876 if (!name().empty())
877 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
878 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
879
881
882 get_array()->print_xml_writer(xml, constrained);
883
884 for_each(map_begin(), map_end(),
885 PrintGridFieldXMLWriter(xml, constrained, "Map"));
886
887 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
888 throw InternalErr(__FILE__, __LINE__, "Could not end Grid element");
889 }
890}
891
892void
893Grid::print_val(FILE *out, string space, bool print_decl_p)
894{
895 ostringstream oss;
896 print_val(oss, space, print_decl_p);
897 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
898}
899
900void Grid::print_val(ostream &out, string space, bool print_decl_p)
901{
902 if (print_decl_p) {
903 print_decl(out, space, false);
904 out << " = ";
905 }
906
907 // If we are printing a value on the client-side, projection_yields_grid
908 // should not be called since we don't *have* a projection without a
909 // Constraint. I think that if we are here and send_p() is not true, then
910 // the value of this function should be ignored. 4/6/2000 jhrg
911 bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
912 if (pyg || !send_p())
913 out << "{ Array: ";
914 else
915 out << "{";
916
917 get_array()->print_val(out, "", false);
918
919 if (pyg || !send_p()) out << " Maps: ";
920
921 for (Map_citer i = map_begin(); i != map_end(); i++, (void) (i != map_end() && out << ", ")) {
922 (*i)->print_val(out, "", false);
923 }
924
925 out << " }";
926
927 if (print_decl_p) out << ";\n";
928}
929
930// Grids have ugly semantics.
931
936bool
937Grid::check_semantics(string &msg, bool all)
938{
940 return false;
941
942 msg = "";
943
944 if (!get_array()) {
945 msg += "Null grid base array in `" + name() + "'\n";
946 return false;
947 }
948
949 // Is it an array?
950 if (get_array()->type() != dods_array_c) {
951 msg += "Grid `" + name() + "'s' member `" + get_array()->name() + "' must be an array\n";
952 return false;
953 }
954
955 Array *av = (Array *)get_array(); // past test above, must be an array
956
957 // Array must be of a simple_type.
958 if (!av->var()->is_simple_type()) {
959 msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
960 return false;
961 }
962
963 // enough maps?
964 if ((unsigned)d_vars.size()-1 != av->dimensions()) {
965 msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
966 msg += av->name() + "'\n";
967 return false;
968 }
969
970 const string array_var_name = av->name();
971 Array::Dim_iter asi = av->dim_begin() ;
972 for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++, asi++) {
973
974 BaseType *mv = *mvi;
975
976 // check names
977 if (array_var_name == mv->name()) {
978 msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
979 return false;
980 }
981 // check types
982 if (mv->type() != dods_array_c) {
983 msg += "Grid map variable `" + mv->name() + "' is not an array\n";
984 return false;
985 }
986
987 Array *mv_a = (Array *)mv; // downcast to (Array *)
988
989 // Array must be of a simple_type.
990 if (!mv_a->var()->is_simple_type()) {
991 msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
992 return false;
993 }
994
995 // check shape
996 if (mv_a->dimensions() != 1) {// maps must have one dimension
997 msg += "Grid map variable `" + mv_a->name() + "' must be only one dimension\n";
998 return false;
999 }
1000 // size of map must match corresponding array dimension
1001 Array::Dim_iter mv_asi = mv_a->dim_begin() ;
1002 int mv_a_size = mv_a->dimension_size(mv_asi) ;
1003 int av_size = av->dimension_size(asi) ;
1004 if (mv_a_size != av_size) {
1005 msg += "Grid map variable `" + mv_a->name() + "'s' size does not match the size of array variable '";
1006 msg += get_array()->name() + "'s' cooresponding dimension\n";
1007 return false;
1008 }
1009 }
1010
1011 if (all) {
1012 if (!get_array()->check_semantics(msg, true))
1013 return false;
1014 for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++) {
1015 if (!(*mvi)->check_semantics(msg, true)) {
1016 return false;
1017 }
1018 }
1019 }
1020
1021 return true;
1022}
1023
1032void
1033Grid::dump(ostream &strm) const
1034{
1035 strm << DapIndent::LMarg << "Grid::dump - ("
1036 << (void *)this << ")" << endl ;
1037 DapIndent::Indent() ;
1038 Constructor::dump(strm) ;
1039
1040 DapIndent::UnIndent() ;
1041}
1042
1043} // namespace libdap
1044
A multidimensional array of identical data types.
Definition Array.h:113
virtual int dimension_start(Dim_iter i, bool constrained=false)
Return the start index of a dimension.
Definition Array.cc:765
virtual void clear_constraint()
Clears the projection; add each projected dimension explicitly using add_constraint.
Definition Array.cc:616
Dim_iter dim_end()
Definition Array.cc:696
virtual BaseType * ptr_duplicate()
Definition Array.cc:175
virtual int dimension_stop(Dim_iter i, bool constrained=false)
Return the stop index of the constraint.
Definition Array.cc:788
virtual void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Prints a DDS entry for the Array.
Definition Array.cc:1039
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:733
Dim_iter dim_begin()
Definition Array.cc:690
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition Array.cc:1124
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition Array.cc:1271
virtual unsigned int dimensions(bool constrained=false)
Return the total number of dimensions in the array.
Definition Array.cc:711
virtual int dimension_stride(Dim_iter i, bool constrained=false)
Returns the stride value of the constraint.
Definition Array.cc:812
Contains the attributes for a dataset.
Definition AttrTable.h:143
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition AttrTable.cc:410
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition AttrTable.cc:607
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition AttrTable.cc:307
void print_dap4(XMLWriter &xml)
virtual string get_name() const
Get the name of this attribute table.
Definition AttrTable.cc:238
void print_xml_writer(XMLWriter &xml)
The basic data type for the DODS DAP types.
Definition BaseType.h:118
virtual string type_name() const
Returns the type of the class instance as a string.
Definition BaseType.cc:379
virtual AttrTable & get_attr_table()
Definition BaseType.cc:582
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:320
virtual void set_parent(BaseType *parent)
Definition BaseType.cc:733
virtual D4Attributes * attributes()
Definition BaseType.cc:599
virtual std::string FQN() const
Definition BaseType.cc:332
virtual bool send_p()
Should this variable be sent?
Definition BaseType.cc:554
virtual bool is_simple_type() const
Returns true if the instance is a numeric, string or URL type variable.
Definition BaseType.cc:393
virtual BaseType * ptr_duplicate()=0
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition BaseType.cc:216
virtual void transfer_attributes(AttrTable *at)
Definition BaseType.cc:644
virtual bool check_semantics(string &msg, bool all=false)
Compare an object's current state with the semantics of its type.
Definition BaseType.cc:1209
virtual Type type() const
Returns the type of the class instance.
Definition BaseType.cc:365
virtual BaseType * var(const string &name, bool exact_match=true, btp_stack *s=0)
btp_stack no longer needed; use back pointers (BaseType::get_parent())
virtual void dump(ostream &strm) const
dumps information about this object
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:116
BaseType * array_var()
Returns the Grid Array.
Definition Grid.cc:501
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition Grid.cc:148
virtual void print_xml(ostream &out, string space=" ", bool constrained=false)
Definition Grid.cc:819
Map_iter map_begin()
Returns an iterator referencing the first Map vector.
Definition Grid.cc:525
Map_iter get_map_iter(int i)
Definition Grid.cc:563
virtual void set_array(Array *p_new_arr)
Definition Grid.cc:389
virtual void clear_constraint()
Definition Grid.cc:736
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition Grid.cc:900
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:753
virtual Array * prepend_map(Array *p_new_map, bool add_copy)
Definition Grid.cc:484
Grid(const string &n)
The Grid constructor.
Definition Grid.cc:86
Array * get_array()
Returns the Grid Array. This method returns the array using an Array*, so no cast is required.
Definition Grid.cc:518
virtual void transfer_attributes(AttrTable *at_container)
Definition Grid.cc:610
virtual bool projection_yields_grid()
Definition Grid.cc:692
Map_iter map_end()
Definition Grid.cc:537
Map_riter map_rend()
Definition Grid.cc:554
virtual void dump(ostream &strm) const
dumps information about this object
Definition Grid.cc:1033
virtual Array * add_map(Array *p_new_map, bool add_copy)
Definition Grid.cc:455
virtual int components(bool constrained=false)
Returns the number of components in the Grid object.
Definition Grid.cc:585
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition Grid.cc:847
virtual bool check_semantics(string &msg, bool all=false)
Return true if this Grid is well formed.
Definition Grid.cc:937
virtual void add_var(BaseType *bt, Part part)
Definition Grid.cc:264
virtual void add_var_nocopy(BaseType *bt, Part part)
Definition Grid.cc:330
Map_riter map_rbegin()
Returns an iterator referencing the first Map vector.
Definition Grid.cc:544
virtual bool is_dap2_only_type()
Definition Grid.cc:246
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
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