libdap++  Updated for version 3.12.0
Grid.cc
Go to the documentation of this file.
1 
2 // -*- mode: c++; c-basic-offset:4 -*-
3 
4 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
5 // Access Protocol.
6 
7 // Copyright (c) 2002,2003 OPeNDAP, Inc.
8 // Author: James Gallagher <jgallagher@opendap.org>
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25 
26 // (c) COPYRIGHT URI/MIT 1994-1999
27 // Please read the full copyright statement in the file COPYRIGHT_URI.
28 //
29 // Authors:
30 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
31 
32 // implementation for Grid.
33 //
34 // jhrg 9/15/94
35 
36 #include "config.h"
37 
38 // #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 using namespace std;
54 
55 namespace libdap {
56 
57 void
58 Grid::m_duplicate(const Grid &s)
59 {
60  // Clear out any spurious vars in Constructor::d_vars
61  d_vars.clear(); // [mjohnson 10 Sep 2009]
62 
63  d_array_var = s.d_array_var->ptr_duplicate();
64  d_array_var->set_parent(this);
65  d_vars.push_back(d_array_var); // so the Constructor::Vars_Iter sees it [mjohnson 10 Sep 2009]
66 
67  Grid &cs = const_cast<Grid &>(s);
68 
69  for (Map_iter i = cs.d_map_vars.begin(); i != cs.d_map_vars.end(); i++) {
70  BaseType *btp = (*i)->ptr_duplicate();
71  btp->set_parent(this);
72  d_map_vars.push_back(btp);
73  d_vars.push_back(btp); // push all map vectors as weak refs into super::d_vars which won't delete them [mjohnson 10 Sep 2009]
74  }
75 
76 }
77 
87 Grid::Grid(const string &n) : Constructor(n, dods_grid_c), d_array_var(0)
88 {}
89 
101 Grid::Grid(const string &n, const string &d)
102  : Constructor(n, d, dods_grid_c), d_array_var(0)
103 {}
104 
106 Grid::Grid(const Grid &rhs) : Constructor(rhs)
107 {
108  m_duplicate(rhs);
109 }
110 
112 {
113  delete d_array_var; d_array_var = 0;
114 
115  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
116  BaseType *btp = *i ;
117  delete btp ; btp = 0;
118  }
119 }
120 
121 BaseType *
123 {
124  return new Grid(*this);
125 }
126 
127 Grid &
129 {
130  if (this == &rhs)
131  return *this;
132 
133  delete d_array_var; d_array_var = 0;
134 
135  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
136  BaseType *btp = *i ;
137  delete btp ;
138  }
139 
140  // this doesn't copy Constructor::d_vars so...
141  dynamic_cast<Constructor &>(*this) = rhs;
142 
143  // we do it in here...
144  m_duplicate(rhs);
145 
146  return *this;
147 }
148 
154 bool
156 {
157  return true;
158 }
159 
160 int
162 {
163  if (!leaves)
164  return d_map_vars.size() + 1;
165  else {
166  int i = 0;
167  for (Map_iter j = d_map_vars.begin(); j != d_map_vars.end(); j++) {
168  j += (*j)->element_count(leaves);
169  }
170 
171  if (!get_array())
172  throw InternalErr(__FILE__, __LINE__, "No Grid array!");
173 
174  i += get_array()->element_count(leaves);
175  return i;
176  }
177 }
178 
179 void
180 Grid::set_send_p(bool state)
181 {
182  d_array_var->set_send_p(state);
183 
184  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
185  (*i)->set_send_p(state);
186  }
187 
188  BaseType::set_send_p(state);
189 }
190 
191 void
192 Grid::set_read_p(bool state)
193 {
194  d_array_var->set_read_p(state);
195 
196  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
197  (*i)->set_read_p(state);
198  }
199 
200  BaseType::set_read_p(state);
201 }
202 
203 void
205 {
206  d_array_var->set_in_selection(state);
207 
208  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
209  (*i)->set_in_selection(state);
210  }
211 
213 }
214 #if 0
215 unsigned int
216 Grid::width(bool)
217 {
218  unsigned int sz = d_array_var->width();
219 
220  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
221  sz += (*i)->width();
222  }
223 
224  return sz;
225 }
226 #endif
227 
234 unsigned int
235 Grid::width(bool constrained)
236 {
237  unsigned int sz = 0;
238 
239  if (constrained) {
240  if (d_array_var->send_p())
241  sz = d_array_var->width(constrained);
242  }
243  else {
244  sz = d_array_var->width(constrained);
245  }
246 
247  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
248  if (constrained) {
249  if ((*i)->send_p())
250  sz += (*i)->width(constrained);
251  }
252  else {
253  sz += (*i)->width(constrained);
254  }
255  }
256 
257  return sz;
258 }
259 
260 void
262 {
263  dds.timeout_on();
264 
265  if (!read_p())
266  read(); // read() throws Error and InternalErr
267 
268  dds.timeout_off();
269 
270  if (d_array_var->send_p())
271  d_array_var->intern_data(eval, dds);
272 
273  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
274  if ((*i)->send_p()) {
275  (*i)->intern_data(eval, dds);
276  }
277  }
278 }
279 
280 bool
281 Grid::serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval)
282 {
283  DBG(cerr << "In Grid::serialize()" << endl);
284 
285  dds.timeout_on();
286 
287  // Re ticket 560: Get an object from eval that describes how to sample
288  // and rearrange the data, then perform those actions. Alternative:
289  // implement this as a selection function.
290  DBG(cerr << "In Grid::serialize(), before read() - read_p() returned: " << read_p() << endl);
291 
292  if (!read_p())
293  read(); // read() throws Error and InternalErr
294 
295  DBG(cerr << "In Grid::serialize(), past read() - read_p() returned: " << read_p() << endl);
296 
297  #if EVAL
298  if (ce_eval && !eval.eval_selection(dds, dataset()))
299  return true;
300 #endif
301 
302  dds.timeout_off();
303 
304  if (d_array_var->send_p()) {
305 #ifdef CHECKSUMS
306  XDRStreamMarshaller *sm = dynamic_cast<XDRStreamMarshaller*>(&m);
307  if (sm && sm->checksums())
308  sm->reset_checksum();
309 
310  d_array_var->serialize(eval, dds, m, false);
311 
312  if (sm && sm->checksums())
313  sm->get_checksum();
314 #else
315  DBG(cerr << "About to call Array::serialize() in Grid::serialize" << endl);
316  d_array_var->serialize(eval, dds, m, false);
317 #endif
318  }
319 
320  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
321  if ((*i)->send_p()) {
322 #ifdef CHECKSUMS
323  XDRStreamMarshaller *sm = dynamic_cast<XDRStreamMarshaller*>(&m);
324  if (sm && sm->checksums())
325  sm->reset_checksum();
326 
327  (*i)->serialize(eval, dds, m, false);
328 
329  if (sm && sm->checksums())
330  sm->get_checksum();
331 #else
332  (*i)->serialize(eval, dds, m, false);
333 #endif
334  }
335  }
336 
337  return true;
338 }
339 
340 bool
341 Grid::deserialize(UnMarshaller &um, DDS *dds, bool reuse)
342 {
343  d_array_var->deserialize(um, dds, reuse);
344 
345  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
346  (*i)->deserialize(um, dds, reuse);
347  }
348 
349  return false;
350 }
351 
352 #if 0
353 
360 unsigned int
361 Grid::val2buf(void *, bool)
362 {
363  return sizeof(Grid);
364 }
365 
369 unsigned int
370 Grid::buf2val(void **)
371 {
372  return sizeof(Grid);
373 }
374 #endif
375 
376 BaseType *
377 Grid::var(const string &n, btp_stack &s)
378 {
379  return var(n, true, &s);
380 }
381 
386 BaseType *
387 Grid::var(const string &n, bool, btp_stack *s)
388 {
389  string name = www2id(n);
390 
391  if (d_array_var->name() == name) {
392  if (s)
393  s->push(static_cast<BaseType *>(this));
394  return d_array_var;
395  }
396 
397  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
398  if ((*i)->name() == name) {
399  if (s)
400  s->push(static_cast<BaseType *>(this));
401  return *i;
402  }
403  }
404 
405  return 0;
406 }
407 
420 void
422 {
423  if (!bt)
424  throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
425 #if 0
426  if (bt->is_dap4_only_type())
427  throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 Grid.");
428 #endif
429  if (part == array && d_array_var) {
430  // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
431  throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
432  }
433 
434  // Set to the clone of bt if we get that far.
435  BaseType* bt_clone = 0;
436 
437  switch (part) {
438 
439  case array: {
440  // Refactored to use new set_array ([mjohnson 11 nov 2009])
441  Array* p_arr = dynamic_cast<Array*>(bt);
442  // avoid obvious broken semantics
443  if (!p_arr) {
444  throw InternalErr(__FILE__, __LINE__,
445  "Grid::add_var(): with Part==array: object is not an Array!");
446  }
447  // Add it as a copy to preserve old semantics. This sets parent too.
448  bt_clone = p_arr->ptr_duplicate();
449  set_array(static_cast<Array*>(bt_clone));
450  }
451  break;
452 
453  case maps: {
454  bt_clone = bt->ptr_duplicate();
455  bt_clone->set_parent(this);
456  d_map_vars.push_back(bt_clone);
457  }
458  break;
459 
460  default: {
461  if (!d_array_var) {
462  // Refactored to use new set_array ([mjohnson 11 nov 2009])
463  Array* p_arr = dynamic_cast<Array*>(bt);
464  // avoid obvious broken semantics
465  if (!p_arr) {
466  throw InternalErr(__FILE__, __LINE__,
467  "Grid::add_var(): with Part==array: object is not an Array!");
468  }
469  // Add it as a copy to preserve old semantics. This sets parent too.
470  bt_clone = p_arr->ptr_duplicate();
471  set_array(static_cast<Array*>(bt_clone));
472  }
473  else {
474  bt_clone = bt->ptr_duplicate();
475  bt_clone->set_parent(this);
476  d_map_vars.push_back(bt_clone);
477  }
478  }
479  break;
480  }// switch
481 
482  // if we get ehre without exception, add the cloned object to the superclass variable iterator
483  // mjohnson 10 Sep 2009
484  // Add it to the superclass d_vars list so we can iterate on superclass vars
485  if (bt_clone) {
486  d_vars.push_back(bt_clone);
487  }
488 }
489 
505 void
507 {
508  if (!bt)
509  throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
510 #if 0
511  if (bt->is_dap4_only_type())
512  throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 Grid.");
513 #endif
514  if (part == array && d_array_var) {
515  // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
516  throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
517  }
518 
519  bt->set_parent(this);
520 
521  switch (part) {
522 
523  case array: {
524  // Refactored to use new set_array ([mjohnson 11 nov 2009])
525  Array* p_arr = dynamic_cast<Array*>(bt);
526  // avoid obvious broken semantics
527  if (!p_arr) {
528  throw InternalErr(__FILE__, __LINE__,
529  "Grid::add_var(): with Part==array: object is not an Array!");
530  }
531  set_array(static_cast<Array*>(bt));
532  }
533  break;
534 
535  case maps: {
536  //bt->set_parent(this);
537  d_map_vars.push_back(bt);
538  }
539  break;
540 
541  default: {
542  if (!d_array_var) {
543  // Refactored to use new set_array ([mjohnson 11 nov 2009])
544  Array* p_arr = dynamic_cast<Array*>(bt);
545  // avoid obvious broken semantics
546  if (!p_arr) {
547  throw InternalErr(__FILE__, __LINE__,
548  "Grid::add_var(): with Part==array: object is not an Array!");
549  }
550  set_array(static_cast<Array*>(bt));
551  }
552  else {
553  d_map_vars.push_back(bt);
554  }
555  }
556  break;
557  }// switch
558 
559  // if we get here without exception, add the cloned object to the superclass variable iterator
560  // mjohnson 10 Sep 2009
561  // Add it to the superclass d_vars list so we can iterate on superclass vars
562  if (bt) {
563  d_vars.push_back(bt);
564  }
565 }
566 
576 void
578 {
579  if (!p_new_arr) {
580  throw InternalErr(__FILE__, __LINE__,
581  "Grid::set_array(): Cannot set to null!");
582  }
583  // Make sure not same memory, this would be evil.
584  if (p_new_arr == d_array_var) {
585  return;
586  }
587  // clean out any old array
588  delete d_array_var; d_array_var = 0;
589  // Set the new, with parent
590  d_array_var = p_new_arr;
591  d_array_var->set_parent(this);
592 }
593 
620 Array*
621 Grid::add_map(Array* p_new_map, bool add_as_copy)
622 {
623  if (!p_new_map)
624  throw InternalErr(__FILE__, __LINE__, "Grid::add_map(): cannot have p_new_map null!");
625 #if 0
626  if (p_new_map->is_dap4_only_type())
627  throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 Grid.");
628 #endif
629  if (add_as_copy)
630  p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
631 
632  p_new_map->set_parent(this);
633  d_map_vars.push_back(p_new_map);
634  d_vars.push_back(p_new_map); // allow superclass iter to work as well.
635 
636  // return the one that got put into the Grid.
637  return p_new_map;
638 }
639 
652 Array*
653 Grid::prepend_map(Array* p_new_map, bool add_copy)
654 {
655  if (add_copy)
656  {
657  p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
658  }
659 
660  p_new_map->set_parent(this);
661  d_map_vars.insert(d_map_vars.begin(), p_new_map);
662  d_vars.insert(d_vars.begin(), p_new_map); // allow superclass iter to work as well.
663 
664  // return the one that got put into the Grid.
665  return p_new_map;
666 }
667 
671 BaseType *
673 {
674  return d_array_var;
675 }
676 
680 Array *
682 {
683  Array *a = dynamic_cast<Array*>(d_array_var);
684  if (a)
685  return a;
686  else
687  throw InternalErr(__FILE__, __LINE__, "bad Cast");
688 }
689 
693 {
694  return d_map_vars.begin() ;
695 }
696 
701 {
702  return d_map_vars.end() ;
703 }
704 
708 {
709  return d_map_vars.rbegin() ;
710 }
711 
716 {
717  return d_map_vars.rend() ;
718 }
719 
725 {
726  return d_map_vars.begin() + i;
727 }
728 
744 int
745 Grid::components(bool constrained)
746 {
747  int comp;
748 
749  if (constrained) {
750  comp = d_array_var->send_p() ? 1 : 0;
751 
752  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
753  if ((*i)->send_p()) {
754  comp++;
755  }
756  }
757  }
758  else {
759  comp = 1 + d_map_vars.size();
760  }
761 
762  return comp;
763 }
764 
766 {
767  AttrTable *at = at_container->get_attr_table(name());
768 
769  if (at) {
770  at->set_is_global_attribute(false);
771 
773 
774  Map_iter map = map_begin();
775  while (map != map_end()) {
776  (*map)->transfer_attributes(at);
777  map++;
778  }
779 
780  // Trick: If an attribute that's within the container 'at' still has its
781  // is_global_attribute property set, then it's not really a global attr
782  // but instead an attribute that belongs to this Grid.
783  AttrTable::Attr_iter at_p = at->attr_begin();
784  while (at_p != at->attr_end()) {
785  if (at->is_global_attribute(at_p)) {
786  if (at->get_attr_type(at_p) == Attr_container)
788  *at->get_attr_table(at_p)), at->get_name(at_p));
789  else
790  get_attr_table().append_attr(at->get_name(at_p),
791  at->get_type(at_p), at->get_attr_vector(at_p));
792  }
793 
794  at_p++;
795  }
796  }
797 }
798 
799 // When projected (using whatever the current constraint provides in the way
800 // of a projection), is the object still a Grid?
801 
818 bool
820 {
821  // For each dimension in the Array part, check the corresponding Map
822  // vector to make sure it is present in the projected Grid. If for each
823  // projected dimension in the Array component, there is a matching Map
824  // vector, then the Grid is valid.
825  bool valid = true;
826  Array *a = (Array *)d_array_var;
827 
828  // Don't bother checking if the Array component is not included.
829  if (!a->send_p())
830  return false;
831 
832  // If only one part is being sent, it's clearly not a grid (it must be
833  // the array part of the Grid that's being sent (given that the above
834  // test passed and the array is being sent).
835  if (components(true) == 1)
836  return false;
837 
838  Array::Dim_iter d = a->dim_begin() ;
839  Map_iter m = map_begin() ;
840 
841  while (valid && d != a->dim_end() && m != map_end()) {
842  Array &map = dynamic_cast<Array&>(**m);
843  if (a->dimension_size(d, true) && map.send_p()) {
844  // Check the matching Map vector; the Map projection must equal
845  // the Array dimension projection
846  Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
847  valid = map.dimension_start(fd, true) == a->dimension_start(d, true)
848  && map.dimension_stop(fd, true) == a->dimension_stop(d, true)
849  && map.dimension_stride(fd, true) == a->dimension_stride(d, true);
850  }
851  else {
852  valid = false;
853  }
854 
855  d++, m++;
856  }
857 
858  return valid;
859 }
860 
862 void
864 {
865  dynamic_cast<Array&>(*d_array_var).clear_constraint();
866  for (Map_iter m = map_begin(); m != map_end(); ++m)
867  dynamic_cast<Array&>(*(*m)).clear_constraint();
868 }
869 
870 void
871 Grid::print_decl(FILE *out, string space, bool print_semi,
872  bool constraint_info, bool constrained)
873 {
874  ostringstream oss;
875  print_decl(oss, space, print_semi, constraint_info, constrained);
876  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
877 }
878 
879 void
880 Grid::print_decl(ostream &out, string space, bool print_semi,
881  bool constraint_info, bool constrained)
882 {
883  if (constrained && !send_p())
884  return;
885 
886  // See comment for the FILE* version of this method.
887  if (constrained && !projection_yields_grid()) {
888  out << space << "Structure {\n" ;
889 
890  d_array_var->print_decl(out, space + " ", true, constraint_info,
891  constrained);
892 
893  for (Map_citer i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
894  (*i)->print_decl(out, space + " ", true,
895  constraint_info, constrained);
896  }
897 
898  out << space << "} " << id2www(name()) ;
899  }
900  else {
901  // The number of elements in the (projected) Grid must be such that
902  // we have a valid Grid object; send it as such.
903  out << space << type_name() << " {\n" ;
904 
905  out << space << " Array:\n" ;
906  d_array_var->print_decl(out, space + " ", true, constraint_info,
907  constrained);
908 
909  out << space << " Maps:\n" ;
910  for (Map_citer i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
911  (*i)->print_decl(out, space + " ", true,
912  constraint_info, constrained);
913  }
914 
915  out << space << "} " << id2www(name()) ;
916  }
917 
918  if (constraint_info) {
919  if (send_p())
920  out << ": Send True";
921  else
922  out << ": Send False";
923  }
924 
925  if (print_semi)
926  out << ";\n" ;
927 
928  return;
929 }
930 
934 void
935 Grid::print_xml(FILE *out, string space, bool constrained)
936 {
937  XMLWriter xml(space);
938  print_xml_writer(xml, constrained);
939  fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
940 }
941 
945 void
946 Grid::print_xml(ostream &out, string space, bool constrained)
947 {
948  XMLWriter xml(space);
949  print_xml_writer(xml, constrained);
950  out << xml.get_doc();
951 }
952 
953 
954 class PrintGridFieldXMLWriter : public unary_function<BaseType *, void>
955 {
956  XMLWriter &d_xml;
957  bool d_constrained;
958  string d_tag;
959 public:
960  PrintGridFieldXMLWriter(XMLWriter &x, bool c, const string &t = "Map")
961  : d_xml(x), d_constrained(c), d_tag(t)
962  {}
963 
964  void operator()(BaseType *btp)
965  {
966  Array *a = dynamic_cast<Array*>(btp);
967  if (!a)
968  throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
969  a->print_xml_writer_core(d_xml, d_constrained, d_tag);
970  }
971 };
972 
973 void
974 Grid::print_xml_writer(XMLWriter &xml, bool constrained)
975 {
976  if (constrained && !send_p())
977  return;
978 
979  if (constrained && !projection_yields_grid()) {
980  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Structure") < 0)
981  throw InternalErr(__FILE__, __LINE__, "Could not write Structure element");
982 
983  if (!name().empty())
984  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
985  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
986 
988 
989  get_array()->print_xml_writer(xml, constrained);
990 
991  for_each(map_begin(), map_end(),
992  PrintGridFieldXMLWriter(xml, constrained, "Array"));
993 
994  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
995  throw InternalErr(__FILE__, __LINE__, "Could not end Structure element");
996  }
997  else {
998  // The number of elements in the (projected) Grid must be such that
999  // we have a valid Grid object; send it as such.
1000  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Grid") < 0)
1001  throw InternalErr(__FILE__, __LINE__, "Could not write Grid element");
1002 
1003  if (!name().empty())
1004  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
1005  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1006 
1008 
1009  get_array()->print_xml_writer(xml, constrained);
1010 
1011  for_each(map_begin(), map_end(),
1012  PrintGridFieldXMLWriter(xml, constrained, "Map"));
1013 
1014  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1015  throw InternalErr(__FILE__, __LINE__, "Could not end Grid element");
1016  }
1017 }
1018 
1019 void
1020 Grid::print_val(FILE *out, string space, bool print_decl_p)
1021 {
1022  ostringstream oss;
1023  print_val(oss, space, print_decl_p);
1024  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1025 }
1026 
1027 void
1028 Grid::print_val(ostream &out, string space, bool print_decl_p)
1029 {
1030  if (print_decl_p) {
1031  print_decl(out, space, false);
1032  out << " = " ;
1033  }
1034 
1035  // If we are printing a value on the client-side, projection_yields_grid
1036  // should not be called since we don't *have* a projection without a
1037  // Constraint. I think that if we are here and send_p() is not true, then
1038  // the value of this function should be ignored. 4/6/2000 jhrg
1039  bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
1040  if (pyg || !send_p())
1041  out << "{ Array: " ;
1042  else
1043  out << "{" ;
1044  d_array_var->print_val(out, "", false);
1045  if (pyg || !send_p())
1046  out << " Maps: " ;
1047  for (Map_citer i = d_map_vars.begin(); i != d_map_vars.end();
1048  i++, (void)(i != d_map_vars.end() && out << ", ")) {
1049  (*i)->print_val(out, "", false);
1050  }
1051  out << " }" ;
1052 
1053  if (print_decl_p)
1054  out << ";\n" ;
1055 }
1056 
1057 // Grids have ugly semantics.
1058 
1063 bool
1064 Grid::check_semantics(string &msg, bool all)
1065 {
1066  if (!BaseType::check_semantics(msg))
1067  return false;
1068 
1069  msg = "";
1070 
1071  if (!d_array_var) {
1072  msg += "Null grid base array in `" + name() + "'\n";
1073  return false;
1074  }
1075 
1076  // Is it an array?
1077  if (d_array_var->type() != dods_array_c) {
1078  msg += "Grid `" + name() + "'s' member `" + d_array_var->name() + "' must be an array\n";
1079  return false;
1080  }
1081 
1082  Array *av = (Array *)d_array_var; // past test above, must be an array
1083 
1084  // Array must be of a simple_type.
1085  if (!av->var()->is_simple_type()) {
1086  msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
1087  return false;
1088  }
1089 
1090  // enough maps?
1091  if ((unsigned)d_map_vars.size() != av->dimensions()) {
1092  msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
1093  msg += av->name() + "'\n";
1094  return false;
1095  }
1096 
1097  const string array_var_name = av->name();
1098  Array::Dim_iter asi = av->dim_begin() ;
1099  for (Map_iter mvi = d_map_vars.begin();
1100  mvi != d_map_vars.end(); mvi++, asi++) {
1101 
1102  BaseType *mv = *mvi;
1103 
1104  // check names
1105  if (array_var_name == mv->name()) {
1106  msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
1107  return false;
1108  }
1109  // check types
1110  if (mv->type() != dods_array_c) {
1111  msg += "Grid map variable `" + mv->name() + "' is not an array\n";
1112  return false;
1113  }
1114 
1115  Array *mv_a = (Array *)mv; // downcast to (Array *)
1116 
1117  // Array must be of a simple_type.
1118  if (!mv_a->var()->is_simple_type()) {
1119  msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
1120  return false;
1121  }
1122 
1123  // check shape
1124  if (mv_a->dimensions() != 1) {// maps must have one dimension
1125  msg += "Grid map variable `" + mv_a->name() + "' must be only one dimension\n";
1126  return false;
1127  }
1128  // size of map must match corresponding array dimension
1129  Array::Dim_iter mv_asi = mv_a->dim_begin() ;
1130  int mv_a_size = mv_a->dimension_size(mv_asi) ;
1131  int av_size = av->dimension_size(asi) ;
1132  if (mv_a_size != av_size) {
1133  msg += "Grid map variable `" + mv_a->name() + "'s' size does not match the size of array variable '";
1134  msg += d_array_var->name() + "'s' cooresponding dimension\n";
1135  return false;
1136  }
1137  }
1138 
1139  if (all) {
1140  if (!d_array_var->check_semantics(msg, true))
1141  return false;
1142  for (Map_iter mvi = d_map_vars.begin(); mvi != d_map_vars.end(); mvi++) {
1143  if (!(*mvi)->check_semantics(msg, true)) {
1144  return false;
1145  }
1146  }
1147  }
1148 
1149  return true;
1150 }
1151 
1160 void
1161 Grid::dump(ostream &strm) const
1162 {
1163  strm << DapIndent::LMarg << "Grid::dump - ("
1164  << (void *)this << ")" << endl ;
1165  DapIndent::Indent() ;
1166  Constructor::dump(strm) ;
1167  if (d_array_var) {
1168  strm << DapIndent::LMarg << "array var: " << endl ;
1169  DapIndent::Indent() ;
1170  d_array_var->dump(strm) ;
1172  }
1173  else {
1174  strm << DapIndent::LMarg << "array var: null" << endl ;
1175  }
1176  strm << DapIndent::LMarg << "map var: " << endl ;
1177  DapIndent::Indent() ;
1178  Map_citer i = d_map_vars.begin() ;
1179  Map_citer ie = d_map_vars.end() ;
1180  for (; i != ie; i++) {
1181  (*i)->dump(strm) ;
1182  }
1185 }
1186 
1187 } // namespace libdap
1188