Blame D4Sequence.cc

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