libdap Updated for version 3.18.1
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
60using namespace std;
61
62namespace libdap {
63
64Array::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
75void
76Array::_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
102void
103Array::update_length(int)
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
136Array::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
155Array::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
162Array::Array(const Array &rhs) : Vector(rhs)
163{
164 _duplicate(rhs);
165}
166
169{
170 delete d_maps;
171}
172
173BaseType *
175{
176 return new Array(*this);
177}
178
179Array &
180Array::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
192BaseType *
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
251void
252Array::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
292void
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 {
311 }
312}
313
314void
315Array::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
346void
347Array::append_dim(int size, const string &name)
348{
349 dimension d(size, www2id(name));
350 _shape.push_back(d);
351
353}
354
355void
357{
358 dimension d(/*dim->size(), www2id(dim->name()),*/ dim);
359 _shape.push_back(d);
360
362}
363
369void
370Array::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
379void
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
392void
394{
395 _shape.clear();
396}
403void
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
415 }
416}
417
418
428void
430{
432}
433
434// Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n
435// is explicit.
436static const char *array_sss = \
437"Invalid constraint parameters: At least one of the start, stride or stop \n\
438specified do not match the array variable.";
439
460void
461Array::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
489
490 d.use_sdim_for_slice = false;
491}
492
493void
494Array::add_constraint(Dim_iter i, D4Dimension *dim)
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
532unsigned int
533Array::dimensions(bool /*constrained*/)
534{
535 return _shape.size();
536}
537
555int
556Array::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
588int
589Array::dimension_start(Dim_iter i, bool /*constrained*/)
590{
591 return (!_shape.empty()) ? (*i).start : 0;
592}
593
612int
613Array::dimension_stop(Dim_iter i, bool /*constrained*/)
614{
615 return (!_shape.empty()) ? (*i).stop : 0;
616}
617
637int
638Array::dimension_stride(Dim_iter i, bool /*constrained*/)
639{
640 return (!_shape.empty()) ? (*i).stride : 0;
641}
642
653string
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
668Array::dimension_D4dim(Dim_iter i)
669{
670 return (!_shape.empty()) ? (*i).dim : 0;
671}
672
673D4Maps *
674Array::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
687unsigned 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
706class 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;
711public:
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
749class PrintD4ConstructorVarXMLWriter: public unary_function<BaseType*, void> {
750 XMLWriter &xml;
751 bool d_constrained;
752public:
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
761class PrintD4MapXMLWriter: public unary_function<D4Map*, void> {
762 XMLWriter &xml;
763
764public:
765 PrintD4MapXMLWriter(XMLWriter &xml) : xml(xml) { }
766
767 void operator()(D4Map *m)
768 {
769 m->print_dap4(xml);
770 }
771};
772
778void
779Array::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
836void
837Array::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
862void 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
890void
891Array::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
901void
902Array::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
912void
913Array::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
923void
924Array::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
934void
935Array::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
945void
946Array::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
953void
954Array::print_xml_writer(XMLWriter &xml, bool constrained)
955{
956 print_xml_writer_core(xml, constrained, "Array");
957}
958
959void
960Array::print_as_map_xml_writer(XMLWriter &xml, bool constrained)
961{
962 print_xml_writer_core(xml, constrained, "Map");
963}
964
965class PrintArrayDimXMLWriter : public unary_function<Array::dimension&, void>
966{
967 XMLWriter &xml;
968 bool d_constrained;
969public:
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
991void
992Array::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
1029unsigned int
1030Array::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
1051unsigned 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
1097void
1098Array::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
1105void
1106Array::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
1142bool
1143Array::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
1161void
1162Array::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
A multidimensional array of identical data types.
Definition: Array.h:113
virtual int dimension_start(Dim_iter i, bool constrained=false)
Return the start index of a dimension.
Definition: Array.cc:589
virtual void clear_constraint()
Clears the projection; add each projected dimension explicitly using add_constraint.
Definition: Array.cc:429
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Array.cc:1162
Dim_iter dim_end()
Definition: Array.cc:517
virtual BaseType * ptr_duplicate()
Definition: Array.cc:174
virtual void print_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Array.cc:902
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
virtual int dimension_stop(Dim_iter i, bool constrained=false)
Return the stop index of the constraint.
Definition: Array.cc:613
virtual void update_length(int size=0)
Definition: Array.cc:103
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 dimension_name(Dim_iter i)
Returns the name of the specified dimension.
Definition: Array.cc:654
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
virtual BaseType * transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: Array.cc:193
void append_dim(int size, const string &name="")
Add a dimension of a given size.
Definition: Array.cc:347
std::vector< dimension >::iterator Dim_iter
Definition: Array.h:204
virtual int dimension_size(Dim_iter i, bool constrained=false)
Returns the size of the dimension.
Definition: Array.cc:556
void clear_all_dims()
Definition: Array.cc:393
virtual void print_dap4(XMLWriter &xml, bool constrained=false)
Print the DAP4 representation of an array.
Definition: Array.cc:779
virtual bool check_semantics(string &msg, bool all=false)
Check semantic features of the Array.
Definition: Array.cc:1143
std::vector< dimension >::const_iterator Dim_citer
Definition: Array.h:196
virtual void print_as_map_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Array.cc:924
virtual void reset_constraint()
Reset constraint to select entire array.
Definition: Array.cc:404
void add_var(BaseType *v, Part p=nil)
Add the BaseType pointer to this constructor type instance.
Definition: Array.cc:293
virtual ~Array()
The Array destructor.
Definition: Array.cc:168
virtual void print_xml_core(FILE *out, string space, bool constrained, string tag)
Definition: Array.cc:935
void prepend_dim(int size, const string &name="")
Definition: Array.cc:370
Dim_iter dim_begin()
Definition: Array.cc:510
Array(const string &n, BaseType *v, bool is_dap4=false)
Array constructor.
Definition: Array.cc:136
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: Array.cc:954
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 dimensions(bool constrained=false)
Return the total number of dimensions in the array.
Definition: Array.cc:533
virtual int dimension_stride(Dim_iter i, bool constrained=false)
Returns the stride value of the constraint.
Definition: Array.cc:638
void print_xml_writer(XMLWriter &xml)
Definition: AttrTable.cc:1424
The basic data type for the DODS DAP types.
Definition: BaseType.h:118
virtual string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:324
virtual AttrTable & get_attr_table()
Definition: BaseType.cc:527
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:265
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
virtual unsigned int width(bool constrained=false) const
How many bytes does this use Return the number of bytes of storage this variable uses....
Definition: BaseType.cc:1222
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
virtual D4Attributes * attributes()
Definition: BaseType.cc:544
virtual std::string FQN() const
Definition: BaseType.cc:277
virtual bool send_p()
Should this variable be sent?
Definition: BaseType.cc:499
virtual bool check_semantics(string &msg, bool all=false)
Compare an object's current state with the semantics of its type.
Definition: BaseType.cc:1130
BaseType(const string &n, const Type &t, bool is_dap4=false)
The BaseType constructor.
Definition: BaseType.cc:125
virtual Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:310
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: BaseType.cc:1011
Vars_iter var_end()
Definition: Constructor.cc:339
Vars_iter var_begin()
Definition: Constructor.cc:331
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
vector< D4Dimension * >::iterator D4DimensionsIter
Iterator used for D4Dimensions.
Definition: D4Dimensions.h:122
void add_dim_nocopy(D4Dimension *dim)
Definition: D4Dimensions.h:160
D4DimensionsIter dim_end()
Get an iterator to the end of the dimensions.
Definition: D4Dimensions.h:166
D4DimensionsIter dim_begin()
Get an iterator to the start of the dimensions.
Definition: D4Dimensions.h:163
Holds a DAP4 enumeration.
Definition: D4Enum.h:62
D4Dimensions * dims()
Get the dimensions defined for this Group.
Definition: D4Group.h:80
A class for error processing.
Definition: Error.h:91
A class for software fault reporting.
Definition: InternalErr.h:65
Holds a one-dimensional collection of DAP2 data types.
Definition: Vector.h:81
virtual void add_var(BaseType *v, Part p=nil)
Add the BaseType pointer to this constructor type instance.
Definition: Vector.cc:1954
virtual void set_length(int l)
Definition: Vector.cc:564
virtual int length() const
Definition: Vector.cc:557
virtual unsigned int width(bool constrained=false) const
Returns the width of the data, in bytes.
Definition: Vector.cc:545
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Vector.cc:2037
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Definition: Vector.cc:434
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:220
Part
Names the parts of multi-section constructor data types.
Definition: Type.h:48
string id2www(string in, const string &allowable)
Definition: escaping.cc:153
int stride
The constraint stride.
Definition: Array.h:150
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
int size
The unconstrained dimension size.
Definition: Array.h:135
int stop
The constraint end index.
Definition: Array.h:149
int c_size
Size of dimension once constrained.
Definition: Array.h:151