libdap  Updated for version 3.18.2
Array.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 Array.
33 //
34 // jhrg 9/13/94
35 
36 #include "config.h"
37 
38 // #define DODS_DEBUG
39 
40 #include <algorithm>
41 #include <functional>
42 #include <sstream>
43 
44 #include "Array.h"
45 
46 #include "D4Attributes.h"
47 #include "DMR.h"
48 #include "D4Dimensions.h"
49 #include "D4Maps.h"
50 #include "D4Group.h"
51 #include "D4EnumDefs.h"
52 #include "D4Enum.h"
53 #include "XMLWriter.h"
54 
55 #include "util.h"
56 #include "debug.h"
57 #include "InternalErr.h"
58 #include "escaping.h"
59 
60 using namespace std;
61 
62 namespace libdap {
63 
64 Array::dimension::dimension(D4Dimension *d) : dim(d), use_sdim_for_slice(true)
65 {
66  size = d->size();
67  name = d->name();
68 
69  start = 0;
70  stop = size - 1;
71  stride = 1;
72  c_size = size;
73 }
74 
75 void
76 Array::_duplicate(const Array &a)
77 {
78  _shape = a._shape;
79 
80  // Deep copy the Maps if they are being used.
81  if (a.d_maps) {
82  d_maps = new D4Maps(*(a.d_maps));
83  }
84  else {
85  d_maps = 0;
86  }
87  // d_maps = a.d_maps ? new D4Maps(*(a.d_maps)) : 0;
88 }
89 
90 // The first method of calculating length works when only one dimension is
91 // constrained and you want the others to appear in total. This is important
92 // when selecting from grids since users may not select from all dimensions
93 // in which case that means they want the whole thing. Array projection
94 // should probably work this way too, but it doesn't. 9/21/2001 jhrg
95 
102 void
104 {
105  int length = 1;
106  for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
107 #if 0
108  // If the size of any dimension is zero, then the array is not
109  // capable of storing any values. jhrg 1/28/16
110  length *= (*i).c_size > 0 ? (*i).c_size : 1;
111 #endif
112  length *= (*i).c_size;
113  }
114 
115  set_length(length);
116 }
117 
118 // Construct an instance of Array. The (BaseType *) is assumed to be
119 // allocated using new - The dtor for Vector will delete this object.
120 
136 Array::Array(const string &n, BaseType *v, bool is_dap4 /* default:false */)
137  : Vector(n, 0, dods_array_c, is_dap4), d_maps(0)
138 {
139  add_var(v); // Vector::add_var() stores null if v is null
140 }
141 
155 Array::Array(const string &n, const string &d, BaseType *v, bool is_dap4 /* default:false */)
156  : Vector(n, d, 0, dods_array_c, is_dap4), d_maps(0)
157 {
158  add_var(v); // Vector::add_var() stores null if v is null
159 }
160 
162 Array::Array(const Array &rhs) : Vector(rhs)
163 {
164  _duplicate(rhs);
165 }
166 
169 {
170  delete d_maps;
171 }
172 
173 BaseType *
175 {
176  return new Array(*this);
177 }
178 
179 Array &
180 Array::operator=(const Array &rhs)
181 {
182  if (this == &rhs)
183  return *this;
184 
185  dynamic_cast<Vector &>(*this) = rhs;
186 
187  _duplicate(rhs);
188 
189  return *this;
190 }
191 
192 BaseType *
194 {
195  Array *dest = static_cast<Array*>(ptr_duplicate());
196 
197  // Process the Array's dimensions, making D4 shared dimensions for
198  // D2 dimensions that are named. If there is just a size, don't make
199  // a D4Dimension (In DAP4 you cannot share a dimension unless it has
200  // a name). jhrg 3/18/14
201 
202  D4Dimensions *dims = root->dims();
203  for (Array::Dim_iter d = dest->dim_begin(), e = dest->dim_end(); d != e; ++d) {
204  if (!(*d).name.empty()) {
205  // If a D4Dimension with the name already exists, use it.
206  D4Dimension *d4_dim = dims->find_dim((*d).name);
207  if (!d4_dim) {
208  d4_dim = new D4Dimension((*d).name, (*d).size);
209  dims->add_dim_nocopy(d4_dim);
210  }
211  // TODO Revisit this decision. jhrg 3/18/14
212  // ...in case the name/size are different, make a unique D4Dimension
213  // but don't fiddle with the name. Not sure I like this idea, so I'm
214  // making the case explicit (could be rolled in to the block above).
215  // jhrg 3/18/14
216  //
217  // This is causing problems in the FITS handler because there are cases
218  // where two arrays have dimensions with the same name but different
219  // sizes. The deserializing code is using the first size listed, which is
220  // wrong in some cases. I'm going to try making this new D4Dimension using
221  // the dim name along with the variable name. jhrg 8/15/14
222  else if (d4_dim->size() != (unsigned long) (*d).size) {
223  d4_dim = new D4Dimension((*d).name + "_" + name(), (*d).size);
224  dims->add_dim_nocopy(d4_dim);
225  }
226  // At this point d4_dim's name and size == those of (*d) so just set
227  // the D4Dimension pointer so it matches the one in the D4Group.
228  (*d).dim = d4_dim;
229  }
230  }
231 
232  // Copy the D2 attributes to D4 Attributes
234 
235  dest->set_is_dap4(true);
236 
237  return dest;
238 }
239 
251 void
252 Array::update_dimension_pointers(D4Dimensions *old_dims, D4Dimensions *new_dims)
253 {
254  std::vector<dimension>::iterator i = _shape.begin(), e = _shape.end();
255  while (i != e) {
256  D4Dimensions::D4DimensionsIter old_i = old_dims->dim_begin(), old_e = old_dims->dim_end();
257  while (old_i != old_e) {
258  if ((*i).dim == *old_i) {
259  (*i).dim = new_dims->find_dim((*old_i)->name());
260  }
261  ++old_i;
262  }
263 
264  ++i;
265  }
266 }
267 
292 void
294 {
295  // If 'v' is an Array, add the template instance to this object and
296  // then copy the dimension information. Odd semantics; I wonder if this
297  //is ever used. jhrg 6/13/12
298  if (v && v->type() == dods_array_c) {
299  Array *a = static_cast<Array*>(v);
300  Vector::add_var(a->var());
301 
302  Dim_iter i = a->dim_begin();
303  Dim_iter i_end = a->dim_end();
304  while (i != i_end) {
306  ++i;
307  }
308  }
309  else {
310  Vector::add_var(v);
311  }
312 }
313 
314 void
315 Array::add_var_nocopy(BaseType *v, Part)
316 {
317  // If 'v' is an Array, add the template instance to this object and
318  // then copy the dimension information. Odd semantics; I wonder if this
319  //is ever used. jhrg 6/13/12
320  if (v && v->type() == dods_array_c) {
321  Array &a = dynamic_cast<Array&>(*v);
322  Vector::add_var_nocopy(a.var());
323  Dim_iter i = a.dim_begin();
324  Dim_iter i_end = a.dim_end();
325  while (i != i_end) {
327  ++i;
328  }
329  }
330  else {
331  Vector::add_var_nocopy(v);
332  }
333 }
334 
346 void
347 Array::append_dim(int size, const string &name)
348 {
349  dimension d(size, www2id(name));
350  _shape.push_back(d);
351 
352  update_length();
353 }
354 
355 void
357 {
358  dimension d(/*dim->size(), www2id(dim->name()),*/ dim);
359  _shape.push_back(d);
360 
361  update_length();
362 }
363 
369 void
370 Array::prepend_dim(int size, const string& name/* = "" */)
371 {
372  dimension d(size, www2id(name));
373  // Shifts the whole array, but it's tiny in general
374  _shape.insert(_shape.begin(), d);
375 
376  update_length(); // the number is ignored...
377 }
378 
379 void
381 {
382  dimension d(/*dim->size(), www2id(dim->name()),*/ dim);
383  // Shifts the whole array, but it's tiny in general
384  _shape.insert(_shape.begin(), d);
385 
386  update_length(); // the number is ignored...
387 }
388 
392 void
394 {
395  _shape.clear();
396 }
403 void
405 {
406  set_length(-1);
407 
408  for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
409  (*i).start = 0;
410  (*i).stop = (*i).size - 1;
411  (*i).stride = 1;
412  (*i).c_size = (*i).size;
413 
414  update_length();
415  }
416 }
417 
418 
428 void
430 {
432 }
433 
434 // Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n
435 // is explicit.
436 static const char *array_sss = \
437 "Invalid constraint parameters: At least one of the start, stride or stop \n\
438 specified do not match the array variable.";
439 
460 void
461 Array::add_constraint(Dim_iter i, int start, int stride, int stop)
462 {
463  dimension &d = *i ;
464 
465  // if stop is -1, set it to the array's max element index
466  // jhrg 12/20/12
467  if (stop == -1)
468  stop = d.size - 1;
469 
470  // Check for bad constraints.
471  // Jose Garcia
472  // Usually invalid data for a constraint is the user's mistake
473  // because they build a wrong URL in the client side.
474  if (start >= d.size || stop >= d.size || stride > d.size || stride <= 0)
475  throw Error(malformed_expr, array_sss);
476 
477  if (((stop - start) / stride + 1) > d.size)
478  throw Error(malformed_expr, array_sss);
479 
480  d.start = start;
481  d.stop = stop;
482  d.stride = stride;
483 
484  d.c_size = (stop - start) / stride + 1;
485 
486  DBG(cerr << "add_constraint: c_size = " << d.c_size << endl);
487 
488  update_length();
489 
490  d.use_sdim_for_slice = false;
491 }
492 
493 void
495 {
496  dimension &d = *i ;
497 
498  if (dim->constrained())
499  add_constraint(i, dim->c_start(), dim->c_stride(), dim->c_stop());
500 
501  dim->set_used_by_projected_var(true);
502 
503  // In this case the value below overrides the value for use_sdim_for_slice
504  // set in the above call. jhrg 12/20/13
505  d.use_sdim_for_slice = true;
506 }
507 
511 {
512  return _shape.begin() ;
513 }
514 
518 {
519  return _shape.end() ;
520 }
521 
522 //TODO Many of these methods take a bool parameter that serves no use; remove.
523 
532 unsigned int
533 Array::dimensions(bool /*constrained*/)
534 {
535  return _shape.size();
536 }
537 
555 int
556 Array::dimension_size(Dim_iter i, bool constrained)
557 {
558  int size = 0;
559 
560  if (!_shape.empty()) {
561  if (constrained)
562  size = (*i).c_size;
563  else
564  size = (*i).size;
565  }
566 
567  return size;
568 }
569 
588 int
589 Array::dimension_start(Dim_iter i, bool /*constrained*/)
590 {
591  return (!_shape.empty()) ? (*i).start : 0;
592 }
593 
612 int
613 Array::dimension_stop(Dim_iter i, bool /*constrained*/)
614 {
615  return (!_shape.empty()) ? (*i).stop : 0;
616 }
617 
637 int
638 Array::dimension_stride(Dim_iter i, bool /*constrained*/)
639 {
640  return (!_shape.empty()) ? (*i).stride : 0;
641 }
642 
653 string
655 {
656  // Jose Garcia
657  // Since this method is public, it is possible for a user
658  // to call it before the Array object has been properly set
659  // this will cause an exception which is the user's fault.
660  // (User in this context is the developer of the surrogate library.)
661  if (_shape.empty())
662  throw InternalErr(__FILE__, __LINE__,
663  "*This* array has no dimensions.");
664  return (*i).name;
665 }
666 
667 D4Dimension *
668 Array::dimension_D4dim(Dim_iter i)
669 {
670  return (!_shape.empty()) ? (*i).dim : 0;
671 }
672 
673 D4Maps *
674 Array::maps()
675 {
676  if (!d_maps) d_maps = new D4Maps(this); // init with this as parent
677  return d_maps;
678 }
679 
680 #if 0
681 
687 unsigned int Array::width(bool constrained) const
688 {
689 
690  if (constrained) {
691  // This preserves the original method's semantics when we ask for the
692  // size of the constrained array but no constraint has been applied.
693  // In this case, length will be -1. Wrong, I know...
694  return length() * var()->width(constrained);
695  }
696  else {
697  int length = 1;
698  for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
699  length *= dimension_size(i, false);
700  }
701  return length * var()->width(false);
702  }
703 }
704 #endif
705 
706 class PrintD4ArrayDimXMLWriter: public unary_function<Array::dimension&, void> {
707  XMLWriter &xml;
708  // Was this variable constrained using local/direct slicing? i.e., is d_local_constraint set?
709  // If so, don't use shared dimensions; instead emit Dim elements that are anonymous.
710  bool d_constrained;
711 public:
712 
713  PrintD4ArrayDimXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) { }
714 
715  void operator()(Array::dimension &d)
716  {
717  // This duplicates code in D4Dimensions (where D4Dimension::print_dap4() is defined
718  // because of the need to print the constrained size of a dimension. I think that
719  // the constraint information has to be kept here and not in the dimension (since they
720  // are shared dims). Could hack print_dap4() to take the constrained size, however.
721  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dim") < 0)
722  throw InternalErr(__FILE__, __LINE__, "Could not write Dim element");
723 
724  string name = (d.dim) ? d.dim->fully_qualified_name() : d.name;
725  // If there is a name, there must be a Dimension (named dimension) in scope
726  // so write its name but not its size.
727  if (!d_constrained && !name.empty()) {
728  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name.c_str())
729  < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
730  }
731  else if (d.use_sdim_for_slice) {
732  assert(!name.empty());
733  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name.c_str())
734  < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
735  }
736  else {
737  ostringstream size;
738  size << (d_constrained ? d.c_size : d.size);
739  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size",
740  (const xmlChar*) size.str().c_str()) < 0)
741  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
742  }
743 
744  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
745  throw InternalErr(__FILE__, __LINE__, "Could not end Dim element");
746  }
747 };
748 
749 class PrintD4ConstructorVarXMLWriter: public unary_function<BaseType*, void> {
750  XMLWriter &xml;
751  bool d_constrained;
752 public:
753  PrintD4ConstructorVarXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) { }
754 
755  void operator()(BaseType *btp)
756  {
757  btp->print_dap4(xml, d_constrained);
758  }
759 };
760 
761 class PrintD4MapXMLWriter: public unary_function<D4Map*, void> {
762  XMLWriter &xml;
763 
764 public:
765  PrintD4MapXMLWriter(XMLWriter &xml) : xml(xml) { }
766 
767  void operator()(D4Map *m)
768  {
769  m->print_dap4(xml);
770  }
771 };
772 
778 void
779 Array::print_dap4(XMLWriter &xml, bool constrained /* default: false*/)
780 {
781  if (constrained && !send_p()) return;
782 
783  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) var()->type_name().c_str()) < 0)
784  throw InternalErr(__FILE__, __LINE__, "Could not write " + type_name() + " element");
785 
786  if (!name().empty())
787  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
788  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
789 
790  // Hack job... Copied from D4Enum::print_xml_writer. jhrg 11/12/13
791  if (var()->type() == dods_enum_c) {
792  D4Enum *e = static_cast<D4Enum*>(var());
793  string path = e->enumeration()->name();
794  if (e->enumeration()->parent()) {
795  // print the FQN for the enum def; D4Group::FQN() includes the trailing '/'
796  path = static_cast<D4Group*>(e->enumeration()->parent()->parent())->FQN() + path;
797  }
798  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "enum", (const xmlChar*)path.c_str()) < 0)
799  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for enum");
800  }
801 
802  if (prototype()->is_constructor_type()) {
803  Constructor &c = static_cast<Constructor&>(*prototype());
804  for_each(c.var_begin(), c.var_end(), PrintD4ConstructorVarXMLWriter(xml, constrained));
805  // bind2nd(mem_fun_ref(&BaseType::print_dap4), xml));
806  }
807 
808  // Drop the local_constraint which is per-array and use a per-dimension on instead
809  for_each(dim_begin(), dim_end(), PrintD4ArrayDimXMLWriter(xml, constrained));
810 
811  attributes()->print_dap4(xml);
812 
813  for_each(maps()->map_begin(), maps()->map_end(), PrintD4MapXMLWriter(xml));
814 
815  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
816  throw InternalErr(__FILE__, __LINE__, "Could not end " + type_name() + " element");
817 }
818 
836 void
837 Array::print_decl(FILE *out, string space, bool print_semi,
838  bool constraint_info, bool constrained)
839 {
840  ostringstream oss;
841  print_decl(oss, space, print_semi, constraint_info, constrained);
842  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
843 }
844 
862 void Array::print_decl(ostream &out, string space, bool print_semi, bool constraint_info, bool constrained)
863 {
864  if (constrained && !send_p()) return;
865 
866  // print it, but w/o semicolon
867  var()->print_decl(out, space, false, constraint_info, constrained);
868 
869  for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
870  out << "[";
871  if ((*i).name != "") {
872  out << id2www((*i).name) << " = ";
873  }
874  if (constrained) {
875  out << (*i).c_size << "]";
876  }
877  else {
878  out << (*i).size << "]";
879  }
880  }
881 
882  if (print_semi) {
883  out << ";\n";
884  }
885 }
886 
890 void
891 Array::print_xml(FILE *out, string space, bool constrained)
892 {
893  XMLWriter xml(space);
894  print_xml_writer_core(xml, constrained, "Array");
895  fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
896 }
897 
901 void
902 Array::print_xml(ostream &out, string space, bool constrained)
903 {
904  XMLWriter xml(space);
905  print_xml_writer_core(xml, constrained, "Array");
906  out << xml.get_doc();
907 }
908 
912 void
913 Array::print_as_map_xml(FILE *out, string space, bool constrained)
914 {
915  XMLWriter xml(space);
916  print_xml_writer_core(xml, constrained, "Map");
917  fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
918 }
919 
923 void
924 Array::print_as_map_xml(ostream &out, string space, bool constrained)
925 {
926  XMLWriter xml(space);
927  print_xml_writer_core(xml, constrained, "Map");
928  out << xml.get_doc();
929 }
930 
934 void
935 Array::print_xml_core(FILE *out, string space, bool constrained, string tag)
936 {
937  XMLWriter xml(space);
938  print_xml_writer_core(xml, constrained, tag);
939  fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
940 }
941 
945 void
946 Array::print_xml_core(ostream &out, string space, bool constrained, string tag)
947 {
948  XMLWriter xml(space);
949  print_xml_writer_core(xml, constrained, tag);
950  out << xml.get_doc();
951 }
952 
953 void
954 Array::print_xml_writer(XMLWriter &xml, bool constrained)
955 {
956  print_xml_writer_core(xml, constrained, "Array");
957 }
958 
959 void
960 Array::print_as_map_xml_writer(XMLWriter &xml, bool constrained)
961 {
962  print_xml_writer_core(xml, constrained, "Map");
963 }
964 
965 class PrintArrayDimXMLWriter : public unary_function<Array::dimension&, void>
966 {
967  XMLWriter &xml;
968  bool d_constrained;
969 public:
970  PrintArrayDimXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) {}
971 
972  void operator()(Array::dimension &d)
973  {
974  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"dimension") < 0)
975  throw InternalErr(__FILE__, __LINE__, "Could not write dimension element");
976 
977  if (!d.name.empty())
978  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d.name.c_str()) < 0)
979  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
980 
981  ostringstream size;
982  size << (d_constrained ? d.c_size : d.size);
983  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size", (const xmlChar*)size.str().c_str()) < 0)
984  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
985 
986  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
987  throw InternalErr(__FILE__, __LINE__, "Could not end dimension element");
988  }
989 };
990 
991 void
992 Array::print_xml_writer_core(XMLWriter &xml, bool constrained, string tag)
993 {
994  if (constrained && !send_p())
995  return;
996 
997  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)tag.c_str()) < 0)
998  throw InternalErr(__FILE__, __LINE__, "Could not write " + tag + " element");
999 
1000  if (!name().empty())
1001  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
1002  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1003 
1005 
1006  BaseType *btp = var();
1007  string tmp_name = btp->name();
1008  btp->set_name("");
1009  btp->print_xml_writer(xml, constrained);
1010  btp->set_name(tmp_name);
1011 
1012  for_each(dim_begin(), dim_end(), PrintArrayDimXMLWriter(xml, constrained));
1013 
1014  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1015  throw InternalErr(__FILE__, __LINE__, "Could not end " + tag + " element");
1016 }
1017 
1029 unsigned int
1030 Array::print_array(FILE *out, unsigned int index, unsigned int dims,
1031  unsigned int shape[])
1032 {
1033  ostringstream oss;
1034  unsigned int i = print_array(oss, index, dims, shape);
1035  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1036 
1037  return i;
1038 }
1039 
1051 unsigned int Array::print_array(ostream &out, unsigned int index, unsigned int dims, unsigned int shape[])
1052 {
1053  if (dims == 1) {
1054  out << "{";
1055 
1056  // Added test in case this method is passed an array with no elements. jhrg 1/27/16
1057  if (shape[0] >= 1) {
1058  for (unsigned i = 0; i < shape[0] - 1; ++i) {
1059  var(index++)->print_val(out, "", false);
1060  out << ", ";
1061  }
1062  var(index++)->print_val(out, "", false);
1063  }
1064 
1065  out << "}";
1066 
1067  return index;
1068  }
1069  else {
1070  out << "{";
1071  // Fixed an off-by-one error in the following loop. Since the array
1072  // length is shape[dims-1]-1 *and* since we want one less dimension
1073  // than that, the correct limit on this loop is shape[dims-2]-1. From
1074  // Todd Karakasian.
1075  //
1076  // The saga continues; the loop test should be `i < shape[0]-1'. jhrg
1077  // 9/12/96.
1078  //
1079  // For arrays that hold zero values but have rank > 1, the print out
1080  // may look a little odd (e.g., x[4][0] will print as { {}, {}, {}, {} })
1081  // but it's not wrong and this is really for debugging mostly. jhrg 1/28/16
1082  if (shape[0] > 0) {
1083  for (unsigned i = 0; i < shape[0] - 1; ++i) {
1084  index = print_array(out, index, dims - 1, shape + 1);
1085  out << ",";
1086  }
1087 
1088  index = print_array(out, index, dims - 1, shape + 1);
1089  }
1090 
1091  out << "}";
1092 
1093  return index;
1094  }
1095 }
1096 
1097 void
1098 Array::print_val(FILE *out, string space, bool print_decl_p)
1099 {
1100  ostringstream oss;
1101  print_val(oss, space, print_decl_p);
1102  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1103 }
1104 
1105 void
1106 Array::print_val(ostream &out, string space, bool print_decl_p)
1107 {
1108  // print the declaration if print decl is true.
1109  // for each dimension,
1110  // for each element,
1111  // print the array given its shape, number of dimensions.
1112  // Add the `;'
1113 
1114  if (print_decl_p) {
1115  print_decl(out, space, false, false, false);
1116  out << " = " ;
1117  }
1118 
1119  unsigned int *shape = new unsigned int[dimensions(true)];
1120  unsigned int index = 0;
1121  for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i)
1122  shape[index++] = dimension_size(i, true);
1123 
1124  print_array(out, 0, dimensions(true), shape);
1125 
1126  delete [] shape; shape = 0;
1127 
1128  if (print_decl_p) {
1129  out << ";\n" ;
1130  }
1131 }
1132 
1142 bool
1143 Array::check_semantics(string &msg, bool)
1144 {
1145  bool sem = BaseType::check_semantics(msg) && !_shape.empty();
1146 
1147  if (!sem)
1148  msg = "An array variable must have dimensions";
1149 
1150  return sem;
1151 }
1152 
1161 void
1162 Array::dump(ostream &strm) const
1163 {
1164  strm << DapIndent::LMarg << "Array::dump - ("
1165  << (void *)this << ")" << endl ;
1166  DapIndent::Indent() ;
1167  Vector::dump(strm) ;
1168  strm << DapIndent::LMarg << "shape:" << endl ;
1169  DapIndent::Indent() ;
1170  Dim_citer i = _shape.begin() ;
1171  Dim_citer ie = _shape.end() ;
1172  unsigned int dim_num = 0 ;
1173  for (; i != ie; i++) {
1174  strm << DapIndent::LMarg << "dimension " << dim_num++ << ":"
1175  << endl ;
1176  DapIndent::Indent() ;
1177  strm << DapIndent::LMarg << "name: " << (*i).name << endl ;
1178  strm << DapIndent::LMarg << "size: " << (*i).size << endl ;
1179  strm << DapIndent::LMarg << "start: " << (*i).start << endl ;
1180  strm << DapIndent::LMarg << "stop: " << (*i).stop << endl ;
1181  strm << DapIndent::LMarg << "stride: " << (*i).stride << endl ;
1182  strm << DapIndent::LMarg << "constrained size: " << (*i).c_size
1183  << endl ;
1184  DapIndent::UnIndent() ;
1185  }
1186  DapIndent::UnIndent() ;
1187  DapIndent::UnIndent() ;
1188 }
1189 
1190 } // namespace libdap
1191 
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: Array.cc:954
virtual void reset_constraint()
Reset constraint to select entire array.
Definition: Array.cc:404
virtual void add_constraint(Dim_iter i, int start, int stride, int stop)
Adds a constraint to an Array dimension.
Definition: Array.cc:461
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:265
virtual bool check_semantics(string &msg, bool all=false)
Check semantic features of the Array.
Definition: Array.cc:1143
virtual void print_xml_core(FILE *out, string space, bool constrained, string tag)
Definition: Array.cc:935
vector< D4Dimension * >::iterator D4DimensionsIter
Iterator used for D4Dimensions.
Definition: D4Dimensions.h:122
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Array.cc:1162
virtual void print_decl(FILE *out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Print an ASCII representation of the variable structure.
Definition: BaseType.cc:924
Array(const string &n, BaseType *v, bool is_dap4=false)
Array constructor.
Definition: Array.cc:136
virtual unsigned int dimensions(bool constrained=false)
Return the total number of dimensions in the array.
Definition: Array.cc:533
Part
Names the parts of multi-section constructor data types.
Definition: Type.h:48
void add_var(BaseType *v, Part p=nil)
Add the BaseType pointer to this constructor type instance.
Definition: Array.cc:293
virtual void set_name(const string &n)
Sets the name of the class instance.
Definition: BaseType.cc:289
int stop
The constraint end index.
Definition: Array.h:149
Holds a one-dimensional collection of DAP2 data types.
Definition: Vector.h:80
virtual unsigned int width(bool constrained=false) const
Returns the width of the data, in bytes.
Definition: Vector.cc:545
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: BaseType.cc:1055
std::vector< dimension >::const_iterator Dim_citer
Definition: Array.h:196
bool use_sdim_for_slice
Used to control printing the DMR in data responses.
Definition: Array.h:146
int start
The constraint start index.
Definition: Array.h:148
BaseType(const string &n, const Type &t, bool is_dap4=false)
The BaseType constructor.
Definition: BaseType.cc:125
virtual void add_var(BaseType *v, Part p=nil)
Add the BaseType pointer to this constructor type instance.
Definition: Vector.cc:1954
D4DimensionsIter dim_end()
Get an iterator to the end of the dimensions.
Definition: D4Dimensions.h:166
STL namespace.
void print_xml_writer(XMLWriter &xml)
Definition: AttrTable.cc:1424
void append_dim(int size, const string &name="")
Add a dimension of a given size.
Definition: Array.cc:347
virtual void update_length(int size=0)
Definition: Array.cc:103
D4DimensionsIter dim_begin()
Get an iterator to the start of the dimensions.
Definition: D4Dimensions.h:163
A class for software fault reporting.
Definition: InternalErr.h:64
Dim_iter dim_end()
Definition: Array.cc:517
virtual std::string FQN() const
Definition: BaseType.cc:277
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Definition: Vector.cc:434
virtual void print_as_map_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Array.cc:924
Holds a DAP4 enumeration.
Definition: D4Enum.h:61
virtual int dimension_size(Dim_iter i, bool constrained=false)
Returns the size of the dimension.
Definition: Array.cc:556
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: BaseType.cc:1011
virtual bool is_constructor_type() const
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable...
Definition: BaseType.cc:357
void add_dim_nocopy(D4Dimension *dim)
Definition: D4Dimensions.h:160
virtual Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:310
std::vector< dimension >::iterator Dim_iter
Definition: Array.h:204
void clear_all_dims()
Definition: Array.cc:393
virtual string dimension_name(Dim_iter i)
Returns the name of the specified dimension.
Definition: Array.cc:654
virtual BaseType * ptr_duplicate()
Definition: Array.cc:174
virtual int dimension_stride(Dim_iter i, bool constrained=false)
Returns the stride value of the constraint.
Definition: Array.cc:638
int stride
The constraint stride.
Definition: Array.h:150
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:862
int c_size
Size of dimension once constrained.
Definition: Array.h:151
virtual D4Attributes * attributes()
Definition: BaseType.cc:544
void prepend_dim(int size, const string &name="")
Definition: Array.cc:370
virtual void print_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Array.cc:902
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:220
virtual int dimension_stop(Dim_iter i, bool constrained=false)
Return the stop index of the constraint.
Definition: Array.cc:613
virtual int dimension_start(Dim_iter i, bool constrained=false)
Return the start index of a dimension.
Definition: Array.cc:589
virtual AttrTable & get_attr_table()
Definition: BaseType.cc:527
virtual void print_dap4(XMLWriter &xml, bool constrained=false)
Print the DAP4 representation of an array.
Definition: Array.cc:779
virtual ~Array()
The Array destructor.
Definition: Array.cc:168
int size
The unconstrained dimension size.
Definition: Array.h:135
string name
The name of this dimension.
Definition: Array.h:136
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
Dim_iter dim_begin()
Definition: Array.cc:510
virtual string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:324
Vars_iter var_begin()
Definition: Constructor.cc:331
virtual int length() const
Definition: Vector.cc:557
Vars_iter var_end()
Definition: Constructor.cc:339
virtual void set_length(int l)
Definition: Vector.cc:564
A class for error processing.
Definition: Error.h:90
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
virtual BaseType * transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: Array.cc:193
unsigned int print_array(FILE *out, unsigned int index, unsigned int dims, unsigned int shape[])
Print the value given the current constraint.
Definition: Array.cc:1030
A multidimensional array of identical data types.
Definition: Array.h:112
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: Array.cc:1106
virtual unsigned int width(bool constrained=false) const
How many bytes does this use Return the number of bytes of storage this variable uses. For scalar types, this is pretty simple (an int32 uses 4 bytes, etc.). For arrays and Constructors, it is a bit more complex. Note that a scalar String variable uses sizeof(String*) bytes, not the length of the string. In other words, the value returned is independent of the type. Also note width() of a String array returns the number of elements in the array times sizeof(String*). That is, each different array size is a different data type.
Definition: BaseType.cc:1222
virtual bool send_p()
Should this variable be sent?
Definition: BaseType.cc:499
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Vector.cc:2037
string id2www(string in, const string &allowable)
Definition: escaping.cc:153
D4Dimensions * dims()
Get the dimensions defined for this Group.
Definition: D4Group.h:80
virtual void clear_constraint()
Clears the projection; add each projected dimension explicitly using add_constraint.
Definition: Array.cc:429
virtual bool check_semantics(string &msg, bool all=false)
Compare an object&#39;s current state with the semantics of its type.
Definition: BaseType.cc:1130