libdap++  Updated for version 3.14.0
Array.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 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  size = d->size();
66  name = d->name();
67 
68  start = 0;
69  stop = size - 1;
70  stride = 1;
71  c_size = size;
72 }
73 
74 void
76 {
77  _shape = a._shape;
78 
79  // Deep copy the Maps if they are being used.
80  if (a.d_maps) {
81  d_maps = new D4Maps(*(a.d_maps));
82  }
83  else {
84  d_maps = 0;
85  }
86  // d_maps = a.d_maps ? new D4Maps(*(a.d_maps)) : 0;
87 }
88 
89 // The first method of calculating length works when only one dimension is
90 // constrained and you want the others to appear in total. This is important
91 // when selecting from grids since users may not select from all dimensions
92 // in which case that means they want the whole thing. Array projection
93 // should probably work this way too, but it doesn't. 9/21/2001 jhrg
94 
101 void
103 {
104  int length = 1;
105  for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
106  length *= (*i).c_size > 0 ? (*i).c_size : 1;
107  }
108 
109  set_length(length);
110 }
111 
112 // Construct an instance of Array. The (BaseType *) is assumed to be
113 // allocated using new - The dtor for Vector will delete this object.
114 
130 Array::Array(const string &n, BaseType *v, bool is_dap4 /* default:false */)
131  : Vector(n, 0, dods_array_c, is_dap4), d_maps(0)
132 {
133  add_var(v); // Vector::add_var() stores null if v is null
134 }
135 
149 Array::Array(const string &n, const string &d, BaseType *v, bool is_dap4 /* default:false */)
150  : Vector(n, d, 0, dods_array_c, is_dap4), d_maps(0)
151 {
152  add_var(v); // Vector::add_var() stores null if v is null
153 }
154 
156 Array::Array(const Array &rhs) : Vector(rhs)
157 {
158  _duplicate(rhs);
159 }
160 
163 {
164  delete d_maps;
165 }
166 
167 BaseType *
169 {
170  return new Array(*this);
171 }
172 
173 Array &
175 {
176  if (this == &rhs)
177  return *this;
178 
179  dynamic_cast<Vector &>(*this) = rhs;
180 
181  _duplicate(rhs);
182 
183  return *this;
184 }
185 
186 BaseType *
188 {
189  Array *dest = static_cast<Array*>(ptr_duplicate());
190 
191  // Process the Array's dimensions, making D4 shared dimensions for
192  // D2 dimensions that are named. If there is just a size, don't make
193  // a D4Dimension (In DAP4 you cannot share a dimension unless it has
194  // a name). jhrg 3/18/14
195 
196  D4Dimensions *dims = root->dims();
197  for (Array::Dim_iter d = dest->dim_begin(), e = dest->dim_end(); d != e; ++d) {
198  if (!(*d).name.empty()) {
199  // If a D4Dimension with the name already exists, use it.
200  D4Dimension *d4_dim = dims->find_dim((*d).name);
201  if (!d4_dim) {
202  d4_dim = new D4Dimension((*d).name, (*d).size);
203  dims->add_dim_nocopy(d4_dim);
204  }
205  // TODO Revisit this decision. jhrg 3/18/14
206  // ...in case the name/size are different, make a unique D4Dimension
207  // but don't fiddle with the name. Not sure I like this idea, so I'm
208  // making the case explicit (could be rolled in to the block above).
209  // jhrg 3/18/14
210  //
211  // This is causing problems in the FITS handler because there are cases
212  // where two arrays have dimensions with the same name but different
213  // sizes. The deserializing code is using the first size listed, which is
214  // wrong in some cases. I'm going to try making this new D4Dimension using
215  // the dim name along with the variable name. jhrg 8/15/14
216  else if (d4_dim->size() != (unsigned long) (*d).size) {
217  d4_dim = new D4Dimension((*d).name + "_" + name(), (*d).size);
218  dims->add_dim_nocopy(d4_dim);
219  }
220  // At this point d4_dim's name and size == those of (*d) so just set
221  // the D4Dimension pointer so it matches the one in the D4Group.
222  (*d).dim = d4_dim;
223  }
224  }
225 
226  // Copy the D2 attributes to D4 Attributes
228 
229  dest->set_is_dap4(true);
230 
231  return dest;
232 }
233 
245 void
246 Array::update_dimension_pointers(D4Dimensions *old_dims, D4Dimensions *new_dims)
247 {
248  std::vector<dimension>::iterator i = _shape.begin(), e = _shape.end();
249  while (i != e) {
250  D4Dimensions::D4DimensionsIter old_i = old_dims->dim_begin(), old_e = old_dims->dim_end();
251  while (old_i != old_e) {
252  if ((*i).dim == *old_i) {
253  (*i).dim = new_dims->find_dim((*old_i)->name());
254  }
255  ++old_i;
256  }
257 
258  ++i;
259  }
260 }
261 
286 void
288 {
289  // If 'v' is an Array, add the template instance to this object and
290  // then copy the dimension information. Odd semantics; I wonder if this
291  //is ever used. jhrg 6/13/12
292  if (v && v->type() == dods_array_c) {
293  Array *a = static_cast<Array*>(v);
294  Vector::add_var(a->var());
295 
296  Dim_iter i = a->dim_begin();
297  Dim_iter i_end = a->dim_end();
298  while (i != i_end) {
300  ++i;
301  }
302  }
303  else {
304  Vector::add_var(v);
305  }
306 }
307 
308 void
310 {
311  // If 'v' is an Array, add the template instance to this object and
312  // then copy the dimension information. Odd semantics; I wonder if this
313  //is ever used. jhrg 6/13/12
314  if (v && v->type() == dods_array_c) {
315  Array &a = dynamic_cast<Array&>(*v);
317  Dim_iter i = a.dim_begin();
318  Dim_iter i_end = a.dim_end();
319  while (i != i_end) {
321  ++i;
322  }
323  }
324  else {
326  }
327 }
328 
340 void
341 Array::append_dim(int size, const string &name)
342 {
343  dimension d(size, www2id(name));
344  _shape.push_back(d);
345 
346  update_length();
347 }
348 
349 void
351 {
352  dimension d(/*dim->size(), www2id(dim->name()),*/ dim);
353  _shape.push_back(d);
354 
355  update_length();
356 }
357 
363 void
364 Array::prepend_dim(int size, const string& name/* = "" */)
365 {
366  dimension d(size, www2id(name));
367  // Shifts the whole array, but it's tiny in general
368  _shape.insert(_shape.begin(), d);
369 
370  update_length(); // the number is ignored...
371 }
372 
373 void
375 {
376  dimension d(/*dim->size(), www2id(dim->name()),*/ dim);
377  // Shifts the whole array, but it's tiny in general
378  _shape.insert(_shape.begin(), d);
379 
380  update_length(); // the number is ignored...
381 }
382 
386 void
388 {
389  _shape.clear();
390 }
397 void
399 {
400  set_length(-1);
401 
402  for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
403  (*i).start = 0;
404  (*i).stop = (*i).size - 1;
405  (*i).stride = 1;
406  (*i).c_size = (*i).size;
407 
408  update_length();
409  }
410 }
411 
412 
422 void
424 {
426 }
427 
428 // Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n
429 // is explicit.
430 static const char *array_sss = \
431 "Invalid constraint parameters: At least one of the start, stride or stop \n\
432 specified do not match the array variable.";
433 
454 void
455 Array::add_constraint(Dim_iter i, int start, int stride, int stop)
456 {
457  dimension &d = *i ;
458 
459  // if stop is -1, set it to the array's max element index
460  // jhrg 12/20/12
461  if (stop == -1)
462  stop = d.size - 1;
463 
464  // Check for bad constraints.
465  // Jose Garcia
466  // Usually invalid data for a constraint is the user's mistake
467  // because they build a wrong URL in the client side.
468  if (start >= d.size || stop >= d.size || stride > d.size || stride <= 0)
469  throw Error(malformed_expr, array_sss);
470 
471  if (((stop - start) / stride + 1) > d.size)
472  throw Error(malformed_expr, array_sss);
473 
474  d.start = start;
475  d.stop = stop;
476  d.stride = stride;
477 
478  d.c_size = (stop - start) / stride + 1;
479 
480  DBG(cerr << "add_constraint: c_size = " << d.c_size << endl);
481 
482  update_length();
483 
484  d.use_sdim_for_slice = false;
485 }
486 
487 void
489 {
490  dimension &d = *i ;
491 
492  if (dim->constrained())
493  add_constraint(i, dim->c_start(), dim->c_stride(), dim->c_stop());
494 
495  dim->set_used_by_projected_var(true);
496 
497  // In this case the value below overrides the value for use_sdim_for_slice
498  // set in the above call. jhrg 12/20/13
499  d.use_sdim_for_slice = true;
500 }
501 
505 {
506  return _shape.begin() ;
507 }
508 
512 {
513  return _shape.end() ;
514 }
515 
516 //TODO Many of these methods take a bool parameter that serves no use; remove.
517 
526 unsigned int
527 Array::dimensions(bool /*constrained*/)
528 {
529  return _shape.size();
530 }
531 
549 int
550 Array::dimension_size(Dim_iter i, bool constrained)
551 {
552  int size = 0;
553 
554  if (!_shape.empty()) {
555  if (constrained)
556  size = (*i).c_size;
557  else
558  size = (*i).size;
559  }
560 
561  return size;
562 }
563 
582 int
583 Array::dimension_start(Dim_iter i, bool /*constrained*/)
584 {
585  return (!_shape.empty()) ? (*i).start : 0;
586 }
587 
606 int
607 Array::dimension_stop(Dim_iter i, bool /*constrained*/)
608 {
609  return (!_shape.empty()) ? (*i).stop : 0;
610 }
611 
631 int
632 Array::dimension_stride(Dim_iter i, bool /*constrained*/)
633 {
634  return (!_shape.empty()) ? (*i).stride : 0;
635 }
636 
647 string
649 {
650  // Jose Garcia
651  // Since this method is public, it is possible for a user
652  // to call it before the Array object has been properly set
653  // this will cause an exception which is the user's fault.
654  // (User in this context is the developer of the surrogate library.)
655  if (_shape.empty())
656  throw InternalErr(__FILE__, __LINE__,
657  "*This* array has no dimensions.");
658  return (*i).name;
659 }
660 
661 D4Dimension *
663 {
664  return (!_shape.empty()) ? (*i).dim : 0;
665 }
666 
667 D4Maps *
669 {
670  if (!d_maps) d_maps = new D4Maps(this); // init with this as parent
671  return d_maps;
672 }
673 
674 #if 0
675 
681 unsigned int Array::width(bool constrained) const
682 {
683 
684  if (constrained) {
685  // This preserves the original method's semantics when we ask for the
686  // size of the constrained array but no constraint has been applied.
687  // In this case, length will be -1. Wrong, I know...
688  return length() * var()->width(constrained);
689  }
690  else {
691  int length = 1;
692  for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
693  length *= dimension_size(i, false);
694  }
695  return length * var()->width(false);
696  }
697 }
698 #endif
699 
700 class PrintD4ArrayDimXMLWriter: public unary_function<Array::dimension&, void> {
701  XMLWriter &xml;
702  // Was this variable constrained using local/direct slicing? i.e., is d_local_constraint set?
703  // If so, don't use shared dimensions; instead emit Dim elements that are anonymous.
704  bool d_constrained;
705 public:
706 
707  PrintD4ArrayDimXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) { }
708 
709  void operator()(Array::dimension &d)
710  {
711  // This duplicates code in D4Dimensions (where D4Dimension::print_dap4() is defined
712  // because of the need to print the constrained size of a dimension. I think that
713  // the constraint information has to be kept here and not in the dimension (since they
714  // are shared dims). Could hack print_dap4() to take the constrained size, however.
715  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dim") < 0)
716  throw InternalErr(__FILE__, __LINE__, "Could not write Dim element");
717 
718  string name = (d.dim) ? d.dim->fully_qualified_name() : d.name;
719  // If there is a name, there must be a Dimension (named dimension) in scope
720  // so write its name but not its size.
721  if (!d_constrained && !name.empty()) {
722  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name.c_str())
723  < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
724  }
725  else if (d.use_sdim_for_slice) {
726  assert(!name.empty());
727  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name.c_str())
728  < 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
729  }
730  else {
731  ostringstream size;
732  size << (d_constrained ? d.c_size : d.size);
733  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size",
734  (const xmlChar*) size.str().c_str()) < 0)
735  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
736  }
737 
738  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
739  throw InternalErr(__FILE__, __LINE__, "Could not end Dim element");
740  }
741 };
742 
743 class PrintD4ConstructorVarXMLWriter: public unary_function<BaseType*, void> {
744  XMLWriter &xml;
745  bool d_constrained;
746 public:
747  PrintD4ConstructorVarXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) { }
748 
749  void operator()(BaseType *btp)
750  {
751  btp->print_dap4(xml, d_constrained);
752  }
753 };
754 
755 class PrintD4MapXMLWriter: public unary_function<D4Map*, void> {
756  XMLWriter &xml;
757 
758 public:
759  PrintD4MapXMLWriter(XMLWriter &xml) : xml(xml) { }
760 
761  void operator()(D4Map *m)
762  {
763  m->print_dap4(xml);
764  }
765 };
766 
772 void
773 Array::print_dap4(XMLWriter &xml, bool constrained /* default: false*/)
774 {
775  if (constrained && !send_p()) return;
776 
777  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) var()->type_name().c_str()) < 0)
778  throw InternalErr(__FILE__, __LINE__, "Could not write " + type_name() + " element");
779 
780  if (!name().empty())
781  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
782  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
783 
784  // Hack job... Copied from D4Enum::print_xml_writer. jhrg 11/12/13
785  if (var()->type() == dods_enum_c) {
786  D4Enum *e = static_cast<D4Enum*>(var());
787  string path = e->enumeration()->name();
788  if (e->enumeration()->parent()) {
789  // print the FQN for the enum def; D4Group::FQN() includes the trailing '/'
790  path = static_cast<D4Group*>(e->enumeration()->parent()->parent())->FQN() + path;
791  }
792  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "enum", (const xmlChar*)path.c_str()) < 0)
793  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for enum");
794  }
795 
796  if (prototype()->is_constructor_type()) {
797  Constructor &c = static_cast<Constructor&>(*prototype());
798  for_each(c.var_begin(), c.var_end(), PrintD4ConstructorVarXMLWriter(xml, constrained));
799  // bind2nd(mem_fun_ref(&BaseType::print_dap4), xml));
800  }
801 
802  // Drop the local_constraint which is per-array and use a per-dimension on instead
803  for_each(dim_begin(), dim_end(), PrintD4ArrayDimXMLWriter(xml, constrained));
804 
805  attributes()->print_dap4(xml);
806 
807  for_each(maps()->map_begin(), maps()->map_end(), PrintD4MapXMLWriter(xml));
808 
809  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
810  throw InternalErr(__FILE__, __LINE__, "Could not end " + type_name() + " element");
811 }
812 
830 void
831 Array::print_decl(FILE *out, string space, bool print_semi,
832  bool constraint_info, bool constrained)
833 {
834  ostringstream oss;
835  print_decl(oss, space, print_semi, constraint_info, constrained);
836  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
837 }
838 
856 void
857 Array::print_decl(ostream &out, string space, bool print_semi,
858  bool constraint_info, bool constrained)
859 {
860  if (constrained && !send_p())
861  return;
862 
863  // print it, but w/o semicolon
864  var()->print_decl(out, space, false, constraint_info, constrained);
865 
866  for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
867  out << "[" ;
868  if ((*i).name != "") {
869  out << id2www((*i).name) << " = " ;
870  }
871  if (constrained) {
872  out << (*i).c_size << "]" ;
873  }
874  else {
875  out << (*i).size << "]" ;
876  }
877  }
878 
879  if (print_semi) {
880  out << ";\n" ;
881  }
882 }
883 
887 void
888 Array::print_xml(FILE *out, string space, bool constrained)
889 {
890  XMLWriter xml(space);
891  print_xml_writer_core(xml, constrained, "Array");
892  fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
893 }
894 
898 void
899 Array::print_xml(ostream &out, string space, bool constrained)
900 {
901  XMLWriter xml(space);
902  print_xml_writer_core(xml, constrained, "Array");
903  out << xml.get_doc();
904 }
905 
909 void
910 Array::print_as_map_xml(FILE *out, string space, bool constrained)
911 {
912  XMLWriter xml(space);
913  print_xml_writer_core(xml, constrained, "Map");
914  fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
915 }
916 
920 void
921 Array::print_as_map_xml(ostream &out, string space, bool constrained)
922 {
923  XMLWriter xml(space);
924  print_xml_writer_core(xml, constrained, "Map");
925  out << xml.get_doc();
926 }
927 
931 void
932 Array::print_xml_core(FILE *out, string space, bool constrained, string tag)
933 {
934  XMLWriter xml(space);
935  print_xml_writer_core(xml, constrained, tag);
936  fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
937 }
938 
942 void
943 Array::print_xml_core(ostream &out, string space, bool constrained, string tag)
944 {
945  XMLWriter xml(space);
946  print_xml_writer_core(xml, constrained, tag);
947  out << xml.get_doc();
948 }
949 
950 void
951 Array::print_xml_writer(XMLWriter &xml, bool constrained)
952 {
953  print_xml_writer_core(xml, constrained, "Array");
954 }
955 
956 void
958 {
959  print_xml_writer_core(xml, constrained, "Map");
960 }
961 
962 class PrintArrayDimXMLWriter : public unary_function<Array::dimension&, void>
963 {
964  XMLWriter &xml;
965  bool d_constrained;
966 public:
967  PrintArrayDimXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) {}
968 
969  void operator()(Array::dimension &d)
970  {
971  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"dimension") < 0)
972  throw InternalErr(__FILE__, __LINE__, "Could not write dimension element");
973 
974  if (!d.name.empty())
975  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d.name.c_str()) < 0)
976  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
977 
978  ostringstream size;
979  size << (d_constrained ? d.c_size : d.size);
980  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size", (const xmlChar*)size.str().c_str()) < 0)
981  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
982 
983  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
984  throw InternalErr(__FILE__, __LINE__, "Could not end dimension element");
985  }
986 };
987 
988 void
989 Array::print_xml_writer_core(XMLWriter &xml, bool constrained, string tag)
990 {
991  if (constrained && !send_p())
992  return;
993 
994  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)tag.c_str()) < 0)
995  throw InternalErr(__FILE__, __LINE__, "Could not write " + tag + " element");
996 
997  if (!name().empty())
998  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
999  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1000 
1002 
1003  BaseType *btp = var();
1004  string tmp_name = btp->name();
1005  btp->set_name("");
1006  btp->print_xml_writer(xml, constrained);
1007  btp->set_name(tmp_name);
1008 
1009  for_each(dim_begin(), dim_end(), PrintArrayDimXMLWriter(xml, constrained));
1010 
1011  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1012  throw InternalErr(__FILE__, __LINE__, "Could not end " + tag + " element");
1013 }
1014 
1026 unsigned int
1027 Array::print_array(FILE *out, unsigned int index, unsigned int dims,
1028  unsigned int shape[])
1029 {
1030  ostringstream oss;
1031  unsigned int i = print_array(oss, index, dims, shape);
1032  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1033 
1034  return i;
1035 }
1036 
1048 unsigned int Array::print_array(ostream &out, unsigned int index, unsigned int dims, unsigned int shape[])
1049 {
1050  if (dims == 1) {
1051  out << "{";
1052  for (unsigned i = 0; i < shape[0] - 1; ++i) {
1053  var(index++)->print_val(out, "", false);
1054  out << ", ";
1055  }
1056  var(index++)->print_val(out, "", false);
1057  out << "}";
1058 
1059  return index;
1060  }
1061  else {
1062  out << "{";
1063  // Fixed an off-by-one error in the following loop. Since the array
1064  // length is shape[dims-1]-1 *and* since we want one less dimension
1065  // than that, the correct limit on this loop is shape[dims-2]-1. From
1066  // Todd Karakasian.
1067  // The saga continues; the loop test should be `i < shape[0]-1'. jhrg
1068  // 9/12/96.
1069  for (unsigned i = 0; i < shape[0] - 1; ++i) {
1070  index = print_array(out, index, dims - 1, shape + 1);
1071  out << ",";
1072  }
1073  index = print_array(out, index, dims - 1, shape + 1);
1074  out << "}";
1075 
1076  return index;
1077  }
1078 }
1079 
1080 void
1081 Array::print_val(FILE *out, string space, bool print_decl_p)
1082 {
1083  ostringstream oss;
1084  print_val(oss, space, print_decl_p);
1085  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1086 }
1087 
1088 void
1089 Array::print_val(ostream &out, string space, bool print_decl_p)
1090 {
1091  // print the declaration if print decl is true.
1092  // for each dimension,
1093  // for each element,
1094  // print the array given its shape, number of dimensions.
1095  // Add the `;'
1096 
1097  if (print_decl_p) {
1098  print_decl(out, space, false, false, false);
1099  out << " = " ;
1100  }
1101 
1102  unsigned int *shape = new unsigned int[dimensions(true)];
1103  unsigned int index = 0;
1104  for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i)
1105  shape[index++] = dimension_size(i, true);
1106 
1107  print_array(out, 0, dimensions(true), shape);
1108 
1109  delete [] shape; shape = 0;
1110 
1111  if (print_decl_p) {
1112  out << ";\n" ;
1113  }
1114 }
1115 
1125 bool
1126 Array::check_semantics(string &msg, bool)
1127 {
1128  bool sem = BaseType::check_semantics(msg) && !_shape.empty();
1129 
1130  if (!sem)
1131  msg = "An array variable must have dimensions";
1132 
1133  return sem;
1134 }
1135 
1144 void
1145 Array::dump(ostream &strm) const
1146 {
1147  strm << DapIndent::LMarg << "Array::dump - ("
1148  << (void *)this << ")" << endl ;
1149  DapIndent::Indent() ;
1150  Vector::dump(strm) ;
1151  strm << DapIndent::LMarg << "shape:" << endl ;
1152  DapIndent::Indent() ;
1153  Dim_citer i = _shape.begin() ;
1154  Dim_citer ie = _shape.end() ;
1155  unsigned int dim_num = 0 ;
1156  for (; i != ie; i++) {
1157  strm << DapIndent::LMarg << "dimension " << dim_num++ << ":"
1158  << endl ;
1159  DapIndent::Indent() ;
1160  strm << DapIndent::LMarg << "name: " << (*i).name << endl ;
1161  strm << DapIndent::LMarg << "size: " << (*i).size << endl ;
1162  strm << DapIndent::LMarg << "start: " << (*i).start << endl ;
1163  strm << DapIndent::LMarg << "stop: " << (*i).stop << endl ;
1164  strm << DapIndent::LMarg << "stride: " << (*i).stride << endl ;
1165  strm << DapIndent::LMarg << "constrained size: " << (*i).c_size
1166  << endl ;
1168  }
1171 }
1172 
1173 } // namespace libdap
1174 
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: Array.cc:951
virtual void reset_constraint()
Reset constraint to select entire array.
Definition: Array.cc:398
void set_is_dap4(const bool v)
Definition: BaseType.h:167
virtual void add_constraint(Dim_iter i, int start, int stride, int stop)
Adds a constraint to an Array dimension.
Definition: Array.cc:455
virtual bool check_semantics(string &msg, bool all=false)
Check semantic features of the Array.
Definition: Array.cc:1126
virtual void print_xml_core(FILE *out, string space, bool constrained, string tag)
Definition: Array.cc:932
static void UnIndent()
Definition: DapIndent.cc:51
vector< D4Dimension * >::iterator D4DimensionsIter
Iterator used for D4Dimensions.
Definition: D4Dimensions.h:122
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:1179
virtual void add_var_nocopy(BaseType *v, Part p=nil)
Definition: Vector.cc:2267
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:905
Array(const string &n, BaseType *v, bool is_dap4=false)
Array constructor.
Definition: Array.cc:130
xmlTextWriterPtr get_writer()
Definition: XMLWriter.h:56
virtual unsigned int dimensions(bool constrained=false)
Return the total number of dimensions in the array.
Definition: Array.cc:527
Part
Names the parts of multi-section constructor data types.
Definition: Type.h:48
D4EnumDefs * parent() const
Definition: D4EnumDefs.h:70
virtual BaseType * prototype() const
Definition: Vector.h:120
void add_var(BaseType *v, Part p=nil)
Add the BaseType pointer to this constructor type instance.
Definition: Array.cc:287
unsigned long long c_start() const
Definition: D4Dimensions.h:71
virtual void set_name(const string &n)
Sets the name of the class instance.
Definition: BaseType.cc:285
int stop
The constraint end index.
Definition: Array.h:149
#define malformed_expr
Definition: Error.h:64
Holds a one-dimensional collection of DAP2 data types.
Definition: Vector.h:80
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Vector.cc:2310
bool is_dap4() const
Definition: BaseType.h:166
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: BaseType.cc:1036
virtual int length() const
Definition: Vector.cc:513
std::vector< dimension >::const_iterator Dim_citer
Definition: Array.h:207
unsigned long long c_stop() const
Definition: D4Dimensions.h:73
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
Array & operator=(const Array &rhs)
Definition: Array.cc:174
virtual void add_var(BaseType *v, Part p=nil)
Add the BaseType pointer to this constructor type instance.
Definition: Vector.cc:2227
D4DimensionsIter dim_end()
Get an iterator to the end of the dimensions.
Definition: D4Dimensions.h:166
unsigned long long c_stride() const
Definition: D4Dimensions.h:72
virtual D4Maps * maps()
Definition: Array.cc:668
D4Maps * d_maps
Definition: Array.h:182
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:341
virtual void update_length(int size=0)
Definition: Array.cc:102
Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:306
D4DimensionsIter dim_begin()
Get an iterator to the start of the dimensions.
Definition: D4Dimensions.h:163
void _duplicate(const Array &a)
Definition: Array.cc:75
virtual D4Dimension * dimension_D4dim(Dim_iter i)
Definition: Array.cc:662
A class for software fault reporting.
Definition: InternalErr.h:64
Dim_iter dim_end()
Definition: Array.cc:511
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Definition: Vector.cc:387
virtual void print_as_map_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Array.cc:921
#define DBG(x)
Definition: debug.h:58
string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:320
Holds a DAP4 enumeration.
Definition: D4Enum.h:55
virtual int dimension_size(Dim_iter i, bool constrained=false)
Returns the size of the dimension.
Definition: Array.cc:550
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: BaseType.cc:992
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:353
void add_dim_nocopy(D4Dimension *dim)
Definition: D4Dimensions.h:160
const char * get_doc()
Definition: XMLWriter.cc:105
static void Indent()
Definition: DapIndent.cc:45
D4Group * parent() const
Definition: D4EnumDefs.h:129
std::vector< dimension >::iterator Dim_iter
Definition: Array.h:214
void clear_all_dims()
Definition: Array.cc:387
virtual string dimension_name(Dim_iter i)
Returns the name of the specified dimension.
Definition: Array.cc:648
virtual BaseType * ptr_duplicate()
Definition: Array.cc:168
virtual int dimension_stride(Dim_iter i, bool constrained=false)
Returns the stride value of the constraint.
Definition: Array.cc:632
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:857
int c_size
Size of dimension once constrained.
Definition: Array.h:151
virtual D4Attributes * attributes()
Definition: BaseType.cc:529
virtual void print_as_map_xml_writer(XMLWriter &xml, bool constrained)
Definition: Array.cc:957
virtual std::string FQN() const
Definition: BaseType.cc:273
void prepend_dim(int size, const string &name="")
Definition: Array.cc:364
string name() const
Returns the name of the class instance.
Definition: BaseType.cc:261
virtual void print_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Array.cc:899
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:607
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Array.cc:1145
bool constrained() const
Definition: D4Dimensions.h:70
static ostream & LMarg(ostream &strm)
Definition: DapIndent.cc:80
virtual int dimension_start(Dim_iter i, bool constrained=false)
Return the start index of a dimension.
Definition: Array.cc:583
virtual AttrTable & get_attr_table()
Definition: BaseType.cc:512
virtual void print_dap4(XMLWriter &xml, bool constrained=false)
Print the DAP4 representation of an array.
Definition: Array.cc:773
virtual ~Array()
The Array destructor.
Definition: Array.cc:162
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:504
Vars_iter var_begin()
Definition: Constructor.cc:331
void add_var_nocopy(BaseType *v, Part p=nil)
Definition: Array.cc:309
Vars_iter var_end()
Definition: Constructor.cc:339
virtual void print_xml_writer_core(XMLWriter &out, bool constrained, string tag)
Definition: Array.cc:989
virtual D4EnumDef * enumeration() const
Definition: D4Enum.h:164
string name() const
Definition: D4Dimensions.h:58
virtual void set_length(int l)
Definition: Vector.cc:520
void set_used_by_projected_var(bool state)
Definition: D4Dimensions.h:76
A class for error processing.
Definition: Error.h:90
string name() const
Definition: D4EnumDefs.h:64
unsigned long size() const
Definition: D4Dimensions.h:62
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:187
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:1027
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:1089
virtual bool send_p()
Should this variable be sent?
Definition: BaseType.cc:484
D4Dimension * find_dim(const string &name)
string id2www(string in, const string &allowable)
Definition: escaping.cc:153
virtual unsigned int width(bool constrained=false) const
Returns the width of the data, in bytes.
Definition: Vector.cc:498
void print_dap4(XMLWriter &xml) const
unsigned int get_doc_size()
Definition: XMLWriter.cc:129
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:423
virtual bool check_semantics(string &msg, bool all=false)
Compare an object's current state with the semantics of its type.
Definition: BaseType.cc:1111