bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
XDArray.cc
1
2// -*- mode: c++; c-basic-offset:4 -*-
3
4// This file is part of asciival, software which can return an XML data
5// representation of the data read from a DAP server.
6
7// Copyright (c) 2010 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// Authors:
27// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
28
29// Implementation for XDArray. See XDByte.cc
30//
31// 3/12/98 jhrg
32
33#include "config.h"
34
35#include <iostream>
36#include <string>
37#include <sstream>
38#include <algorithm>
39
40using namespace std;
41
42//#define DODS_DEBUG
43#include <BESDebug.h>
44
45#include <libdap/InternalErr.h>
46#include <libdap/escaping.h>
47#include <libdap/util.h>
48#include <libdap/debug.h>
49
50#include "XDArray.h"
51#include "get_xml_data.h"
52
53using namespace xml_data;
54
55BaseType *
56XDArray::ptr_duplicate()
57{
58 return new XDArray(*this);
59}
60
61XDArray::XDArray(const string &n, BaseType *v) : Array(n, v)
62{
63}
64
65XDArray::XDArray( Array *bt )
66 : Array(bt->name(), 0), XDOutput( bt )
67{
68 // By calling var() without any parameters we get back the template
69 // itself, then we can add it to this Array as the template. By doing
70 // this we set the parent as well, which is what we need.
71 BaseType *abt = basetype_to_xd( bt->var() ) ;
72 add_var( abt ) ;
73 // add_var makes a copy of the base type passed, so delete the original
74 delete abt ;
75
76 // Copy the dimensions
77 Dim_iter p = bt->dim_begin();
78 while ( p != bt->dim_end() ) {
79 append_dim(bt->dimension_size(p, true), bt->dimension_name(p));
80 ++p;
81 }
82
83 // I'm not particularly happy with this constructor; we should be able to
84 // use the libdap ctors like BaseType::BaseType(const BaseType &copy_from)
85 // using that via the Array copy ctor won't let us use the
86 // basetype_to_asciitype() factory class. jhrg 5/19/09
87 set_send_p(bt->send_p());
88}
89
90XDArray::~XDArray()
91{
92}
93
100void XDArray::print_xml_map_data(XMLWriter *writer, bool /*show_type*/) throw(InternalErr)
101{
102 if (var()->is_simple_type()) {
103 if (dimensions(true) > 1) {
104 // We might have n-dimensional maps someday...
105 m_print_xml_array(writer, "Map");
106 }
107 else {
108 m_print_xml_vector(writer, "Map");
109 }
110 }
111 else {
112 throw InternalErr(__FILE__, __LINE__, "A Map must be a simple type.");
113 }
114}
115
116void XDArray::print_xml_data(XMLWriter *writer, bool /*show_type*/) throw(InternalErr)
117{
118 BESDEBUG("xd", "Entering XDArray::print_xml_data" << endl);
119
120 if (var()->is_simple_type()) {
121 if (dimensions(true) > 1)
122 m_print_xml_array(writer, "Array");
123 else
124 m_print_xml_vector(writer, "Array");
125 }
126 else {
127 m_print_xml_complex_array(writer, "Array");
128 }
129}
130
131class PrintArrayDimXML : public unary_function<Array::dimension&, void>
132{
133 XMLWriter *d_writer;
134 bool d_constrained;
135
136public:
137 PrintArrayDimXML(XMLWriter *writer, bool c)
138 : d_writer(writer), d_constrained(c)
139 {}
140
141 void operator()(Array::dimension &d)
142 {
143 int size = d_constrained ? d.c_size : d.size;
144 if (d.name.empty()) {
145 if (xmlTextWriterStartElement(d_writer->get_writer(), (const xmlChar*) "dimension") < 0)
146 throw InternalErr(__FILE__, __LINE__, "Could not write dimension element");
147 if (xmlTextWriterWriteFormatAttribute(d_writer->get_writer(), (const xmlChar*)"size", "%d", size) < 0)
148 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for size");
149 if (xmlTextWriterEndElement(d_writer->get_writer()) < 0)
150 throw InternalErr(__FILE__, __LINE__, "Could not end dimension element");
151 }
152 else {
153 string id_name = id2xml(d.name);
154 if (xmlTextWriterStartElement(d_writer->get_writer(), (const xmlChar*) "dimension") < 0)
155 throw InternalErr(__FILE__, __LINE__, "Could not write dimension element");
156 if (xmlTextWriterWriteAttribute(d_writer->get_writer(), (const xmlChar*) "name", (const xmlChar*)id_name.c_str()) < 0)
157 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
158 if (xmlTextWriterWriteFormatAttribute(d_writer->get_writer(), (const xmlChar*) "size", "%d", size) < 0)
159 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for size");
160 if (xmlTextWriterEndElement(d_writer->get_writer()) < 0)
161 throw InternalErr(__FILE__, __LINE__, "Could not end dimension element");
162 }
163 }
164};
165
166void XDArray::start_xml_declaration(XMLWriter *writer, const char *element) throw(InternalErr)
167{
168 // Start the Array element (includes the name)
169 if (xmlTextWriterStartElement(writer->get_writer(), (element != 0) ? (const xmlChar*)element : (const xmlChar*)"Array") < 0)
170 throw InternalErr(__FILE__, __LINE__, "Could not write Array element '" + ((element != 0) ? string(element): string("Array")) + "' for " + name());
171 if (xmlTextWriterWriteAttribute(writer->get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
172 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for " + name());
173
174 // Start and End the Type element/s
175 dynamic_cast<XDOutput&>(*var()).start_xml_declaration(writer);
176
177 end_xml_declaration(writer);
178
179 for_each(dim_begin(), dim_end(), PrintArrayDimXML(writer, true));
180}
181
182// Print out a values for a vector (one dimensional array) of simple types.
183void XDArray::m_print_xml_vector(XMLWriter *writer, const char *element)
184{
185 BESDEBUG("xd", "Entering XDArray::m_print_xml_vector" << endl);
186
187 start_xml_declaration(writer, element);
188
189 // only one dimension
190 int end = dimension_size(dim_begin(), true);
191 m_print_xml_row(writer, 0, end);
192
193 end_xml_declaration(writer);
194}
195
196void XDArray::m_print_xml_array(XMLWriter *writer, const char *element)
197{
198 BESDEBUG("xd", "Entering XDArray::m_print_xml_array" << endl);
199
200 int dims = dimensions(true);
201 if (dims <= 1)
202 throw InternalErr(__FILE__, __LINE__, "Dimension count is <= 1 while printing multidimensional array.");
203
204 start_xml_declaration(writer, element);
205
206 // shape holds the maximum index value of all but the last dimension of
207 // the array (not the size; each value is one less that the size).
208 vector < int >shape = get_shape_vector(dims - 1);
209 int rightmost_dim_size = get_nth_dim_size(dims - 1);
210
211 // state holds the indexes of the current row being printed. For an N-dim
212 // array, there are N-1 dims that are iterated over when printing (the
213 // Nth dim is not printed explicitly. Instead it's the number of values
214 // on the row).
215 vector < int >state(dims - 1, 0);
216
217 bool more_indices;
218 int index = 0;
219 do {
220 for (int i = 0; i < dims - 1; ++i) {
221 if (xmlTextWriterStartElement(writer->get_writer(), (const xmlChar*) "dim") < 0)
222 throw InternalErr(__FILE__, __LINE__, "Could not write Array element for " + name());
223 if (xmlTextWriterWriteFormatAttribute(writer->get_writer(), (const xmlChar*) "number", "%d", i) < 0)
224 throw InternalErr(__FILE__, __LINE__, "Could not write number attribute for " + name() + ": " + long_to_string(i));
225 if (xmlTextWriterWriteFormatAttribute(writer->get_writer(), (const xmlChar*) "index", "%d", state[i]) < 0)
226 throw InternalErr(__FILE__, __LINE__, "Could not write index attribute for " + name());
227 }
228
229 index = m_print_xml_row(writer, index, rightmost_dim_size);
230
231 for (int i = 0; i < dims - 1; ++i) {
232 if (xmlTextWriterEndElement(writer->get_writer()) < 0)
233 throw InternalErr(__FILE__, __LINE__, "Could not end element for " + name());
234 }
235
236 more_indices = increment_state(&state, shape);
237 } while (more_indices);
238
239 end_xml_declaration(writer);
240}
241
269int XDArray::m_print_xml_row(XMLWriter *writer, int index, int number)
270{
271 Array *a = dynamic_cast<Array*>(d_redirect);
272#if ENABLE_UNIT_TESTS
273 if (!a)
274 a = this;
275#else
276 if (!a)
277 throw InternalErr(__FILE__, __LINE__, "d_redirect is null");
278#endif
279
280 BESDEBUG("xd", "Entering XDArray::m_print_xml_row" << endl);
281 for (int i = 0; i < number; ++i) {
282 // Must use the variable that holds the data here!
283 BaseType *curr_var = basetype_to_xd(a->var(index++));
284 dynamic_cast < XDOutput & >(*curr_var).print_xml_data(writer, false);
285 // we're not saving curr_var for future use, so delete it here
286 delete curr_var;
287 }
288
289 return index;
290}
291
292// Given a vector of indices, return the corresponding index.
293
294int XDArray::m_get_index(vector < int >indices) throw(InternalErr)
295{
296 if (indices.size() != dimensions(true)) {
297 throw InternalErr(__FILE__, __LINE__,
298 "Index vector is the wrong size!");
299 }
300 // suppose shape is [3][4][5][6] for x,y,z,t. The index is
301 // t + z(6) + y(5 * 6) + x(4 * 5 *6).
302 // Assume that indices[0] holds x, indices[1] holds y, ...
303
304 // It's hard to work with Pixes
305 vector < int >shape = get_shape_vector(indices.size());
306
307 // We want to work from the rightmost index to the left
308 reverse(indices.begin(), indices.end());
309 reverse(shape.begin(), shape.end());
310
311 vector < int >::iterator indices_iter = indices.begin();
312 vector < int >::iterator shape_iter = shape.begin();
313
314 int index = *indices_iter++; // in the ex. above, this adds `t'
315 int multiplier = 1;
316 while (indices_iter != indices.end()) {
317 multiplier *= *shape_iter++;
318 index += multiplier * *indices_iter++;
319 }
320
321 return index;
322}
323
324// get_shape_vector and get_nth_dim_size are public because that are called
325// from Grid. 9/14/2001 jhrg
326
332vector < int > XDArray::get_shape_vector(size_t n) throw(InternalErr)
333{
334 if (n < 1 || n > dimensions(true)) {
335 string msg = "Attempt to get ";
336 msg += long_to_string(n) + " dimensions from " + name()
337 + " which has only " + long_to_string(dimensions(true))
338 + " dimensions.";
339
340 throw InternalErr(__FILE__, __LINE__, msg);
341 }
342
343 vector < int >shape;
344 Array::Dim_iter p = dim_begin();
345 for (unsigned i = 0; i < n && p != dim_end(); ++i, ++p) {
346 shape.push_back(dimension_size(p, true));
347 }
348
349 return shape;
350}
351
355int XDArray::get_nth_dim_size(size_t n) throw(InternalErr)
356{
357 if (n > dimensions(true) - 1) {
358 string msg = "Attempt to get dimension ";
359 msg +=
360 long_to_string(n + 1) + " from `" + name() +
361 "' which has " + long_to_string(dimensions(true)) +
362 " dimension(s).";
363 throw InternalErr(__FILE__, __LINE__, msg);
364 }
365
366 return dimension_size(dim_begin() + n, true);
367}
368
369void XDArray::m_print_xml_complex_array(XMLWriter *writer, const char *element)
370{
371 start_xml_declaration(writer, element);
372
373 int dims = dimensions(true);
374 if (dims < 1)
375 throw InternalErr(__FILE__, __LINE__, "Dimension count is < 1 while printing an array.");
376
377 // shape holds the maximum index value of all but the last dimension of
378 // the array (not the size; each value is one less that the size).
379 vector < int >shape = get_shape_vector(dims);
380
381 vector < int >state(dims, 0);
382
383 bool more_indices = true;
384 do {
385 for (int i = 0; i < dims - 1; ++i) {
386 if (xmlTextWriterStartElement(writer->get_writer(), (const xmlChar*) "dim") < 0)
387 throw InternalErr(__FILE__, __LINE__, "Could not write Array element for " + name());
388 if (xmlTextWriterWriteFormatAttribute(writer->get_writer(), (const xmlChar*) "number", "%d", i) < 0)
389 throw InternalErr(__FILE__, __LINE__, "Could not write number attribute for " + name() + ": " + long_to_string(i));
390 if (xmlTextWriterWriteFormatAttribute(writer->get_writer(), (const xmlChar*) "index", "%d", state[i]) < 0)
391 throw InternalErr(__FILE__, __LINE__, "Could not write index attribute for " + name());
392 }
393
394 BaseType *curr_var = basetype_to_xd(var(m_get_index(state)));
395 dynamic_cast < XDOutput & >(*curr_var).print_xml_data(writer, true);
396 // we are not saving curr_var for future reference, so delete it
397 delete curr_var;
398
399 for (int i = 0; i < dims - 1; ++i) {
400 if (xmlTextWriterEndElement(writer->get_writer()) < 0)
401 throw InternalErr(__FILE__, __LINE__, "Could not end element for " + name());
402 }
403
404 more_indices = increment_state(&state, shape);
405
406 } while (more_indices);
407
408 end_xml_declaration(writer);
409}
void print_xml_map_data(XMLWriter *writer, bool show_type)
Definition XDArray.cc:100
vector< int > get_shape_vector(size_t n)
Definition XDArray.cc:332
int get_nth_dim_size(size_t n)
Definition XDArray.cc:355
XDOutput(libdap::BaseType *bt)
Definition XDOutput.h:54