libdap++  Updated for version 3.8.2
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 <functional>
41 #include <algorithm>
42 
43 #include "Grid.h"
44 #include "DDS.h"
45 #include "Array.h" // for downcasts
46 #include "util.h"
47 #include "InternalErr.h"
48 #include "escaping.h"
49 
50 #include "debug.h"
51 
52 using namespace std;
53 
54 namespace libdap {
55 
56 void
57 Grid::_duplicate(const Grid &s)
58 {
59  // Clear out any spurious vars in Constructor::_vars
60  _vars.clear(); // [mjohnson 10 Sep 2009]
61 
62  _array_var = s._array_var->ptr_duplicate();
63  _array_var->set_parent(this);
64  _vars.push_back(_array_var); // so the Constructor::Vars_Iter sees it [mjohnson 10 Sep 2009]
65 
66  Grid &cs = const_cast<Grid &>(s);
67 
68  for (Map_iter i = cs._map_vars.begin(); i != cs._map_vars.end(); i++) {
69  BaseType *btp = (*i)->ptr_duplicate();
70  btp->set_parent(this);
71  _map_vars.push_back(btp);
72  _vars.push_back(btp); // push all map vectors as weak refs into super::_vars which won't delete them [mjohnson 10 Sep 2009]
73  }
74 
75 }
76 
86 Grid::Grid(const string &n) : Constructor(n, dods_grid_c), _array_var(0)
87 {}
88 
100 Grid::Grid(const string &n, const string &d)
101  : Constructor(n, d, dods_grid_c), _array_var(0)
102 {}
103 
105 Grid::Grid(const Grid &rhs) : Constructor(rhs)
106 {
107  _duplicate(rhs);
108 }
109 
111 {
112  delete _array_var; _array_var = 0;
113 
114  for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
115  BaseType *btp = *i ;
116  delete btp ; btp = 0;
117  }
118 }
119 
120 BaseType *
122 {
123  return new Grid(*this);
124 }
125 
126 Grid &
128 {
129  if (this == &rhs)
130  return *this;
131 
132  delete _array_var; _array_var = 0;
133 
134  for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
135  BaseType *btp = *i ;
136  delete btp ;
137  }
138 
139  // this doesn't copy Constructor::_vars so...
140  dynamic_cast<Constructor &>(*this) = rhs;
141 
142  // we do it in here...
143  _duplicate(rhs);
144 
145  return *this;
146 }
147 
148 int
150 {
151  if (!leaves)
152  return _map_vars.size() + 1;
153  else {
154  int i = 0;
155  for (Map_iter j = _map_vars.begin(); j != _map_vars.end(); j++) {
156  j += (*j)->element_count(leaves);
157  }
158 
159  if (!get_array())
160  throw InternalErr(__FILE__, __LINE__, "No Grid arry!");
161 
162  i += get_array()->element_count(leaves);
163  return i;
164  }
165 }
166 
167 void
168 Grid::set_send_p(bool state)
169 {
170  _array_var->set_send_p(state);
171 
172  for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
173  (*i)->set_send_p(state);
174  }
175 
176  BaseType::set_send_p(state);
177 }
178 
179 void
180 Grid::set_read_p(bool state)
181 {
182  _array_var->set_read_p(state);
183 
184  for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
185  (*i)->set_read_p(state);
186  }
187 
188  BaseType::set_read_p(state);
189 }
190 
191 void
193 {
194  _array_var->set_in_selection(state);
195 
196  for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
197  (*i)->set_in_selection(state);
198  }
199 
201 }
202 
203 unsigned int
205 {
206  unsigned int sz = _array_var->width();
207 
208  for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
209  sz += (*i)->width();
210  }
211 
212  return sz;
213 }
214 
222 unsigned int
223 Grid::width(bool constrained)
224 {
225  unsigned int sz = 0;
226 
227  if (constrained) {
228  if (_array_var->send_p())
229  sz = _array_var->width(constrained);
230  }
231  else {
232  sz = _array_var->width(constrained);
233  }
234 
235  for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
236  if (constrained) {
237  if ((*i)->send_p())
238  sz += (*i)->width(constrained);
239  }
240  else {
241  sz += (*i)->width(constrained);
242  }
243  }
244 
245  return sz;
246 }
247 
248 void
250 {
251  dds.timeout_on();
252 
253  if (!read_p())
254  read(); // read() throws Error and InternalErr
255 
256  dds.timeout_off();
257 
258  if (_array_var->send_p())
259  _array_var->intern_data(eval, dds);
260 
261  for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
262  if ((*i)->send_p()) {
263  (*i)->intern_data(eval, dds);
264  }
265  }
266 }
267 
268 bool
270  Marshaller &m, bool ce_eval)
271 {
272  dds.timeout_on();
273 
274  // Re ticket 560: Get an object from eval that describes how to sample
275  // and rearrange the data, then perform those actions. Alternative:
276  // implement this as a selection function.
277 
278  if (!read_p())
279  read(); // read() throws Error and InternalErr
280 
281 #if EVAL
282  if (ce_eval && !eval.eval_selection(dds, dataset()))
283  return true;
284 #endif
285 
286  dds.timeout_off();
287 
288  if (_array_var->send_p())
289  _array_var->serialize(eval, dds, m, false);
290 
291  for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
292  if ((*i)->send_p()) {
293  (*i)->serialize(eval, dds, m, false);
294  }
295  }
296 
297  return true;
298 }
299 
300 bool
301 Grid::deserialize(UnMarshaller &um, DDS *dds, bool reuse)
302 {
303  _array_var->deserialize(um, dds, reuse);
304 
305  for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
306  (*i)->deserialize(um, dds, reuse);
307  }
308 
309  return false;
310 }
311 
319 unsigned int
320 Grid::val2buf(void *, bool)
321 {
322  return sizeof(Grid);
323 }
324 
328 unsigned int
330 {
331  return sizeof(Grid);
332 }
333 
334 BaseType *
335 Grid::var(const string &n, btp_stack &s)
336 {
337  return var(n, true, &s);
338 }
339 
344 BaseType *
345 Grid::var(const string &n, bool, btp_stack *s)
346 {
347  string name = www2id(n);
348 
349  if (_array_var->name() == name) {
350  if (s)
351  s->push(static_cast<BaseType *>(this));
352  return _array_var;
353  }
354 
355  for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
356  if ((*i)->name() == name) {
357  if (s)
358  s->push(static_cast<BaseType *>(this));
359  return *i;
360  }
361  }
362 
363  return 0;
364 }
365 
378 void
380 {
381  if (!bt) {
382  throw InternalErr(__FILE__, __LINE__,
383  "Passing NULL pointer as variable to be added.");
384  }
385 
386  if (part == array && _array_var) {
387  // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
388  throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
389  }
390 
391  // Set to the clone of bt if we get that far.
392  BaseType* bt_clone = 0;
393 
394  switch (part) {
395 
396  case array: {
397  // Refactored to use new set_array ([mjohnson 11 nov 2009])
398  Array* p_arr = dynamic_cast<Array*>(bt);
399  // avoid obvious broken semantics
400  if (!p_arr) {
401  throw InternalErr(__FILE__, __LINE__,
402  "Grid::add_var(): with Part==array: object is not an Array!");
403  }
404  // Add it as a copy to preserve old semantics. This sets parent too.
405  bt_clone = p_arr->ptr_duplicate();
406  set_array(static_cast<Array*>(bt_clone));
407  }
408  break;
409 
410  case maps: {
411  bt_clone = bt->ptr_duplicate();
412  bt_clone->set_parent(this);
413  _map_vars.push_back(bt_clone);
414  }
415  break;
416 
417  default: {
418  if (!_array_var) {
419  // Refactored to use new set_array ([mjohnson 11 nov 2009])
420  Array* p_arr = dynamic_cast<Array*>(bt);
421  // avoid obvious broken semantics
422  if (!p_arr) {
423  throw InternalErr(__FILE__, __LINE__,
424  "Grid::add_var(): with Part==array: object is not an Array!");
425  }
426  // Add it as a copy to preserve old semantics. This sets parent too.
427  bt_clone = p_arr->ptr_duplicate();
428  set_array(static_cast<Array*>(bt_clone));
429  }
430  else {
431  bt_clone = bt->ptr_duplicate();
432  bt_clone->set_parent(this);
433  _map_vars.push_back(bt_clone);
434  }
435  }
436  break;
437  }// switch
438 
439  // if we get ehre without exception, add the cloned object to the superclass variable iterator
440  // mjohnson 10 Sep 2009
441  // Add it to the superclass _vars list so we can iterate on superclass vars
442  if (bt_clone) {
443  _vars.push_back(bt_clone);
444  }
445 }
446 
462 void
464 {
465  if (!bt) {
466  throw InternalErr(__FILE__, __LINE__,
467  "Passing NULL pointer as variable to be added.");
468  }
469 
470  if (part == array && _array_var) {
471  // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
472  throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
473  }
474 
475  bt->set_parent(this);
476 
477  switch (part) {
478 
479  case array: {
480  // Refactored to use new set_array ([mjohnson 11 nov 2009])
481  Array* p_arr = dynamic_cast<Array*>(bt);
482  // avoid obvious broken semantics
483  if (!p_arr) {
484  throw InternalErr(__FILE__, __LINE__,
485  "Grid::add_var(): with Part==array: object is not an Array!");
486  }
487  set_array(static_cast<Array*>(bt));
488  }
489  break;
490 
491  case maps: {
492  //bt->set_parent(this);
493  _map_vars.push_back(bt);
494  }
495  break;
496 
497  default: {
498  if (!_array_var) {
499  // Refactored to use new set_array ([mjohnson 11 nov 2009])
500  Array* p_arr = dynamic_cast<Array*>(bt);
501  // avoid obvious broken semantics
502  if (!p_arr) {
503  throw InternalErr(__FILE__, __LINE__,
504  "Grid::add_var(): with Part==array: object is not an Array!");
505  }
506  set_array(static_cast<Array*>(bt));
507  }
508  else {
509  _map_vars.push_back(bt);
510  }
511  }
512  break;
513  }// switch
514 
515  // if we get here without exception, add the cloned object to the superclass variable iterator
516  // mjohnson 10 Sep 2009
517  // Add it to the superclass _vars list so we can iterate on superclass vars
518  if (bt) {
519  _vars.push_back(bt);
520  }
521 }
522 
532 void
534 {
535  if (!p_new_arr) {
536  throw InternalErr(__FILE__, __LINE__,
537  "Grid::set_array(): Cannot set to null!");
538  }
539  // Make sure not same memory, this would be evil.
540  if (p_new_arr == _array_var) {
541  return;
542  }
543  // clean out any old array
544  delete _array_var; _array_var = 0;
545  // Set the new, with parent
546  _array_var = p_new_arr;
547  _array_var->set_parent(this);
548 }
549 
576 Array*
577 Grid::add_map(Array* p_new_map, bool add_as_copy)
578 {
579  if (!p_new_map) {
580  throw InternalErr(__FILE__, __LINE__,
581  "Grid::add_map(): cannot have p_new_map null!");
582  }
583 
584  if (add_as_copy) {
585  p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
586  }
587 
588  p_new_map->set_parent(this);
589  _map_vars.push_back(p_new_map);
590  _vars.push_back(p_new_map); // allow superclass iter to work as well.
591 
592  // return the one that got put into the Grid.
593  return p_new_map;
594 }
595 
608 Array*
609 Grid::prepend_map(Array* p_new_map, bool add_copy)
610 {
611  if (add_copy)
612  {
613  p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
614  }
615 
616  p_new_map->set_parent(this);
617  _map_vars.insert(_map_vars.begin(), p_new_map);
618  _vars.insert(_vars.begin(), p_new_map); // allow superclass iter to work as well.
619 
620  // return the one that got put into the Grid.
621  return p_new_map;
622 }
623 
627 BaseType *
629 {
630  return _array_var;
631 }
632 
636 Array *
638 {
639  Array *a = dynamic_cast<Array*>(_array_var);
640  if (a)
641  return a;
642  else
643  throw InternalErr(__FILE__, __LINE__, "bad Cast");
644 }
645 
649 {
650  return _map_vars.begin() ;
651 }
652 
657 {
658  return _map_vars.end() ;
659 }
660 
664 {
665  return _map_vars.rbegin() ;
666 }
667 
672 {
673  return _map_vars.rend() ;
674 }
675 
681 {
682  return _map_vars.begin() + i;
683 }
684 
700 int
701 Grid::components(bool constrained)
702 {
703  int comp;
704 
705  if (constrained) {
706  comp = _array_var->send_p() ? 1 : 0;
707 
708  for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
709  if ((*i)->send_p()) {
710  comp++;
711  }
712  }
713  }
714  else {
715  comp = 1 + _map_vars.size();
716  }
717 
718  return comp;
719 }
720 
722 {
723  AttrTable *at = at_container->get_attr_table(name());
724 
725  if (at) {
726  at->set_is_global_attribute(false);
727 
729 
730  Map_iter map = map_begin();
731  while (map != map_end()) {
732  (*map)->transfer_attributes(at);
733  map++;
734  }
735 
736  // Trick: If an attribute that's within the container 'at' still has its
737  // is_global_attribute property set, then it's not really a global attr
738  // but instead an attribute that belongs to this Grid.
739  AttrTable::Attr_iter at_p = at->attr_begin();
740  while (at_p != at->attr_end()) {
741  if (at->is_global_attribute(at_p)) {
742  if (at->get_attr_type(at_p) == Attr_container)
744  *at->get_attr_table(at_p)), at->get_name(at_p));
745  else
746  get_attr_table().append_attr(at->get_name(at_p),
747  at->get_type(at_p), at->get_attr_vector(at_p));
748  }
749 
750  at_p++;
751  }
752  }
753 }
754 
755 // When projected (using whatever the current constraint provides in the way
756 // of a projection), is the object still a Grid?
757 
774 bool
776 {
777  // For each dimension in the Array part, check the corresponding Map
778  // vector to make sure it is present in the projected Grid. If for each
779  // projected dimension in the Array component, there is a matching Map
780  // vector, then the Grid is valid.
781  bool valid = true;
782  Array *a = (Array *)_array_var;
783 
784  // Don't bother checking if the Array component is not included.
785  if (!a->send_p())
786  return false;
787 
788  // If only one part is being sent, it's clearly not a grid (it must be
789  // the array part of the Grid that's being sent (given that the above
790  // test passed and the array is being sent).
791  if (components(true) == 1)
792  return false;
793 
794  Array::Dim_iter d = a->dim_begin() ;
795  Map_iter m = map_begin() ;
796 
797  while (valid && d != a->dim_end() && m != map_end()) {
798  Array &map = dynamic_cast<Array&>(**m);
799  if (a->dimension_size(d, true) && map.send_p()) {
800  // Check the matching Map vector; the Map projection must equal
801  // the Array dimension projection
802  Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
803  valid = map.dimension_start(fd, true) == a->dimension_start(d, true)
804  && map.dimension_stop(fd, true) == a->dimension_stop(d, true)
805  && map.dimension_stride(fd, true) == a->dimension_stride(d, true);
806  }
807  else {
808  valid = false;
809  }
810 
811  d++, m++;
812  }
813 
814  return valid;
815 }
816 
818 void
820 {
821  dynamic_cast<Array&>(*_array_var).clear_constraint();
822  for (Map_iter m = map_begin(); m != map_end(); ++m)
823  dynamic_cast<Array&>(*(*m)).clear_constraint();
824 }
825 
826 #if FILE_METHODS
827 void
828 Grid::print_decl(FILE *out, string space, bool print_semi,
829  bool constraint_info, bool constrained)
830 {
831  if (constrained && !send_p())
832  return;
833 
834  // The problem with the above is that if two Grids are projected and each
835  // contain one variable, say a map, and it happens to have the same name
836  // in each Grid, then without the enclosing Structures, the returned dataset
837  // has two variables with the same name at the same lexical level. So I'm
838  // removing the code above.
839  if (constrained && !projection_yields_grid()) {
840  fprintf(out, "%sStructure {\n", space.c_str()) ;
841 
842  _array_var->print_decl(out, space + " ", true, constraint_info,
843  constrained);
844 
845  for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
846  (*i)->print_decl(out, space + " ", true,
847  constraint_info, constrained);
848  }
849 
850  fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ;
851  }
852  else {
853  // The number of elements in the (projected) Grid must be such that
854  // we have a valid Grid object; send it as such.
855  fprintf(out, "%s%s {\n", space.c_str(), type_name().c_str()) ;
856 
857  fprintf(out, "%s Array:\n", space.c_str()) ;
858  _array_var->print_decl(out, space + " ", true, constraint_info,
859  constrained);
860 
861  fprintf(out, "%s Maps:\n", space.c_str()) ;
862  for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
863  (*i)->print_decl(out, space + " ", true,
864  constraint_info, constrained);
865  }
866 
867  fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ;
868  }
869 
870  if (constraint_info) {
871  if (send_p())
872  fprintf( out, ": Send True");
873  else
874  fprintf( out, ": Send False");
875  }
876 
877  if (print_semi)
878  fprintf(out, ";\n") ;
879 
880  return;
881 }
882 #endif
883 
884 void
885 Grid::print_decl(ostream &out, string space, bool print_semi,
886  bool constraint_info, bool constrained)
887 {
888  if (constrained && !send_p())
889  return;
890 
891  // See comment for the FILE* version of this method.
892  if (constrained && !projection_yields_grid()) {
893  out << space << "Structure {\n" ;
894 
895  _array_var->print_decl(out, space + " ", true, constraint_info,
896  constrained);
897 
898  for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
899  (*i)->print_decl(out, space + " ", true,
900  constraint_info, constrained);
901  }
902 
903  out << space << "} " << id2www(name()) ;
904  }
905  else {
906  // The number of elements in the (projected) Grid must be such that
907  // we have a valid Grid object; send it as such.
908  out << space << type_name() << " {\n" ;
909 
910  out << space << " Array:\n" ;
911  _array_var->print_decl(out, space + " ", true, constraint_info,
912  constrained);
913 
914  out << space << " Maps:\n" ;
915  for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
916  (*i)->print_decl(out, space + " ", true,
917  constraint_info, constrained);
918  }
919 
920  out << space << "} " << id2www(name()) ;
921  }
922 
923  if (constraint_info) {
924  if (send_p())
925  out << ": Send True";
926  else
927  out << ": Send False";
928  }
929 
930  if (print_semi)
931  out << ";\n" ;
932 
933  return;
934 }
935 
936 #if FILE_METHODS
937 class PrintMapField : public unary_function<BaseType *, void>
938 {
939  FILE *d_out;
940  string d_space;
941  bool d_constrained;
942  string d_tag;
943 public:
944  PrintMapField(FILE *o, string s, bool c, const string &t = "Map")
945  : d_out(o), d_space(s), d_constrained(c), d_tag(t)
946  {}
947 
948  void operator()(BaseType *btp)
949  {
950  Array *a = dynamic_cast<Array*>(btp);
951  if (!a)
952  throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
953  a->print_xml_core(d_out, d_space, d_constrained, d_tag);
954  }
955 };
956 
960 void
961 Grid::print_xml(FILE *out, string space, bool constrained)
962 {
963  if (constrained && !send_p())
964  return;
965 
966  if (constrained && !projection_yields_grid()) {
967  fprintf(out, "%s<Structure", space.c_str());
968  if (!name().empty())
969  fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
970 
971  fprintf(out, ">\n");
972 
973  get_attr_table().print_xml(out, space + " ", constrained);
974 
975  get_array()->print_xml(out, space + " ", constrained);
976 
977  for_each(map_begin(), map_end(),
978  PrintMapField(out, space + " ", constrained, "Array"));
979 
980  fprintf(out, "%s</Structure>\n", space.c_str());
981  }
982  else {
983  // The number of elements in the (projected) Grid must be such that
984  // we have a valid Grid object; send it as such.
985  fprintf(out, "%s<Grid", space.c_str());
986  if (!name().empty())
987  fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
988 
989  fprintf(out, ">\n");
990 
991  get_attr_table().print_xml(out, space + " ", constrained);
992 
993  get_array()->print_xml(out, space + " ", constrained);
994 
995  for_each(map_begin(), map_end(),
996  PrintMapField(out, space + " ", constrained));
997 
998  fprintf(out, "%s</Grid>\n", space.c_str());
999  }
1000 }
1001 #endif
1002 
1003 class PrintMapFieldStrm : public unary_function<BaseType *, void>
1004 {
1005  ostream &d_out;
1006  string d_space;
1007  bool d_constrained;
1008  string d_tag;
1009 public:
1010  PrintMapFieldStrm(ostream &o, string s, bool c, const string &t = "Map")
1011  : d_out(o), d_space(s), d_constrained(c), d_tag(t)
1012  {}
1013 
1014  void operator()(BaseType *btp)
1015  {
1016  Array *a = dynamic_cast<Array*>(btp);
1017  if (!a)
1018  throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
1019  a->print_xml_core(d_out, d_space, d_constrained, d_tag);
1020  }
1021 };
1022 
1026 void
1027 Grid::print_xml(ostream &out, string space, bool constrained)
1028 {
1029  if (constrained && !send_p())
1030  return;
1031 
1032  if (constrained && !projection_yields_grid()) {
1033  out << space << "<Structure" ;
1034  if (!name().empty())
1035  out << " name=\"" << id2xml(name()) << "\"" ;
1036 
1037  out << ">\n" ;
1038 
1039  get_attr_table().print_xml(out, space + " ", constrained);
1040 
1041  get_array()->print_xml(out, space + " ", constrained);
1042 
1043  for_each(map_begin(), map_end(),
1044  PrintMapFieldStrm(out, space + " ", constrained, "Array"));
1045 
1046  out << space << "</Structure>\n" ;
1047  }
1048  else {
1049  // The number of elements in the (projected) Grid must be such that
1050  // we have a valid Grid object; send it as such.
1051  out << space << "<Grid" ;
1052  if (!name().empty())
1053  out << " name=\"" << id2xml(name()) << "\"" ;
1054 
1055  out << ">\n" ;
1056 
1057  get_attr_table().print_xml(out, space + " ", constrained);
1058 
1059  get_array()->print_xml(out, space + " ", constrained);
1060 
1061  for_each(map_begin(), map_end(),
1062  PrintMapFieldStrm(out, space + " ", constrained));
1063 
1064  out << space << "</Grid>\n" ;
1065  }
1066 }
1067 
1068 
1069 class PrintGridFieldXMLWriter : public unary_function<BaseType *, void>
1070 {
1071  XMLWriter &d_xml;
1072  bool d_constrained;
1073  string d_tag;
1074 public:
1075  PrintGridFieldXMLWriter(XMLWriter &x, bool c, const string &t = "Map")
1076  : d_xml(x), d_constrained(c), d_tag(t)
1077  {}
1078 
1079  void operator()(BaseType *btp)
1080  {
1081  Array *a = dynamic_cast<Array*>(btp);
1082  if (!a)
1083  throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
1084  a->print_xml_writer_core(d_xml, d_constrained, d_tag);
1085  }
1086 };
1087 
1088 void
1089 Grid::print_xml_writer(XMLWriter &xml, bool constrained)
1090 {
1091  if (constrained && !send_p())
1092  return;
1093 
1094  if (constrained && !projection_yields_grid()) {
1095  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Structure") < 0)
1096  throw InternalErr(__FILE__, __LINE__, "Could not write Structure element");
1097 
1098  if (!name().empty())
1099  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
1100  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1101 
1103 
1104  get_array()->print_xml_writer(xml, constrained);
1105 
1106  for_each(map_begin(), map_end(),
1107  PrintGridFieldXMLWriter(xml, constrained, "Array"));
1108 
1109  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1110  throw InternalErr(__FILE__, __LINE__, "Could not end Structure element");
1111  }
1112  else {
1113  // The number of elements in the (projected) Grid must be such that
1114  // we have a valid Grid object; send it as such.
1115  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Grid") < 0)
1116  throw InternalErr(__FILE__, __LINE__, "Could not write Grid element");
1117 
1118  if (!name().empty())
1119  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
1120  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1121 
1123 
1124  get_array()->print_xml_writer(xml, constrained);
1125 
1126  for_each(map_begin(), map_end(),
1127  PrintGridFieldXMLWriter(xml, constrained, "Map"));
1128 
1129  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1130  throw InternalErr(__FILE__, __LINE__, "Could not end Grid element");
1131  }
1132 }
1133 
1134 #if FILE_METHODS
1135 void
1136 Grid::print_val(FILE *out, string space, bool print_decl_p)
1137 {
1138  if (print_decl_p) {
1139  print_decl(out, space, false);
1140  fprintf(out, " = ") ;
1141  }
1142 
1143  // If we are printing a value on the client-side, projection_yields_grid
1144  // should not be called since we don't *have* a projection without a
1145  // contraint. I think that if we are here and send_p() is not true, then
1146  // the value of this function should be ignored. 4/6/2000 jhrg
1147  bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
1148  if (pyg || !send_p())
1149  fprintf(out, "{ Array: ") ;
1150  else
1151  fprintf(out, "{") ;
1152  _array_var->print_val(out, "", false);
1153  if (pyg || !send_p())
1154  fprintf(out, " Maps: ") ;
1155  for (Map_citer i = _map_vars.begin(); i != _map_vars.end();
1156  i++, (void)(i != _map_vars.end() && fprintf(out, ", "))) {
1157  (*i)->print_val(out, "", false);
1158  }
1159  fprintf(out, " }") ;
1160 
1161  if (print_decl_p)
1162  fprintf(out, ";\n") ;
1163 }
1164 #endif
1165 
1166 void
1167 Grid::print_val(ostream &out, string space, bool print_decl_p)
1168 {
1169  if (print_decl_p) {
1170  print_decl(out, space, false);
1171  out << " = " ;
1172  }
1173 
1174  // If we are printing a value on the client-side, projection_yields_grid
1175  // should not be called since we don't *have* a projection without a
1176  // Constraint. I think that if we are here and send_p() is not true, then
1177  // the value of this function should be ignored. 4/6/2000 jhrg
1178  bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
1179  if (pyg || !send_p())
1180  out << "{ Array: " ;
1181  else
1182  out << "{" ;
1183  _array_var->print_val(out, "", false);
1184  if (pyg || !send_p())
1185  out << " Maps: " ;
1186  for (Map_citer i = _map_vars.begin(); i != _map_vars.end();
1187  i++, (void)(i != _map_vars.end() && out << ", ")) {
1188  (*i)->print_val(out, "", false);
1189  }
1190  out << " }" ;
1191 
1192  if (print_decl_p)
1193  out << ";\n" ;
1194 }
1195 
1196 // Grids have ugly semantics.
1197 
1202 bool
1203 Grid::check_semantics(string &msg, bool all)
1204 {
1205  if (!BaseType::check_semantics(msg))
1206  return false;
1207 
1208  msg = "";
1209 
1210  if (!_array_var) {
1211  msg += "Null grid base array in `" + name() + "'\n";
1212  return false;
1213  }
1214 
1215  // Is it an array?
1216  if (_array_var->type() != dods_array_c) {
1217  msg += "Grid `" + name() + "'s' member `" + _array_var->name() + "' must be an array\n";
1218  return false;
1219  }
1220 
1221  Array *av = (Array *)_array_var; // past test above, must be an array
1222 
1223  // Array must be of a simple_type.
1224  if (!av->var()->is_simple_type()) {
1225  msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
1226  return false;
1227  }
1228 
1229  // enough maps?
1230  if ((unsigned)_map_vars.size() != av->dimensions()) {
1231  msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
1232  msg += av->name() + "'\n";
1233  return false;
1234  }
1235 
1236  const string array_var_name = av->name();
1237  Array::Dim_iter asi = av->dim_begin() ;
1238  for (Map_iter mvi = _map_vars.begin();
1239  mvi != _map_vars.end(); mvi++, asi++) {
1240 
1241  BaseType *mv = *mvi;
1242 
1243  // check names
1244  if (array_var_name == mv->name()) {
1245  msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
1246  return false;
1247  }
1248  // check types
1249  if (mv->type() != dods_array_c) {
1250  msg += "Grid map variable `" + mv->name() + "' is not an array\n";
1251  return false;
1252  }
1253 
1254  Array *mv_a = (Array *)mv; // downcast to (Array *)
1255 
1256  // Array must be of a simple_type.
1257  if (!mv_a->var()->is_simple_type()) {
1258  msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
1259  return false;
1260  }
1261 
1262  // check shape
1263  if (mv_a->dimensions() != 1) {// maps must have one dimension
1264  msg += "Grid map variable `" + mv_a->name() + "' must be only one dimension\n";
1265  return false;
1266  }
1267  // size of map must match corresponding array dimension
1268  Array::Dim_iter mv_asi = mv_a->dim_begin() ;
1269  int mv_a_size = mv_a->dimension_size(mv_asi) ;
1270  int av_size = av->dimension_size(asi) ;
1271  if (mv_a_size != av_size) {
1272  msg += "Grid map variable `" + mv_a->name() + "'s' size does not match the size of array variable '";
1273  msg += _array_var->name() + "'s' cooresponding dimension\n";
1274  return false;
1275  }
1276  }
1277 
1278  if (all) {
1279  if (!_array_var->check_semantics(msg, true))
1280  return false;
1281  for (Map_iter mvi = _map_vars.begin(); mvi != _map_vars.end(); mvi++) {
1282  if (!(*mvi)->check_semantics(msg, true)) {
1283  return false;
1284  }
1285  }
1286  }
1287 
1288  return true;
1289 }
1290 
1299 void
1300 Grid::dump(ostream &strm) const
1301 {
1302  strm << DapIndent::LMarg << "Grid::dump - ("
1303  << (void *)this << ")" << endl ;
1304  DapIndent::Indent() ;
1305  Constructor::dump(strm) ;
1306  if (_array_var) {
1307  strm << DapIndent::LMarg << "array var: " << endl ;
1308  DapIndent::Indent() ;
1309  _array_var->dump(strm) ;
1311  }
1312  else {
1313  strm << DapIndent::LMarg << "array var: null" << endl ;
1314  }
1315  strm << DapIndent::LMarg << "map var: " << endl ;
1316  DapIndent::Indent() ;
1317  Map_citer i = _map_vars.begin() ;
1318  Map_citer ie = _map_vars.end() ;
1319  for (; i != ie; i++) {
1320  (*i)->dump(strm) ;
1321  }
1324 }
1325 
1326 } // namespace libdap
1327