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 
59 using namespace std;
60 
61 namespace libdap {
62 
63 void
64 Grid::m_duplicate(const Grid &s)
65 {
66  d_is_array_set = s.d_is_array_set;
67 }
68 
78 Grid::Grid(const string &n) : Constructor(n, dods_grid_c), d_is_array_set(false)
79 {}
80 
92 Grid::Grid(const string &n, const string &d)
93  : Constructor(n, d, dods_grid_c), d_is_array_set(false)
94 {}
95 
97 Grid::Grid(const Grid &rhs) : Constructor(rhs)
98 {
99  m_duplicate(rhs);
100 }
101 
102 Grid::~Grid()
103 {
104  //d_array_var = 0; // Weak pointer; object will be freed by Constructor
105 }
106 
107 BaseType *
109 {
110  return new Grid(*this);
111 }
112 
113 Grid &
114 Grid::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 
126 void
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 
224 bool
226 {
227  return true;
228 }
229 
242 void
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 
308 void
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 
368 void 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 
433 Array*
434 Grid::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 
462 Array*
463 Grid::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 
479 BaseType *
481 {
482  return d_is_array_set ? *d_vars.begin() : nullptr;
483 }
484 
488 Array *
490 {
491  return dynamic_cast<Array*>(array_var());
492 }
493 
495 Grid::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 
507 Grid::Map_iter
509 {
510  return d_vars.end();
511 }
512 
514 Grid::Map_riter
516 {
517  // see above
518  return d_vars.rbegin();
519 }
520 
523 Grid::Map_riter
525 {
526  return d_is_array_set ? d_vars.rend() - 1: d_vars.rend();
527 }
528 
532 Grid::Map_iter
534 {
535  return d_is_array_set ? d_vars.begin() + 1 + i : d_vars.begin() + i;
536 }
537 
553 int
554 Grid::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)
627  get_attr_table().append_container(new AttrTable(*at->get_attr_table(at_p)), at->get_name(at_p));
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 
660 bool
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 
704 void
706 {
708  for (Map_iter m = map_begin(); m != map_end(); ++m)
709  dynamic_cast<Array&>(*(*m)).clear_constraint();
710 }
711 
712 void
713 Grid::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 
721 void
722 Grid::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 
776 void
777 Grid::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 
787 void
788 Grid::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 
796 class PrintGridFieldXMLWriter : public unary_function<BaseType *, void>
797 {
798  XMLWriter &d_xml;
799  bool d_constrained;
800  string d_tag;
801 public:
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 
815 void
816 Grid::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 
861 void
862 Grid::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 
869 void 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 
905 bool
906 Grid::check_semantics(string &msg, bool all)
907 {
908  if (!BaseType::check_semantics(msg))
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 
1001 void
1002 Grid::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 BaseType * ptr_duplicate()=0
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 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