libdap Updated for version 3.18.1
D4Sequence.cc
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//#define DODS_DEBUG
28
29#include <algorithm>
30#include <string>
31#include <sstream>
32
33#include "D4Sequence.h"
34
35#include "D4StreamMarshaller.h"
36#include "D4StreamUnMarshaller.h"
37
38#include "D4RValue.h"
39#include "D4FilterClause.h" // also contains D4FilterClauseList
40
41#include "debug.h"
42#include "Error.h"
43#include "InternalErr.h"
44#include "util.h"
45#include "escaping.h"
46
47#undef CLEAR_LOCAL_DATA
48
49using namespace std;
50
51namespace libdap {
52
53#if 0
54// Keep this stuff around in case we decide to switch back to sentinels
55
56static const unsigned char end_of_sequence = 0xA5;// binary pattern 1010 0101
57static const unsigned char start_of_instance = 0x5A;// binary pattern 0101 1010
58
59static void
60write_end_of_sequence(Marshaller &m)
61{
62 m.put_opaque( (char *)&end_of_sequence, 1 );
63}
64
65static void
66write_start_of_instance(Marshaller &m)
67{
68 m.put_opaque( (char *)&start_of_instance, 1 );
69}
70
71static unsigned char
72read_marker(UnMarshaller &um)
73{
74 unsigned char marker;
75 um.get_opaque( (char *)&marker, 1 );
76
77 return marker;
78}
79
80static bool
81is_start_of_instance(unsigned char marker)
82{
83 return (marker == start_of_instance);
84}
85
86static bool
87is_end_of_sequence(unsigned char marker)
88{
89 return (marker == end_of_sequence);
90}
91#endif
92
93// Private member functions
94
95// A reminder of these type defs
96//
97// typedef vector<BaseType *> D4SeqRow;
98// typedef vector<D4SeqRow *> D4SeqValues;
99// D4SeqValues d_values;
100
101void D4Sequence::m_duplicate(const D4Sequence &s)
102{
103 d_length = s.d_length;
104#if INDEX_SUBSETTING
105 d_starting_row_number = s.d_starting_row_number;
106 d_ending_row_number = s.d_ending_row_number;
107 d_row_stride = s.d_row_stride;
108#endif
109 // Deep copy for the values
110 for (D4SeqValues::const_iterator i = s.d_values.begin(), e = s.d_values.end(); i != e; ++i) {
111 D4SeqRow &row = **i;
112 D4SeqRow *dest = new D4SeqRow;
113 for (D4SeqRow::const_iterator j = row.begin(), e = row.end(); j != e; ++j) {
114 // *j is a BaseType*
115 dest->push_back((*j)->ptr_duplicate());
116 }
117
118 d_values.push_back(dest);
119 }
120
121 d_copy_clauses = s.d_copy_clauses;
122 d_clauses = (s.d_clauses != 0) ? new D4FilterClauseList(*s.d_clauses) : 0; // deep copy if != 0
123}
124
125// Public member functions
126
135D4Sequence::D4Sequence(const string &n) :
136 Constructor(n, dods_sequence_c, true /* is dap4 */), d_clauses(0), d_copy_clauses(true), d_length(0)
137{
138}
139
150D4Sequence::D4Sequence(const string &n, const string &d) :
151 Constructor(n, d, dods_sequence_c, true /* is dap4 */), d_clauses(0), d_copy_clauses(true), d_length(0)
152{
153}
154
157{
158 m_duplicate(rhs);
159}
160
161BaseType *
163{
164 return new D4Sequence(*this);
165}
166
167static inline void delete_bt(BaseType *bt_ptr)
168{
169 delete bt_ptr;
170}
171
172static inline void delete_rows(D4SeqRow *bt_row_ptr)
173{
174 for_each(bt_row_ptr->begin(), bt_row_ptr->end(), delete_bt);
175
176 delete bt_row_ptr;
177}
178
179D4Sequence::~D4Sequence()
180{
182 delete d_clauses;
183}
184
186{
187 if (!d_values.empty()) {
188 for_each(d_values.begin(), d_values.end(), delete_rows);
189 d_values.resize(0);
190 }
191
192 set_read_p(false);
193}
194
196D4Sequence::operator=(const D4Sequence &rhs)
197{
198 if (this == &rhs) return *this;
199
200 dynamic_cast<Constructor &>(*this) = rhs; // run Constructor=
201
202 m_duplicate(rhs);
203
204 return *this;
205}
206
231{
232 bool eof = false;
233 bool done = false;
234
235 do {
236 eof = read();
237 if (eof) { // bail if EOF
238 continue;
239 }
240 // if we are supposed to filter and the clauses eval to true, we're done
241 else if (filter && d_clauses && d_clauses->value()) {
242 d_length++;
243 done = true;
244 }
245 // else if we're not supposed to filter or there are no clauses, we're done
246 else if (!filter || !d_clauses) {
247 d_length++;
248 done = true;
249 }
250
251 // Set up the next call to get another row's worth of data
252 set_read_p(false);
253
254 } while (!eof && !done);
255
256 return !eof;
257}
258
260{
262
263#if 0
264 // Read the data values, then serialize.
265 while (read_next_instance(true /*filter*/)) {
266 D4SeqRow *row = new D4SeqRow;
267 for (Vars_iter i = d_vars.begin(), e = d_vars.end(); i != e; i++) {
268 if ((*i)->send_p()) {
269 // store the variable's value.
270 row->push_back((*i)->ptr_duplicate());
271 // the copy should have read_p true to prevent the serialize() call
272 // below in the nested for loops from triggering a second call to
273 // read().
274 row->back()->set_read_p(true);
275 }
276 }
277 d_values.push_back(row);
278 }
279
280 set_length(d_values.size());
281#endif
282}
283
306{
307 DBG(cerr << __PRETTY_FUNCTION__ << " BEGIN" << endl);
308
309 if (read_p()) return;
310
311 // Read the data values, then serialize. NB: read_next_instance sets d_length
312 // evaluates the filter expression
313 while (read_next_instance(filter)) {
314 DBG(cerr << "read_sequence_values() - Adding row" << endl);
315 D4SeqRow* row = new D4SeqRow;
316 for (Vars_iter i = d_vars.begin(), e = d_vars.end(); i != e; i++) {
317 if ((*i)->send_p()) {
318 DBG(cerr << ":serialize() - reading data for " << (*i)->type_name() << " " << (*i)->name() << endl);
319 if ((*i)->type() == dods_sequence_c) {
320 DBG(cerr << "Reading child sequence values for " << (*i)->name() << endl);
321 D4Sequence *d4s = static_cast<D4Sequence*>(*i);
322 d4s->read_sequence_values(filter);
323 d4s->d_copy_clauses = false;
324 row->push_back(d4s->ptr_duplicate());
325 d4s->d_copy_clauses = true; // Must be sure to not break the object in general
326 row->back()->set_read_p(true);
327 }
328 else {
329 // store the variable's value.
330 row->push_back((*i)->ptr_duplicate());
331 // the copy should have read_p true to prevent the serialize() call
332 // below in the nested for loops from triggering a second call to
333 // read().
334 row->back()->set_read_p(true);
335 }
336 }
337 }
338
339 // When specializing this, use set_value()
340 d_values.push_back(row);
341 DBG(cerr << " read_sequence_values() - Row completed" << endl);
342 }
343
344 set_length(d_values.size());
345
346 DBGN(cerr << __PRETTY_FUNCTION__ << " END added " << d_values.size() << endl);
347}
348
369{
370 DBGN(cerr << __PRETTY_FUNCTION__ << " BEGIN" << endl);
371
372 // Read the data values, then serialize. NB: read_next_instance sets d_length
373 // evaluates the filter expression
374 read_sequence_values(filter);
375
376 // write D4Sequecne::length(); don't include the length in the checksum
377 m.put_count(d_length);
378
379 // By this point the d_values object holds all and only the values to be sent;
380 // use the serialize methods to send them (but no need to test send_p).
381 for (D4SeqValues::iterator i = d_values.begin(), e = d_values.end(); i != e; ++i) {
382 for (D4SeqRow::iterator j = (*i)->begin(), f = (*i)->end(); j != f; ++j) {
383 (*j)->serialize(m, dmr, /*eval,*/false);
384 }
385 }
386
387 DBGN(cerr << __PRETTY_FUNCTION__ << " END" << endl);
388}
389
391{
392 int64_t um_count = um.get_count();
393
394 set_length(um_count);
395
396 for (int64_t i = 0; i < d_length; ++i) {
397 D4SeqRow *row = new D4SeqRow;
398 for (Vars_iter i = d_vars.begin(), e = d_vars.end(); i != e; ++i) {
399 (*i)->deserialize(um, dmr);
400 row->push_back((*i)->ptr_duplicate());
401 }
402 d_values.push_back(row);
403 }
404}
405
417{
418 if (!d_clauses) d_clauses = new D4FilterClauseList();
419 return *d_clauses;
420}
421
422
423#if INDEX_SUBSETTING
432virtual void set_row_number_constraint(int start, int stop, int stride)
433{
434 if (stop < start)
435 throw Error(malformed_expr, "Starting row number must precede the ending row number.");
436
437 d_starting_row_number = start;
438 d_row_stride = stride;
439 d_ending_row_number = stop;
440}
441#endif
442
447D4SeqRow *
449{
450 if (row >= d_values.size()) return 0;
451 return d_values[row];
452}
453
454static bool base_type_name_eq(BaseType *btp, const string name)
455{
456 return btp->name() == name;
457}
458
464BaseType *
465D4Sequence::var_value(size_t row_num, const string &name)
466{
467 D4SeqRow *row = row_value(row_num);
468 if (!row) return 0;
469
470 D4SeqRow::iterator elem = find_if(row->begin(), row->end(), bind2nd(ptr_fun(base_type_name_eq), name));
471 return (elem != row->end()) ? *elem : 0;
472}
473
479BaseType *
480D4Sequence::var_value(size_t row_num, size_t i)
481{
482 D4SeqRow *row = row_value(row_num);
483 if (!row) return 0;
484
485 if (i >= row->size()) return 0;
486
487 return (*row)[i];
488}
489
490void D4Sequence::print_one_row(ostream &out, int row, string space, bool print_row_num)
491{
492 if (print_row_num) out << "\n" << space << row << ": ";
493
494 out << "{ ";
495
496 int elements = element_count();
497 int j = 0;
498 BaseType *bt_ptr = 0;
499
500 // This version of print_one_row() works for both data read with
501 // deserialize(), where each variable is assumed to have valid data, and
502 // intern_data(), where some/many variables do not. Because of that, it's
503 // not correct to assume that all of the elements will be printed, which
504 // is what the old code did.
505
506 // Print the first value
507 while (j < elements && !bt_ptr) {
508 bt_ptr = var_value(row, j++);
509 if (bt_ptr) { // data
510 if (bt_ptr->type() == dods_sequence_c) static_cast<D4Sequence*>(bt_ptr)->print_val_by_rows(out,
511 space + " ", false, print_row_num);
512 else
513 bt_ptr->print_val(out, space, false);
514 }
515 }
516
517 // Print the remaining values
518 while (j < elements) {
519 bt_ptr = var_value(row, j++);
520 if (bt_ptr) { // data
521 out << ", ";
522 if (bt_ptr->type() == dods_sequence_c) static_cast<D4Sequence*>(bt_ptr)->print_val_by_rows(out,
523 space + " ", false, print_row_num);
524 else
525 bt_ptr->print_val(out, space, false);
526 }
527 }
528
529 out << " }";
530}
531
532void D4Sequence::print_val_by_rows(ostream &out, string space, bool print_decl_p, bool print_row_numbers)
533{
534 if (print_decl_p) {
535 print_decl(out, space, false);
536 out << " = ";
537 }
538
539 out << "{ ";
540
541 if (length() != 0) {
542 int rows = length() - 1; // -1 because the last row is treated specially
543 for (int i = 0; i < rows; ++i) {
544 print_one_row(out, i, space, print_row_numbers);
545 out << ", ";
546 }
547 print_one_row(out, rows, space, print_row_numbers);
548 }
549
550 out << " }";
551
552 if (print_decl_p) out << ";\n";
553}
554
555void D4Sequence::print_val(ostream &out, string space, bool print_decl_p)
556{
557 DBG(cerr << name() << " isa " << type_name() << endl);
558
559 print_val_by_rows(out, space, print_decl_p, false);
560}
561
570void D4Sequence::dump(ostream &strm) const
571{
572 strm << DapIndent::LMarg << "Sequence::dump - (" << (void *) this << ")" << endl;
573 DapIndent::Indent();
574 Constructor::dump(strm);
575 strm << DapIndent::LMarg << "# rows deserialized: " << d_length << endl;
576 strm << DapIndent::LMarg << "bracket notation information:" << endl;
577
578 DapIndent::Indent();
579#if INDEX_SUBSETTING
580 strm << DapIndent::LMarg << "starting row #: " << d_starting_row_number << endl;
581 strm << DapIndent::LMarg << "row stride: " << d_row_stride << endl;
582 strm << DapIndent::LMarg << "ending row #: " << d_ending_row_number << endl;
583#endif
584 DapIndent::UnIndent();
585
586 DapIndent::UnIndent();
587}
588
589} // namespace libdap
590
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 string name() const
Returns the name of the class instance.
Definition: BaseType.cc:265
virtual bool read_p()
Has this variable been read?
Definition: BaseType.cc:425
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
virtual int element_count(bool leaves=false)
Count the members of constructor types.
Definition: Constructor.cc:169
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Constructor.cc:827
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:601
virtual bool read()
simple implementation of read that iterates through vars and calls read on them
Definition: Constructor.cc:451
virtual void set_read_p(bool state)
Sets the value of the read_p property.
Definition: Constructor.cc:193
List of DAP4 Filter Clauses.
bool value(DMR &dmr)
Evaluate the list of clauses.
Holds a sequence.
Definition: D4Sequence.h:134
virtual D4SeqRow * row_value(size_t row)
Get a whole row from the sequence.
Definition: D4Sequence.cc:448
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:230
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: D4Sequence.cc:555
D4Sequence(const string &n)
The Sequence constructor.
Definition: D4Sequence.cc:135
virtual bool serialize(ConstraintEvaluator &, DDS &, Marshaller &, bool)
Move data to the net, then remove them from the object.
Definition: D4Sequence.h:206
D4FilterClauseList & clauses()
Access the filter clauses for this D4Sequence.
Definition: D4Sequence.cc:416
virtual void intern_data()
Read data into this variable.
Definition: D4Sequence.cc:259
virtual BaseType * ptr_duplicate()
Definition: D4Sequence.cc:162
virtual bool deserialize(UnMarshaller &, DDS *, bool)
Receive data from the net.
Definition: D4Sequence.h:209
void read_sequence_values(bool filter)
Read a Sequence's value into memory.
Definition: D4Sequence.cc:305
virtual void set_length(int count)
Definition: D4Sequence.h:199
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:465
virtual void dump(ostream &strm) const
dumps information about this object
Definition: D4Sequence.cc:570
virtual void clear_local_data()
Definition: D4Sequence.cc:185
virtual int length() const
The number of elements in a Sequence object.
Definition: D4Sequence.h:193
Marshaller that knows how to marshal/serialize dap data objects to a C++ iostream using DAP4's receiv...
virtual void put_count(int64_t count)
Read data from the stream made by D4StreamMarshaller.
A class for error processing.
Definition: Error.h:91
vector< BaseType * > D4SeqRow
Definition: D4Sequence.h:39