libdap++  Updated for version 3.14.0
D4Sequence.cc
Go to the documentation of this file.
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
4 // Access Protocol.
5 
6 // Copyright (c) 2013 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@opendap.org>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 //
23 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24 
25 #include "config.h"
26 
27 #include <algorithm>
28 #include <string>
29 #include <sstream>
30 
31 //#define DODS_DEBUG
32 //#define DODS_DEBUG2
33 
34 #include "Byte.h"
35 #include "Int16.h"
36 #include "UInt16.h"
37 #include "Int32.h"
38 #include "UInt32.h"
39 #include "Float32.h"
40 #include "Float64.h"
41 #include "Str.h"
42 #include "Url.h"
43 #include "Array.h"
44 #include "Structure.h"
45 #include "D4Sequence.h"
46 
47 #include "D4StreamMarshaller.h"
48 #include "D4StreamUnMarshaller.h"
49 
50 #include "debug.h"
51 #include "Error.h"
52 #include "InternalErr.h"
53 #include "util.h"
54 #include "escaping.h"
55 
56 using namespace std;
57 
58 namespace libdap {
59 
60 #if 0
61 // Keep this stuff around in case we decide to switch back to sentinels
62 
63 static const unsigned char end_of_sequence = 0xA5;// binary pattern 1010 0101
64 static const unsigned char start_of_instance = 0x5A;// binary pattern 0101 1010
65 
66 static void
67 write_end_of_sequence(Marshaller &m)
68 {
69  m.put_opaque( (char *)&end_of_sequence, 1 );
70 }
71 
72 static void
73 write_start_of_instance(Marshaller &m)
74 {
75  m.put_opaque( (char *)&start_of_instance, 1 );
76 }
77 
78 static unsigned char
79 read_marker(UnMarshaller &um)
80 {
81  unsigned char marker;
82  um.get_opaque( (char *)&marker, 1 );
83 
84  return marker;
85 }
86 
87 static bool
88 is_start_of_instance(unsigned char marker)
89 {
90  return (marker == start_of_instance);
91 }
92 
93 static bool
94 is_end_of_sequence(unsigned char marker)
95 {
96  return (marker == end_of_sequence);
97 }
98 #endif
99 
100 // Private member functions
101 
102 // A reminder of these type defs
103 //
104 // typedef vector<BaseType *> D4SeqRow;
105 // typedef vector<D4SeqRow *> D4SeqValues;
106 // D4SeqValues d_values;
107 
108 void D4Sequence::m_duplicate(const D4Sequence &s)
109 {
110  d_length = s.d_length;
111 #if INDEX_SUBSETTING
112  d_starting_row_number = s.d_starting_row_number;
113  d_ending_row_number = s.d_ending_row_number;
114  d_row_stride = s.d_row_stride;
115 #endif
116  // Deep copy for the values
117  for (D4SeqValues::const_iterator i = s.d_values.begin(), e = s.d_values.end(); i != e; ++i) {
118  D4SeqRow &row = **i;
119  D4SeqRow *dest = new D4SeqRow;
120  for (D4SeqRow::const_iterator j = row.begin(), e = row.end(); j != e; ++j) {
121  // *j is a BaseType*
122  dest->push_back((*j)->ptr_duplicate());
123  }
124 
125  d_values.push_back(dest);
126  }
127 }
128 
129 // Public member functions
130 
139 D4Sequence::D4Sequence(const string &n) :
140  Constructor(n, dods_sequence_c, true /* is dap4 */), d_length(0) // , d_starting_row_number(-1), d_row_stride(1), d_ending_row_number(-1)
141 {
142 }
143 
154 D4Sequence::D4Sequence(const string &n, const string &d) :
155  Constructor(n, d, dods_sequence_c, true /* is dap4 */), d_length(0) //, d_starting_row_number(-1), d_row_stride(1), d_ending_row_number(-1)
156 {
157 }
158 
161  Constructor(rhs)
162 {
163  m_duplicate(rhs);
164 }
165 
166 BaseType *
168 {
169  return new D4Sequence(*this);
170 }
171 
172 static inline void delete_bt(BaseType *bt_ptr)
173 {
174  delete bt_ptr;
175 }
176 
177 static inline void delete_rows(D4SeqRow *bt_row_ptr)
178 {
179  for_each(bt_row_ptr->begin(), bt_row_ptr->end(), delete_bt);
180 
181  delete bt_row_ptr;
182 }
183 
185 {
186  for_each(d_values.begin(), d_values.end(), delete_rows);
187 }
188 
189 D4Sequence &
191 {
192  if (this == &rhs) return *this;
193 
194  dynamic_cast<Constructor &>(*this) = rhs; // run Constructor=
195 
196  m_duplicate(rhs);
197 
198  return *this;
199 }
200 
224 bool D4Sequence::read_next_instance(/*DMR &dmr, ConstraintEvaluator &eval,*/bool filter)
225 {
226  bool eof = false;
227  bool done = false;
228 
229  do {
230  eof = read();
231  // Advance the row number if ce_eval is false (we're not supposed to
232  // evaluate the selection) or both filter and the selection are
233  // true.
234  // FIXME CE's not supported for DAP4 yet. jhrg 10/11/13
235  filter = false;
236  if (!eof && (!filter /*|| eval.eval_selection(dmr, dataset()*/)) {
237  d_length++;
238  done = true;
239  }
240  } while (!eof && !done);
241 
242  DBG(cerr << "D4Sequence::read_next_instance eof: " << eof << endl);
243  return !eof;
244 }
245 
246 #if 0
247 // Used the version in Constructor, which throws an exception because we should
248 // not compute these for constructor types. In the case of Sequence, it requires
249 // that the values all get read.
257 void
259 {
260  // Read the data values, then serialize.
261  while (read_next_instance(dmr, eval, true)) {
262  for (Vars_iter i = d_vars.begin(), e = d_vars.end(); i != e; i++) {
263  if ((*i)->send_p()) {
264  (*i)->compute_checksum(checksum);
265  }
266  }
267  }
268 }
269 #endif
270 
271 void D4Sequence::intern_data(Crc32 &checksum/*, DMR &dmr, ConstraintEvaluator &eval*/)
272 {
273  // Read the data values, then serialize.
274  while (read_next_instance(/*dmr, eval,*/true /*filter*/)) {
275  D4SeqRow *row = new D4SeqRow;
276  for (Vars_iter i = d_vars.begin(), e = d_vars.end(); i != e; i++) {
277  if ((*i)->send_p()) {
278  // store the variable's value.
279  row->push_back((*i)->ptr_duplicate());
280  // the copy should have read_p true to prevent the serialize() call
281  // below in the nested for loops from triggering a second call to
282  // read().
283  row->back()->set_read_p(true);
284  // Do not compute the checksum for constructor types; those
285  // types will compute the checksum on the values they contain.
286  // TODO Check on this
287  if (!row->back()->is_constructor_type()) row->back()->compute_checksum(checksum);
288  }
289  }
290  d_values.push_back(row);
291  }
292 }
293 
313 void D4Sequence::serialize(D4StreamMarshaller &m, DMR &dmr, bool filter)
314 {
315  // Read the data values, then serialize. NB: read_next_instance sets d_length.
316  while (read_next_instance(filter)) {
317  D4SeqRow *row = new D4SeqRow;
318  for (Vars_iter i = d_vars.begin(), e = d_vars.end(); i != e; i++) {
319  if ((*i)->send_p()) {
320  // store the variable's value.
321  row->push_back((*i)->ptr_duplicate());
322  // the copy should have read_p true to prevent the serialize() call
323  // below in the nested for loops from triggering a second call to
324  // read().
325  row->back()->set_read_p(true);
326  }
327  }
328  d_values.push_back(row);
329  DBG(cerr << "D4Sequence::serialize Added row" << endl);
330  }
331 
332  // write D4Sequecne::length(); don't include the length in the checksum
333  m.put_count(d_length);
334  DBG(cerr << "D4Sequence::serialize count: " << d_length << endl);
335 
336  // By this point the d_values object holds all and only the values to be sent;
337  // use the serialize methods to send them (but no need to test send_p).
338  for (D4SeqValues::iterator i = d_values.begin(), e = d_values.end(); i != e; ++i) {
339  for (D4SeqRow::iterator j = (*i)->begin(), f = (*i)->end(); j != f; ++j) {
340  (*j)->serialize(m, dmr, /*eval,*/false);
341  }
342  }
343 }
344 
346 {
347  set_length(um.get_count());
348  DBG(cerr << "D4Sequence::deserialize count: " << d_length << endl);
349 
350  for (int64_t i = 0; i < d_length; ++i) {
351  D4SeqRow *row = new D4SeqRow;
352  for (Vars_iter i = d_vars.begin(), e = d_vars.end(); i != e; ++i) {
353  (*i)->deserialize(um, dmr);
354  row->push_back((*i)->ptr_duplicate());
355  }
356  d_values.push_back(row);
357  }
358 }
359 
360 #if INDEX_SUBSETTING
361 
369 virtual void set_row_number_constraint(int start, int stop, int stride)
370 {
371  if (stop < start)
372  throw Error(malformed_expr, "Starting row number must precede the ending row number.");
373 
374  d_starting_row_number = start;
375  d_row_stride = stride;
376  d_ending_row_number = stop;
377 }
378 #endif
379 
384 D4SeqRow *
386 {
387  if (row >= d_values.size()) return 0;
388  return d_values[row];
389 }
390 
391 static bool base_type_name_eq(BaseType *btp, const string name)
392 {
393  return btp->name() == name;
394 }
395 
401 BaseType *
402 D4Sequence::var_value(size_t row_num, const string &name)
403 {
404  D4SeqRow *row = row_value(row_num);
405  if (!row) return 0;
406 
407  D4SeqRow::iterator elem = find_if(row->begin(), row->end(), bind2nd(ptr_fun(base_type_name_eq), name));
408  return (elem != row->end()) ? *elem : 0;
409 }
410 
416 BaseType *
417 D4Sequence::var_value(size_t row_num, size_t i)
418 {
419  D4SeqRow *row = row_value(row_num);
420  if (!row) return 0;
421 
422  if (i >= row->size()) return 0;
423 
424  return (*row)[i];
425 }
426 
427 void D4Sequence::print_one_row(ostream &out, int row, string space, bool print_row_num)
428 {
429  if (print_row_num) out << "\n" << space << row << ": ";
430 
431  out << "{ ";
432 
433  int elements = element_count();
434  int j = 0;
435  BaseType *bt_ptr = 0;
436 
437  // This version of print_one_row() works for both data read with
438  // deserialize(), where each variable is assumed to have valid data, and
439  // intern_data(), where some/many variables do not. Because of that, it's
440  // not correct to assume that all of the elements will be printed, which
441  // is what the old code did.
442 
443  // Print the first value
444  while (j < elements && !bt_ptr) {
445  bt_ptr = var_value(row, j++);
446  if (bt_ptr) { // data
447  if (bt_ptr->type() == dods_sequence_c) static_cast<D4Sequence*>(bt_ptr)->print_val_by_rows(out,
448  space + " ", false, print_row_num);
449  else
450  bt_ptr->print_val(out, space, false);
451  }
452  }
453 
454  // Print the remaining values
455  while (j < elements) {
456  bt_ptr = var_value(row, j++);
457  if (bt_ptr) { // data
458  out << ", ";
459  if (bt_ptr->type() == dods_sequence_c) static_cast<D4Sequence*>(bt_ptr)->print_val_by_rows(out,
460  space + " ", false, print_row_num);
461  else
462  bt_ptr->print_val(out, space, false);
463  }
464  }
465 
466  out << " }";
467 }
468 
469 void D4Sequence::print_val_by_rows(ostream &out, string space, bool print_decl_p, bool print_row_numbers)
470 {
471  if (print_decl_p) {
472  print_decl(out, space, false);
473  out << " = ";
474  }
475 
476  out << "{ ";
477 
478  if (length() != 0) {
479  int rows = length() - 1; // -1 because the last row is treated specially
480  for (int i = 0; i < rows; ++i) {
481  print_one_row(out, i, space, print_row_numbers);
482  out << ", ";
483  }
484  print_one_row(out, rows, space, print_row_numbers);
485  }
486 
487  out << " }";
488 
489  if (print_decl_p) out << ";\n";
490 }
491 
492 void D4Sequence::print_val(ostream &out, string space, bool print_decl_p)
493 {
494  print_val_by_rows(out, space, print_decl_p, false);
495 }
496 
505 void D4Sequence::dump(ostream &strm) const
506 {
507  strm << DapIndent::LMarg << "Sequence::dump - (" << (void *) this << ")" << endl;
509  Constructor::dump(strm);
510  strm << DapIndent::LMarg << "# rows deserialized: " << d_length << endl;
511  strm << DapIndent::LMarg << "bracket notation information:" << endl;
512 
514 #if INDEX_SUBSETTING
515  strm << DapIndent::LMarg << "starting row #: " << d_starting_row_number << endl;
516  strm << DapIndent::LMarg << "row stride: " << d_row_stride << endl;
517  strm << DapIndent::LMarg << "ending row #: " << d_ending_row_number << endl;
518 #endif
520 
522 }
523 
524 } // namespace libdap
525 
virtual void print_one_row(ostream &out, int row, string space, bool print_row_num=false)
Definition: D4Sequence.cc:427
virtual BaseType * ptr_duplicate()
Definition: D4Sequence.cc:167
static void UnIndent()
Definition: DapIndent.cc:51
virtual void put_count(int64_t count)
#define malformed_expr
Definition: Error.h:64
std::vector< BaseType * > d_vars
Definition: Constructor.h:49
D4Sequence(const string &n)
The Sequence constructor.
Definition: D4Sequence.cc:139
virtual bool read_next_instance(bool filter)
Read the next instance of the sequence While the rest of the variables' read() methods are assumed to...
Definition: D4Sequence.cc:224
Read data from the stream made by D4StreamMarshaller.
std::vector< BaseType * >::iterator Vars_iter
Definition: Constructor.h:62
Definition: crc.h:76
virtual void compute_checksum(Crc32 &checksum)
include the data for this variable in the checksum DAP4 includes a checksum with every data response...
Definition: Constructor.cc:524
virtual BaseType * var_value(size_t row, const string &name)
Get the BaseType pointer to the named variable of a given row.
Definition: D4Sequence.cc:402
Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:306
vector< BaseType * > D4SeqRow
Definition: D4Sequence.h:38
virtual int element_count(bool leaves=false)
Count the members of constructor types.
Definition: Constructor.cc:169
#define DBG(x)
Definition: debug.h:58
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: BaseType.cc:992
Marshaller that knows how to marshal/serialize dap data objects to a C++ iostream using DAP4's receiv...
static void Indent()
Definition: DapIndent.cc:45
virtual void set_length(int count)
Definition: D4Sequence.h:174
virtual void dump(ostream &strm) const
dumps information about this object
Definition: D4Sequence.cc:505
Holds a sequence.
Definition: D4Sequence.h:124
virtual int length() const
The number of elements in a Sequence object.
Definition: D4Sequence.h:168
virtual bool read()
simple implementation of read that iterates through vars and calls read on them
Definition: Constructor.cc:451
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Constructor.cc:823
D4Sequence & operator=(const D4Sequence &rhs)
Definition: D4Sequence.cc:190
string name() const
Returns the name of the class instance.
Definition: BaseType.cc:261
virtual void intern_data(ConstraintEvaluator &, DDS &)
Definition: D4Sequence.h:178
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: D4Sequence.cc:492
Evaluate a constraint expression.
static ostream & LMarg(ostream &strm)
Definition: DapIndent.cc:80
virtual bool deserialize(UnMarshaller &, DDS *, bool)
Receive data from the net.
Definition: D4Sequence.h:184
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
virtual void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Print an ASCII representation of the variable structure.
Definition: Constructor.cc:600
D4SeqValues d_values
Definition: D4Sequence.h:133
virtual D4SeqRow * row_value(size_t row)
Get a whole row from the sequence.
Definition: D4Sequence.cc:385
A class for error processing.
Definition: Error.h:90
virtual void print_val_by_rows(ostream &out, string space="", bool print_decl_p=true, bool print_row_numbers=true)
Definition: D4Sequence.cc:469
virtual bool serialize(ConstraintEvaluator &, DDS &, Marshaller &, bool)
Move data to the net.
Definition: D4Sequence.h:181
virtual ~D4Sequence()
Definition: D4Sequence.cc:184
void m_duplicate(const D4Sequence &s)
Definition: D4Sequence.cc:108