bes  Updated for version 3.20.6
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 
40 using namespace std;
41 
42 //#define DODS_DEBUG
43 #include <BESDebug.h>
44 
45 #include <InternalErr.h>
46 #include <escaping.h>
47 #include <util.h>
48 #include <debug.h>
49 
50 #include "XDArray.h"
51 #include "get_xml_data.h"
52 
53 using namespace xml_data;
54 
55 BaseType *
56 XDArray::ptr_duplicate()
57 {
58  return new XDArray(*this);
59 }
60 
61 XDArray::XDArray(const string &n, BaseType *v) : Array(n, v)
62 {
63 }
64 
65 XDArray::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 
90 XDArray::~XDArray()
91 {
92 }
93 
100 void 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 
116 void 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 
131 class PrintArrayDimXML : public unary_function<Array::dimension&, void>
132 {
133  XMLWriter *d_writer;
134  bool d_constrained;
135 
136 public:
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 
166 void 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.
183 void 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 
196 void 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 
269 int 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 
294 int 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 
332 vector < 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 
355 int 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 
369 void 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 }
XDArray::print_xml_map_data
void print_xml_map_data(XMLWriter *writer, bool show_type)
Definition: XDArray.cc:100
XDArray
Definition: XDArray.h:42
XDArray::get_nth_dim_size
int get_nth_dim_size(size_t n)
Definition: XDArray.cc:355
XDArray::get_shape_vector
vector< int > get_shape_vector(size_t n)
Definition: XDArray.cc:332
XDOutput
Definition: XDOutput.h:42
XDOutput::increment_state
virtual bool increment_state(vector< int > *state, const vector< int > &shape)
Definition: XDOutput.cc:124