libdap Updated for version 3.20.10
libdap4 is an implementation of OPeNDAP's DAP protocol.
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#include "DapIndent.h"
47
48#undef CLEAR_LOCAL_DATA
49
50using namespace std;
51
52namespace libdap {
53
54// Private member functions
55
56// A reminder of these type defs
57//
58// typedef vector<BaseType *> D4SeqRow;
59// typedef vector<D4SeqRow *> D4SeqValues;
60// D4SeqValues d_values;
61
62void D4Sequence::m_duplicate(const D4Sequence &s)
63{
64 d_length = s.d_length;
65#if INDEX_SUBSETTING
66 d_starting_row_number = s.d_starting_row_number;
67 d_ending_row_number = s.d_ending_row_number;
68 d_row_stride = s.d_row_stride;
69#endif
70 // Deep copy for the values
71 for (D4SeqValues::const_iterator i = s.d_values.begin(), e = s.d_values.end(); i != e; ++i) {
72 D4SeqRow &row = **i;
73 D4SeqRow *dest = new D4SeqRow;
74 for (D4SeqRow::const_iterator j = row.begin(), e = row.end(); j != e; ++j) {
75 // *j is a BaseType*
76 dest->push_back((*j)->ptr_duplicate());
77 }
78
79 d_values.push_back(dest);
80 }
81
82 d_copy_clauses = s.d_copy_clauses;
83 d_clauses = (s.d_clauses != 0) ? new D4FilterClauseList(*s.d_clauses) : 0; // deep copy if != 0
84}
85
86// Public member functions
87
96D4Sequence::D4Sequence(const string &n) :
97 Constructor(n, dods_sequence_c, true /* is dap4 */), d_clauses(0), d_copy_clauses(true), d_length(0)
98{
99}
100
111D4Sequence::D4Sequence(const string &n, const string &d) :
112 Constructor(n, d, dods_sequence_c, true /* is dap4 */), d_clauses(0), d_copy_clauses(true), d_length(0)
113{
114}
115
118{
119 m_duplicate(rhs);
120}
121
122BaseType *
124{
125 return new D4Sequence(*this);
126}
127
128static inline void delete_bt(BaseType *bt_ptr)
129{
130 delete bt_ptr;
131}
132
133static inline void delete_rows(D4SeqRow *bt_row_ptr)
134{
135 for_each(bt_row_ptr->begin(), bt_row_ptr->end(), delete_bt);
136
137 delete bt_row_ptr;
138}
139
140D4Sequence::~D4Sequence()
141{
143 delete d_clauses;
144}
145
147{
148 if (!d_values.empty()) {
149 for_each(d_values.begin(), d_values.end(), delete_rows);
150 d_values.resize(0);
151 }
152
153 set_read_p(false);
154}
155
157D4Sequence::operator=(const D4Sequence &rhs)
158{
159 if (this == &rhs) return *this;
160 Constructor::operator=(rhs);
161 m_duplicate(rhs);
162 return *this;
163}
164
189{
190 bool eof = false;
191 bool done = false;
192
193 do {
194 eof = read();
195 if (eof) { // bail if EOF
196 continue;
197 }
198 // if we are supposed to filter and the clauses eval to true, we're done
199 else if (filter && d_clauses && d_clauses->value()) {
200 d_length++;
201 done = true;
202 }
203 // else if we're not supposed to filter or there are no clauses, we're done
204 else if (!filter || !d_clauses) {
205 d_length++;
206 done = true;
207 }
208
209 // Set up the next call to get another row's worth of data
210 set_read_p(false);
211
212 } while (!eof && !done);
213
214 return !eof;
215}
216
221
244{
245 DBG(cerr << __PRETTY_FUNCTION__ << " BEGIN" << endl);
246
247 if (read_p()) return;
248
249 // Read the data values, then serialize. NB: read_next_instance sets d_length
250 // evaluates the filter expression
251 while (read_next_instance(filter)) {
252 DBG(cerr << "read_sequence_values() - Adding row" << endl);
253 D4SeqRow* row = new D4SeqRow;
254 for (Vars_iter i = d_vars.begin(), e = d_vars.end(); i != e; i++) {
255 if ((*i)->send_p()) {
256 DBG(cerr << ":serialize() - reading data for " << (*i)->type_name() << " " << (*i)->name() << endl);
257 if ((*i)->type() == dods_sequence_c) {
258 DBG(cerr << "Reading child sequence values for " << (*i)->name() << endl);
259 D4Sequence *d4s = static_cast<D4Sequence*>(*i);
260 d4s->read_sequence_values(filter);
261 d4s->d_copy_clauses = false;
262 row->push_back(d4s->ptr_duplicate());
263 d4s->d_copy_clauses = true; // Must be sure to not break the object in general
264 row->back()->set_read_p(true);
265 }
266 else {
267 // store the variable's value.
268 row->push_back((*i)->ptr_duplicate());
269 // the copy should have read_p true to prevent the serialize() call
270 // below in the nested for loops from triggering a second call to
271 // read().
272 row->back()->set_read_p(true);
273 }
274 }
275 }
276
277 // When specializing this, use set_value()
278 d_values.push_back(row);
279 DBG(cerr << " read_sequence_values() - Row completed" << endl);
280 }
281
282 set_length(d_values.size());
283
284 DBGN(cerr << __PRETTY_FUNCTION__ << " END added " << d_values.size() << endl);
285}
286
307{
308 DBGN(cerr << __PRETTY_FUNCTION__ << " BEGIN" << endl);
309
310 // Read the data values, then serialize. NB: read_next_instance sets d_length
311 // evaluates the filter expression
312 read_sequence_values(filter);
313
314 // write D4Sequecne::length(); don't include the length in the checksum
315 m.put_count(d_length);
316
317 // By this point the d_values object holds all and only the values to be sent;
318 // use the serialize methods to send them (but no need to test send_p).
319 for (D4SeqValues::iterator i = d_values.begin(), e = d_values.end(); i != e; ++i) {
320 for (D4SeqRow::iterator j = (*i)->begin(), f = (*i)->end(); j != f; ++j) {
321 (*j)->serialize(m, dmr, /*eval,*/false);
322 }
323 }
324
325 DBGN(cerr << __PRETTY_FUNCTION__ << " END" << endl);
326}
327
329{
330 int64_t um_count = um.get_count();
331
332 set_length(um_count);
333
334 for (int64_t i = 0; i < d_length; ++i) {
335 D4SeqRow *row = new D4SeqRow;
336 for (Vars_iter i = d_vars.begin(), e = d_vars.end(); i != e; ++i) {
337 (*i)->deserialize(um, dmr);
338 row->push_back((*i)->ptr_duplicate());
339 }
340 d_values.push_back(row);
341 }
342}
343
355{
356 if (!d_clauses) d_clauses = new D4FilterClauseList();
357 return *d_clauses;
358}
359
360
361#if INDEX_SUBSETTING
370virtual void set_row_number_constraint(int start, int stop, int stride)
371{
372 if (stop < start)
373 throw Error(malformed_expr, "Starting row number must precede the ending row number.");
374
375 d_starting_row_number = start;
376 d_row_stride = stride;
377 d_ending_row_number = stop;
378}
379#endif
380
385D4SeqRow *
387{
388 if (row >= d_values.size()) return 0;
389 return d_values[row];
390}
391
397BaseType *
398D4Sequence::var_value(size_t row_num, const string &name)
399{
400 D4SeqRow *row = row_value(row_num);
401 if (!row) return nullptr;
402
403 auto elem = find_if(row->begin(), row->end(),
404 [name](const BaseType *btp) { return btp->name() == name; });
405
406 return (elem != row->end()) ? *elem : nullptr;
407}
408
414BaseType *
415D4Sequence::var_value(size_t row_num, size_t i)
416{
417 D4SeqRow *row = row_value(row_num);
418 if (!row) return 0;
419
420 if (i >= row->size()) return 0;
421
422 return (*row)[i];
423}
424
425void D4Sequence::print_one_row(ostream &out, int row, string space, bool print_row_num)
426{
427 if (print_row_num) out << "\n" << space << row << ": ";
428
429 out << "{ ";
430
431 int elements = element_count();
432 int j = 0;
433 BaseType *bt_ptr = 0;
434
435 // This version of print_one_row() works for both data read with
436 // deserialize(), where each variable is assumed to have valid data, and
437 // intern_data(), where some/many variables do not. Because of that, it's
438 // not correct to assume that all of the elements will be printed, which
439 // is what the old code did.
440
441 // Print the first value
442 while (j < elements && !bt_ptr) {
443 bt_ptr = var_value(row, j++);
444 if (bt_ptr) { // data
445 if (bt_ptr->type() == dods_sequence_c) static_cast<D4Sequence*>(bt_ptr)->print_val_by_rows(out,
446 space + " ", false, print_row_num);
447 else
448 bt_ptr->print_val(out, space, false);
449 }
450 }
451
452 // Print the remaining values
453 while (j < elements) {
454 bt_ptr = var_value(row, j++);
455 if (bt_ptr) { // data
456 out << ", ";
457 if (bt_ptr->type() == dods_sequence_c) static_cast<D4Sequence*>(bt_ptr)->print_val_by_rows(out,
458 space + " ", false, print_row_num);
459 else
460 bt_ptr->print_val(out, space, false);
461 }
462 }
463
464 out << " }";
465}
466
467void D4Sequence::print_val_by_rows(ostream &out, string space, bool print_decl_p, bool print_row_numbers)
468{
469 if (print_decl_p) {
470 print_decl(out, space, false);
471 out << " = ";
472 }
473
474 out << "{ ";
475
476 if (length() != 0) {
477 int rows = length() - 1; // -1 because the last row is treated specially
478 for (int i = 0; i < rows; ++i) {
479 print_one_row(out, i, space, print_row_numbers);
480 out << ", ";
481 }
482 print_one_row(out, rows, space, print_row_numbers);
483 }
484
485 out << " }";
486
487 if (print_decl_p) out << ";\n";
488}
489
490void D4Sequence::print_val(ostream &out, string space, bool print_decl_p)
491{
492 DBG(cerr << name() << " isa " << type_name() << endl);
493
494 print_val_by_rows(out, space, print_decl_p, false);
495}
496
505void D4Sequence::dump(ostream &strm) const
506{
507 strm << DapIndent::LMarg << "Sequence::dump - (" << (void *) this << ")" << endl;
508 DapIndent::Indent();
509 Constructor::dump(strm);
510 strm << DapIndent::LMarg << "# rows deserialized: " << d_length << endl;
511 strm << DapIndent::LMarg << "bracket notation information:" << endl;
512
513 DapIndent::Indent();
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
519 DapIndent::UnIndent();
520
521 DapIndent::UnIndent();
522}
523
524} // namespace libdap
525
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:375
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:316
virtual bool read_p()
Has this variable been read?
Definition BaseType.cc:476
int element_count(bool leaves=false) override
Count the members of constructor types.
void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false) override
Print an ASCII representation of the variable structure.
void set_read_p(bool state) override
Set the 'read_p' property for the Constructor and its members.
bool read() override
Read the elements of Constructor marked for transmission.
void dump(ostream &strm) const override
dumps information about this object
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.
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...
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
D4Sequence(const string &n)
The Sequence constructor.
Definition D4Sequence.cc:96
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.
virtual void intern_data()
Read data into this variable.
virtual BaseType * ptr_duplicate()
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.
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.
virtual void dump(ostream &strm) const
dumps information about this object
virtual void clear_local_data()
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...
Read data from the stream made by D4StreamMarshaller.
A class for error processing.
Definition Error.h:94
top level DAP object to house generic methods
vector< BaseType * > D4SeqRow
Definition D4Sequence.h:43