|
Packit |
a4aae4 |
// -*- mode: c++; c-basic-offset:4 -*-
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
|
|
Packit |
a4aae4 |
// Access Protocol.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Copyright (c) 2013 OPeNDAP, Inc.
|
|
Packit |
a4aae4 |
// Author: James Gallagher <jgallagher@opendap.org>
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is free software; you can redistribute it and/or
|
|
Packit |
a4aae4 |
// modify it under the terms of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License as published by the Free Software Foundation; either
|
|
Packit |
a4aae4 |
// version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is distributed in the hope that it will be useful,
|
|
Packit |
a4aae4 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a4aae4 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
a4aae4 |
// Lesser General Public License for more details.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You should have received a copy of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License along with this library; if not, write to the Free Software
|
|
Packit |
a4aae4 |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "config.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
//#define DODS_DEBUG
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <algorithm>
|
|
Packit |
a4aae4 |
#include <string>
|
|
Packit |
a4aae4 |
#include <sstream>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "D4Sequence.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "D4StreamMarshaller.h"
|
|
Packit |
a4aae4 |
#include "D4StreamUnMarshaller.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "D4RValue.h"
|
|
Packit |
a4aae4 |
#include "D4FilterClause.h" // also contains D4FilterClauseList
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "debug.h"
|
|
Packit |
a4aae4 |
#include "Error.h"
|
|
Packit |
a4aae4 |
#include "InternalErr.h"
|
|
Packit |
a4aae4 |
#include "util.h"
|
|
Packit |
a4aae4 |
#include "escaping.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#undef CLEAR_LOCAL_DATA
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
using namespace std;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
namespace libdap {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
// Keep this stuff around in case we decide to switch back to sentinels
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static const unsigned char end_of_sequence = 0xA5;// binary pattern 1010 0101
|
|
Packit |
a4aae4 |
static const unsigned char start_of_instance = 0x5A;// binary pattern 0101 1010
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static void
|
|
Packit |
a4aae4 |
write_end_of_sequence(Marshaller &m)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
m.put_opaque( (char *)&end_of_sequence, 1 );
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static void
|
|
Packit |
a4aae4 |
write_start_of_instance(Marshaller &m)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
m.put_opaque( (char *)&start_of_instance, 1 );
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static unsigned char
|
|
Packit |
a4aae4 |
read_marker(UnMarshaller &um)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
unsigned char marker;
|
|
Packit |
a4aae4 |
um.get_opaque( (char *)&marker, 1 );
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return marker;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static bool
|
|
Packit |
a4aae4 |
is_start_of_instance(unsigned char marker)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return (marker == start_of_instance);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static bool
|
|
Packit |
a4aae4 |
is_end_of_sequence(unsigned char marker)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return (marker == end_of_sequence);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Private member functions
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// A reminder of these type defs
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// typedef vector<BaseType *> D4SeqRow;
|
|
Packit |
a4aae4 |
// typedef vector<D4SeqRow *> D4SeqValues;
|
|
Packit |
a4aae4 |
// D4SeqValues d_values;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4Sequence::m_duplicate(const D4Sequence &s)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
d_length = s.d_length;
|
|
Packit |
a4aae4 |
#if INDEX_SUBSETTING
|
|
Packit |
a4aae4 |
d_starting_row_number = s.d_starting_row_number;
|
|
Packit |
a4aae4 |
d_ending_row_number = s.d_ending_row_number;
|
|
Packit |
a4aae4 |
d_row_stride = s.d_row_stride;
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
// Deep copy for the values
|
|
Packit |
a4aae4 |
for (D4SeqValues::const_iterator i = s.d_values.begin(), e = s.d_values.end(); i != e; ++i) {
|
|
Packit |
a4aae4 |
D4SeqRow &row = **i;
|
|
Packit |
a4aae4 |
D4SeqRow *dest = new D4SeqRow;
|
|
Packit |
a4aae4 |
for (D4SeqRow::const_iterator j = row.begin(), e = row.end(); j != e; ++j) {
|
|
Packit |
a4aae4 |
// *j is a BaseType*
|
|
Packit |
a4aae4 |
dest->push_back((*j)->ptr_duplicate());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_values.push_back(dest);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_copy_clauses = s.d_copy_clauses;
|
|
Packit |
a4aae4 |
d_clauses = (s.d_clauses != 0) ? new D4FilterClauseList(*s.d_clauses) : 0; // deep copy if != 0
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Public member functions
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** The Sequence constructor requires only the name of the variable
|
|
Packit |
a4aae4 |
to be created. The name may be omitted, which will create a
|
|
Packit |
a4aae4 |
nameless variable. This may be adequate for some applications.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param n A string containing the name of the variable to be
|
|
Packit |
a4aae4 |
created.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief The Sequence constructor. */
|
|
Packit |
a4aae4 |
D4Sequence::D4Sequence(const string &n) :
|
|
Packit |
a4aae4 |
Constructor(n, dods_sequence_c, true /* is dap4 */), d_clauses(0), d_copy_clauses(true), d_length(0)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** The Sequence server-side constructor requires the name of the variable
|
|
Packit |
a4aae4 |
to be created and the dataset name from which this variable is being
|
|
Packit |
a4aae4 |
created.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param n A string containing the name of the variable to be
|
|
Packit |
a4aae4 |
created.
|
|
Packit |
a4aae4 |
@param d A string containing the name of the dataset from which this
|
|
Packit |
a4aae4 |
variable is being created.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief The Sequence server-side constructor. */
|
|
Packit |
a4aae4 |
D4Sequence::D4Sequence(const string &n, const string &d) :
|
|
Packit |
a4aae4 |
Constructor(n, d, dods_sequence_c, true /* is dap4 */), d_clauses(0), d_copy_clauses(true), d_length(0)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief The Sequence copy constructor. */
|
|
Packit |
a4aae4 |
D4Sequence::D4Sequence(const D4Sequence &rhs) : Constructor(rhs)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
m_duplicate(rhs);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *
|
|
Packit |
a4aae4 |
D4Sequence::ptr_duplicate()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return new D4Sequence(*this);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static inline void delete_bt(BaseType *bt_ptr)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
delete bt_ptr;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static inline void delete_rows(D4SeqRow *bt_row_ptr)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
for_each(bt_row_ptr->begin(), bt_row_ptr->end(), delete_bt);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
delete bt_row_ptr;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
D4Sequence::~D4Sequence()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
clear_local_data();
|
|
Packit |
a4aae4 |
delete d_clauses;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4Sequence::clear_local_data()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!d_values.empty()) {
|
|
Packit |
a4aae4 |
for_each(d_values.begin(), d_values.end(), delete_rows);
|
|
Packit |
a4aae4 |
d_values.resize(0);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
set_read_p(false);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
D4Sequence &
|
|
Packit |
a4aae4 |
D4Sequence::operator=(const D4Sequence &rhs)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (this == &rhs) return *this;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dynamic_cast<Constructor &>(*this) = rhs; // run Constructor=
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
m_duplicate(rhs);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return *this;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Read the next instance of the sequence
|
|
Packit |
a4aae4 |
* While the rest of the variables' read() methods are assumed to return the entire
|
|
Packit |
a4aae4 |
* variable in one call (modulo enhancements of the library to support streaming
|
|
Packit |
a4aae4 |
* large variables), this class assumes that the underlying data store is returning
|
|
Packit |
a4aae4 |
* data from a table of unknown size. Thus, D4Sequence::read() is assumed to return
|
|
Packit |
a4aae4 |
* one instance (or element or row) of the sequence per call and return true when the
|
|
Packit |
a4aae4 |
* EOF (end of the sequence) is reached.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* For each call to read, the values for each of the sequence's members
|
|
Packit |
a4aae4 |
* are expected to have been loaded into the member's BaseType variables; this
|
|
Packit |
a4aae4 |
* method will copy them out and store then in the D4Sequence's internal storage.
|
|
Packit |
a4aae4 |
* This method always returns the next instance that satisfies the CE when 'filter'
|
|
Packit |
a4aae4 |
* is true.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @note This method is called by D4Sequence::serialize() and it will evaluate the
|
|
Packit |
a4aae4 |
* CE for each set of values read.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param dmr
|
|
Packit |
a4aae4 |
* @param eval
|
|
Packit |
a4aae4 |
* @param filter
|
|
Packit |
a4aae4 |
* @return False when read() indicates that the EOF was found, true otherwise.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
bool D4Sequence::read_next_instance(bool filter)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
bool eof = false;
|
|
Packit |
a4aae4 |
bool done = false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
do {
|
|
Packit |
a4aae4 |
eof = read();
|
|
Packit |
a4aae4 |
if (eof) { // bail if EOF
|
|
Packit |
a4aae4 |
continue;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// if we are supposed to filter and the clauses eval to true, we're done
|
|
Packit |
a4aae4 |
else if (filter && d_clauses && d_clauses->value()) {
|
|
Packit |
a4aae4 |
d_length++;
|
|
Packit |
a4aae4 |
done = true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// else if we're not supposed to filter or there are no clauses, we're done
|
|
Packit |
a4aae4 |
else if (!filter || !d_clauses) {
|
|
Packit |
a4aae4 |
d_length++;
|
|
Packit |
a4aae4 |
done = true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Set up the next call to get another row's worth of data
|
|
Packit |
a4aae4 |
set_read_p(false);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} while (!eof && !done);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return !eof;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4Sequence::intern_data()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
read_sequence_values(true);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
// Read the data values, then serialize.
|
|
Packit |
a4aae4 |
while (read_next_instance(true /*filter*/)) {
|
|
Packit |
a4aae4 |
D4SeqRow *row = new D4SeqRow;
|
|
Packit |
a4aae4 |
for (Vars_iter i = d_vars.begin(), e = d_vars.end(); i != e; i++) {
|
|
Packit |
a4aae4 |
if ((*i)->send_p()) {
|
|
Packit |
a4aae4 |
// store the variable's value.
|
|
Packit |
a4aae4 |
row->push_back((*i)->ptr_duplicate());
|
|
Packit |
a4aae4 |
// the copy should have read_p true to prevent the serialize() call
|
|
Packit |
a4aae4 |
// below in the nested for loops from triggering a second call to
|
|
Packit |
a4aae4 |
// read().
|
|
Packit |
a4aae4 |
row->back()->set_read_p(true);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
d_values.push_back(row);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
set_length(d_values.size());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Read a Sequence's value into memory
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* This is a helper method for serialize() that enables the code
|
|
Packit |
a4aae4 |
* to recursively read values for child sequences. This method assumes
|
|
Packit |
a4aae4 |
* that the D4Sequence::read() method does not call itself recursively
|
|
Packit |
a4aae4 |
* for child sequences, as is the case with DAP2 sequences. If you
|
|
Packit |
a4aae4 |
* have a data store that requires the outer-most sequence to read
|
|
Packit |
a4aae4 |
* values for its child sequences, you will need to specialize this
|
|
Packit |
a4aae4 |
* method. See also the methods associated with the sequence values
|
|
Packit |
a4aae4 |
* because unlike DAP2 sequences, in DAP4 the sequences hold all their
|
|
Packit |
a4aae4 |
* values in memory before writing them out.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @note We may revisit the idea that values must be held in memory
|
|
Packit |
a4aae4 |
* before being written. That is a consequence of using a length prefix
|
|
Packit |
a4aae4 |
* instead of a series of sentinel values.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param filter True if the/a file expression bound to this sequence
|
|
Packit |
a4aae4 |
* should be evaluated.
|
|
Packit |
a4aae4 |
* @see set_value()
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4Sequence::read_sequence_values(bool filter)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << __PRETTY_FUNCTION__ << " BEGIN" << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (read_p()) return;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Read the data values, then serialize. NB: read_next_instance sets d_length
|
|
Packit |
a4aae4 |
// evaluates the filter expression
|
|
Packit |
a4aae4 |
while (read_next_instance(filter)) {
|
|
Packit |
a4aae4 |
DBG(cerr << "read_sequence_values() - Adding row" << endl);
|
|
Packit |
a4aae4 |
D4SeqRow* row = new D4SeqRow;
|
|
Packit |
a4aae4 |
for (Vars_iter i = d_vars.begin(), e = d_vars.end(); i != e; i++) {
|
|
Packit |
a4aae4 |
if ((*i)->send_p()) {
|
|
Packit |
a4aae4 |
DBG(cerr << ":serialize() - reading data for " << (*i)->type_name() << " " << (*i)->name() << endl);
|
|
Packit |
a4aae4 |
if ((*i)->type() == dods_sequence_c) {
|
|
Packit |
a4aae4 |
DBG(cerr << "Reading child sequence values for " << (*i)->name() << endl);
|
|
Packit |
a4aae4 |
D4Sequence *d4s = static_cast<D4Sequence*>(*i);
|
|
Packit |
a4aae4 |
d4s->read_sequence_values(filter);
|
|
Packit |
a4aae4 |
d4s->d_copy_clauses = false;
|
|
Packit |
a4aae4 |
row->push_back(d4s->ptr_duplicate());
|
|
Packit |
a4aae4 |
d4s->d_copy_clauses = true; // Must be sure to not break the object in general
|
|
Packit |
a4aae4 |
row->back()->set_read_p(true);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
// store the variable's value.
|
|
Packit |
a4aae4 |
row->push_back((*i)->ptr_duplicate());
|
|
Packit |
a4aae4 |
// the copy should have read_p true to prevent the serialize() call
|
|
Packit |
a4aae4 |
// below in the nested for loops from triggering a second call to
|
|
Packit |
a4aae4 |
// read().
|
|
Packit |
a4aae4 |
row->back()->set_read_p(true);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// When specializing this, use set_value()
|
|
Packit |
a4aae4 |
d_values.push_back(row);
|
|
Packit |
a4aae4 |
DBG(cerr << " read_sequence_values() - Row completed" << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
set_length(d_values.size());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBGN(cerr << __PRETTY_FUNCTION__ << " END added " << d_values.size() << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Serialize the values of a D4Sequence
|
|
Packit |
a4aae4 |
* This method assumes that the underlying data store cannot/does not return a count
|
|
Packit |
a4aae4 |
* of items separately from the items themselves. For a data store that does, this
|
|
Packit |
a4aae4 |
* method should probably be specialized to take advantage of that. Because the DAP4
|
|
Packit |
a4aae4 |
* spec requires that a sequence be prefixed by a count, this method reads the entire
|
|
Packit |
a4aae4 |
* sequence into memory before sending it (and counts the number of elements in the
|
|
Packit |
a4aae4 |
* the process). For a data store where the count is available a priori, this could
|
|
Packit |
a4aae4 |
* be rewritten so that the count is sent and then each instance/element of the sequence
|
|
Packit |
a4aae4 |
* sent in succession.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* If this method is specialized, once the data are loaded into the D4SeqValues instance,
|
|
Packit |
a4aae4 |
* make sure to set d_length and make sure to set_read_p for each BaseType in D4SeqValues.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param m Stream data sink
|
|
Packit |
a4aae4 |
* @param dmr DMR object for the evaluator
|
|
Packit |
a4aae4 |
* @param eval CE Evaluator object
|
|
Packit |
a4aae4 |
* @param filter True if the CE should be evaluated, false otherwise.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4Sequence::serialize(D4StreamMarshaller &m, DMR &dmr, bool filter)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBGN(cerr << __PRETTY_FUNCTION__ << " BEGIN" << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Read the data values, then serialize. NB: read_next_instance sets d_length
|
|
Packit |
a4aae4 |
// evaluates the filter expression
|
|
Packit |
a4aae4 |
read_sequence_values(filter);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// write D4Sequecne::length(); don't include the length in the checksum
|
|
Packit |
a4aae4 |
m.put_count(d_length);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// By this point the d_values object holds all and only the values to be sent;
|
|
Packit |
a4aae4 |
// use the serialize methods to send them (but no need to test send_p).
|
|
Packit |
a4aae4 |
for (D4SeqValues::iterator i = d_values.begin(), e = d_values.end(); i != e; ++i) {
|
|
Packit |
a4aae4 |
for (D4SeqRow::iterator j = (*i)->begin(), f = (*i)->end(); j != f; ++j) {
|
|
Packit |
a4aae4 |
(*j)->serialize(m, dmr, /*eval,*/false);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBGN(cerr << __PRETTY_FUNCTION__ << " END" << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4Sequence::deserialize(D4StreamUnMarshaller &um, DMR &dmr)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
int64_t um_count = um.get_count();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
set_length(um_count);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for (int64_t i = 0; i < d_length; ++i) {
|
|
Packit |
a4aae4 |
D4SeqRow *row = new D4SeqRow;
|
|
Packit |
a4aae4 |
for (Vars_iter i = d_vars.begin(), e = d_vars.end(); i != e; ++i) {
|
|
Packit |
a4aae4 |
(*i)->deserialize(um, dmr);
|
|
Packit |
a4aae4 |
row->push_back((*i)->ptr_duplicate());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
d_values.push_back(row);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Access the filter clauses for this D4Sequence
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* When a filter is supplied with a DAP4 constraint, the expression is
|
|
Packit |
a4aae4 |
* parsed and one or more D4FilterClause objects are built and stored in
|
|
Packit |
a4aae4 |
* a D4FilterClauseList bound to the D4Sequence to be filtered.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @return A reference to this D4Sequence's filter clause list
|
|
Packit |
a4aae4 |
* @see D4FilterClauseList
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
D4FilterClauseList & D4Sequence::clauses()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!d_clauses) d_clauses = new D4FilterClauseList();
|
|
Packit |
a4aae4 |
return *d_clauses;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#if INDEX_SUBSETTING
|
|
Packit |
a4aae4 |
/** Set the start, stop and stride for a row-number type constraint.
|
|
Packit |
a4aae4 |
This should be used only when the sequence is constrained using the
|
|
Packit |
a4aae4 |
bracket notation (which supplies start, stride and stop information).
|
|
Packit |
a4aae4 |
If omitted, the stride defaults to 1.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param start The starting row number. The first row is row zero.
|
|
Packit |
a4aae4 |
@param stop The ending row number. The 20th row is row 19.
|
|
Packit |
a4aae4 |
@param stride The stride. A stride of two skips every other row. */
|
|
Packit |
a4aae4 |
virtual void set_row_number_constraint(int start, int stop, int stride)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (stop < start)
|
|
Packit |
a4aae4 |
throw Error(malformed_expr, "Starting row number must precede the ending row number.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_starting_row_number = start;
|
|
Packit |
a4aae4 |
d_row_stride = stride;
|
|
Packit |
a4aae4 |
d_ending_row_number = stop;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Get a whole row from the sequence.
|
|
Packit |
a4aae4 |
@param row Get row number row from the sequence.
|
|
Packit |
a4aae4 |
@return A BaseTypeRow object (vector<BaseType *>). Null if there's no such
|
|
Packit |
a4aae4 |
row number as \e row. */
|
|
Packit |
a4aae4 |
D4SeqRow *
|
|
Packit |
a4aae4 |
D4Sequence::row_value(size_t row)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (row >= d_values.size()) return 0;
|
|
Packit |
a4aae4 |
return d_values[row];
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static bool base_type_name_eq(BaseType *btp, const string name)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return btp->name() == name;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Get the BaseType pointer to the named variable of a given row.
|
|
Packit |
a4aae4 |
@param row Read from row in the sequence.
|
|
Packit |
a4aae4 |
@param name Return name from row.
|
|
Packit |
a4aae4 |
@return A BaseType which holds the variable and its value.
|
|
Packit |
a4aae4 |
@see number_of_rows */
|
|
Packit |
a4aae4 |
BaseType *
|
|
Packit |
a4aae4 |
D4Sequence::var_value(size_t row_num, const string &name)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
D4SeqRow *row = row_value(row_num);
|
|
Packit |
a4aae4 |
if (!row) return 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
D4SeqRow::iterator elem = find_if(row->begin(), row->end(), bind2nd(ptr_fun(base_type_name_eq), name));
|
|
Packit |
a4aae4 |
return (elem != row->end()) ? *elem : 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Get the BaseType pointer to the $i^{th}$ variable of row.
|
|
Packit |
a4aae4 |
@param row Read from row in the sequence.
|
|
Packit |
a4aae4 |
@param i Return the $i^{th}$ variable from row.
|
|
Packit |
a4aae4 |
@return A BaseType which holds the variable and its value.
|
|
Packit |
a4aae4 |
@see number_of_rows */
|
|
Packit |
a4aae4 |
BaseType *
|
|
Packit |
a4aae4 |
D4Sequence::var_value(size_t row_num, size_t i)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
D4SeqRow *row = row_value(row_num);
|
|
Packit |
a4aae4 |
if (!row) return 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (i >= row->size()) return 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return (*row)[i];
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4Sequence::print_one_row(ostream &out, int row, string space, bool print_row_num)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (print_row_num) out << "\n" << space << row << ": ";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << "{ ";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int elements = element_count();
|
|
Packit |
a4aae4 |
int j = 0;
|
|
Packit |
a4aae4 |
BaseType *bt_ptr = 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This version of print_one_row() works for both data read with
|
|
Packit |
a4aae4 |
// deserialize(), where each variable is assumed to have valid data, and
|
|
Packit |
a4aae4 |
// intern_data(), where some/many variables do not. Because of that, it's
|
|
Packit |
a4aae4 |
// not correct to assume that all of the elements will be printed, which
|
|
Packit |
a4aae4 |
// is what the old code did.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Print the first value
|
|
Packit |
a4aae4 |
while (j < elements && !bt_ptr) {
|
|
Packit |
a4aae4 |
bt_ptr = var_value(row, j++);
|
|
Packit |
a4aae4 |
if (bt_ptr) { // data
|
|
Packit |
a4aae4 |
if (bt_ptr->type() == dods_sequence_c) static_cast<D4Sequence*>(bt_ptr)->print_val_by_rows(out,
|
|
Packit |
a4aae4 |
space + " ", false, print_row_num);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
bt_ptr->print_val(out, space, false);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Print the remaining values
|
|
Packit |
a4aae4 |
while (j < elements) {
|
|
Packit |
a4aae4 |
bt_ptr = var_value(row, j++);
|
|
Packit |
a4aae4 |
if (bt_ptr) { // data
|
|
Packit |
a4aae4 |
out << ", ";
|
|
Packit |
a4aae4 |
if (bt_ptr->type() == dods_sequence_c) static_cast<D4Sequence*>(bt_ptr)->print_val_by_rows(out,
|
|
Packit |
a4aae4 |
space + " ", false, print_row_num);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
bt_ptr->print_val(out, space, false);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << " }";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4Sequence::print_val_by_rows(ostream &out, string space, bool print_decl_p, bool print_row_numbers)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (print_decl_p) {
|
|
Packit |
a4aae4 |
print_decl(out, space, false);
|
|
Packit |
a4aae4 |
out << " = ";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << "{ ";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (length() != 0) {
|
|
Packit |
a4aae4 |
int rows = length() - 1; // -1 because the last row is treated specially
|
|
Packit |
a4aae4 |
for (int i = 0; i < rows; ++i) {
|
|
Packit |
a4aae4 |
print_one_row(out, i, space, print_row_numbers);
|
|
Packit |
a4aae4 |
out << ", ";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
print_one_row(out, rows, space, print_row_numbers);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << " }";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (print_decl_p) out << ";\n";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4Sequence::print_val(ostream &out, string space, bool print_decl_p)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << name() << " isa " << type_name() << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
print_val_by_rows(out, space, print_decl_p, false);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief dumps information about this object
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* Displays the pointer value of this instance and information about this
|
|
Packit |
a4aae4 |
* instance.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param strm C++ i/o stream to dump the information to
|
|
Packit |
a4aae4 |
* @return void
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4Sequence::dump(ostream &strm) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "Sequence::dump - (" << (void *) this << ")" << endl;
|
|
Packit |
a4aae4 |
DapIndent::Indent();
|
|
Packit |
a4aae4 |
Constructor::dump(strm);
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "# rows deserialized: " << d_length << endl;
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "bracket notation information:" << endl;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DapIndent::Indent();
|
|
Packit |
a4aae4 |
#if INDEX_SUBSETTING
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "starting row #: " << d_starting_row_number << endl;
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "row stride: " << d_row_stride << endl;
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "ending row #: " << d_ending_row_number << endl;
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
DapIndent::UnIndent();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DapIndent::UnIndent();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // namespace libdap
|
|
Packit |
a4aae4 |
|