Blame Sequence.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) 2002,2003 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit a4aae4
//
Packit a4aae4
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
Packit a4aae4
Packit a4aae4
// (c) COPYRIGHT URI/MIT 1994-1999
Packit a4aae4
// Please read the full copyright statement in the file COPYRIGHT_URI.
Packit a4aae4
//
Packit a4aae4
// Authors:
Packit a4aae4
//      jhrg,jimg       James Gallagher <jgallagher@gso.uri.edu>
Packit a4aae4
Packit a4aae4
// Implementation for the class Structure
Packit a4aae4
//
Packit a4aae4
// jhrg 9/14/94
Packit a4aae4
Packit a4aae4
#include "config.h"
Packit a4aae4
Packit a4aae4
//#define DODS_DEBUG
Packit a4aae4
//#define DODS_DEBUG2
Packit a4aae4
Packit a4aae4
#include <algorithm>
Packit a4aae4
#include <string>
Packit a4aae4
#include <sstream>
Packit a4aae4
Packit a4aae4
#include "Byte.h"
Packit a4aae4
#include "Int16.h"
Packit a4aae4
#include "UInt16.h"
Packit a4aae4
#include "Int32.h"
Packit a4aae4
#include "UInt32.h"
Packit a4aae4
#include "Float32.h"
Packit a4aae4
#include "Float64.h"
Packit a4aae4
#include "Str.h"
Packit a4aae4
#include "Url.h"
Packit a4aae4
#include "Array.h"
Packit a4aae4
#include "Structure.h"
Packit a4aae4
#include "Sequence.h"
Packit a4aae4
#include "Grid.h"
Packit a4aae4
Packit a4aae4
#include "Marshaller.h"
Packit a4aae4
#include "UnMarshaller.h"
Packit a4aae4
Packit a4aae4
#include "debug.h"
Packit a4aae4
#include "Error.h"
Packit a4aae4
#include "InternalErr.h"
Packit a4aae4
#include "Sequence.h"
Packit a4aae4
#include "DDS.h"
Packit a4aae4
#include "DataDDS.h"
Packit a4aae4
#include "util.h"
Packit a4aae4
#include "InternalErr.h"
Packit a4aae4
#include "escaping.h"
Packit a4aae4
Packit a4aae4
#include "D4Attributes.h"
Packit a4aae4
#include "D4Sequence.h"
Packit a4aae4
#include "D4Group.h"
Packit a4aae4
#include "Constructor.h"
Packit a4aae4
#include "DMR.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
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
// Private member functions
Packit a4aae4
Packit a4aae4
void Sequence::m_duplicate(const Sequence &s)
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "In Sequence::m_duplicate" << endl);
Packit a4aae4
Packit a4aae4
    d_row_number = s.d_row_number;
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
    d_leaf_sequence = s.d_leaf_sequence;
Packit a4aae4
    d_unsent_data = s.d_unsent_data;
Packit a4aae4
    d_wrote_soi = s.d_wrote_soi;
Packit a4aae4
    d_top_most = s.d_top_most;
Packit a4aae4
Packit a4aae4
    Sequence &cs = const_cast<Sequence &>(s);
Packit a4aae4
Packit a4aae4
    // Copy the BaseType objects used to hold values.
Packit a4aae4
    for (vector<BaseTypeRow *>::iterator rows_iter = cs.d_values.begin(); rows_iter != cs.d_values.end(); rows_iter++) {
Packit a4aae4
        // Get the current BaseType Row
Packit a4aae4
        BaseTypeRow *src_bt_row_ptr = *rows_iter;
Packit a4aae4
        // Create a new row.
Packit a4aae4
        BaseTypeRow *dest_bt_row_ptr = new BaseTypeRow;
Packit a4aae4
        // Copy the BaseType objects from a row to new BaseType objects.
Packit a4aae4
        // Push new BaseType objects onto new row.
Packit a4aae4
        for (BaseTypeRow::iterator bt_row_iter = src_bt_row_ptr->begin(); bt_row_iter != src_bt_row_ptr->end();
Packit a4aae4
                bt_row_iter++) {
Packit a4aae4
            BaseType *src_bt_ptr = *bt_row_iter;
Packit a4aae4
            BaseType *dest_bt_ptr = src_bt_ptr->ptr_duplicate();
Packit a4aae4
            dest_bt_row_ptr->push_back(dest_bt_ptr);
Packit a4aae4
        }
Packit a4aae4
        // Push new row onto d_values.
Packit a4aae4
        d_values.push_back(dest_bt_row_ptr);
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
static void 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 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 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 is_start_of_instance(unsigned char marker)
Packit a4aae4
{
Packit a4aae4
    return (marker == start_of_instance);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
static bool is_end_of_sequence(unsigned char marker)
Packit a4aae4
{
Packit a4aae4
    return (marker == end_of_sequence);
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
Sequence::Sequence(const string &n) :
Packit a4aae4
        Constructor(n, dods_sequence_c), d_row_number(-1), d_starting_row_number(-1), d_row_stride(1), d_ending_row_number(
Packit a4aae4
                -1), d_unsent_data(false), d_wrote_soi(false), d_leaf_sequence(false), d_top_most(false)
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
Sequence::Sequence(const string &n, const string &d) :
Packit a4aae4
		Constructor(n, d, dods_sequence_c), d_row_number(-1), d_starting_row_number(-1),
Packit a4aae4
		d_row_stride(1), d_ending_row_number(-1), d_unsent_data(false),
Packit a4aae4
		d_wrote_soi(false), d_leaf_sequence(false), d_top_most(false)
Packit a4aae4
{
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief The Sequence copy constructor. */
Packit a4aae4
Sequence::Sequence(const Sequence &rhs) :
Packit a4aae4
        Constructor(rhs)
Packit a4aae4
{
Packit a4aae4
    m_duplicate(rhs);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
BaseType *
Packit a4aae4
Sequence::ptr_duplicate()
Packit a4aae4
{
Packit a4aae4
    return new Sequence(*this);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * Build a D4Sequence from a DAP2 Sequence.
Packit a4aae4
 *
Packit a4aae4
 * Because DAP4 uses a different type for sequences, this code must
Packit a4aae4
 * be subclassed by anything other than trivial test code or client
Packit a4aae4
 * side-only uses of the library.
Packit a4aae4
 *
Packit a4aae4
 * @note This version of transformto_dap4() builds a new type of object,
Packit a4aae4
 * so it must be subclassed.
Packit a4aae4
 *
Packit a4aae4
 * @param root Use this as the environment for D4Dimensions
Packit a4aae4
 * @param container Load the result into this container
Packit a4aae4
 * @return The new D4Sequence
Packit a4aae4
 */
Packit a4aae4
void
Packit a4aae4
Sequence::transform_to_dap4(D4Group *root, Constructor *container)
Packit a4aae4
{
Packit a4aae4
    D4Sequence *dest;
Packit a4aae4
    // If it's already a DAP4 object then we can just return it!
Packit a4aae4
    if(is_dap4()){
Packit a4aae4
        dest = static_cast<D4Sequence*>(ptr_duplicate());
Packit a4aae4
        dest->set_length(-1);
Packit a4aae4
        container->add_var_nocopy(dest);
Packit a4aae4
        return;
Packit a4aae4
    }
Packit a4aae4
    dest = new D4Sequence(name());
Packit a4aae4
    Constructor::transform_to_dap4(root, dest);
Packit a4aae4
    dest->set_length(-1);
Packit a4aae4
    container->add_var_nocopy(dest);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
static inline void delete_bt(BaseType *bt_ptr)
Packit a4aae4
{
Packit a4aae4
    delete bt_ptr;
Packit a4aae4
    bt_ptr = 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
static inline void delete_rows(BaseTypeRow *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
    bt_row_ptr = 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
Sequence::~Sequence()
Packit a4aae4
{
Packit a4aae4
    clear_local_data();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void Sequence::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
Sequence &
Packit a4aae4
Sequence::operator=(const Sequence &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
 * The Sequence class will be streamlined for DAP4.
Packit a4aae4
 */
Packit a4aae4
bool Sequence::is_dap2_only_type()
Packit a4aae4
{
Packit a4aae4
    return true;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
string Sequence::toString()
Packit a4aae4
{
Packit a4aae4
    ostringstream oss;
Packit a4aae4
Packit a4aae4
    oss << BaseType::toString();
Packit a4aae4
Packit a4aae4
    for (Vars_iter i = d_vars.begin(); i != d_vars.end(); i++) {
Packit a4aae4
        oss << (*i)->toString();
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    oss << endl;
Packit a4aae4
Packit a4aae4
    return oss.str();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
bool Sequence::is_linear()
Packit a4aae4
{
Packit a4aae4
    bool linear = true;
Packit a4aae4
    bool seq_found = false;
Packit a4aae4
    for (Vars_iter iter = d_vars.begin(); linear && iter != d_vars.end(); iter++) {
Packit a4aae4
        if ((*iter)->type() == dods_sequence_c) {
Packit a4aae4
            // A linear sequence cannot have more than one child seq. at any
Packit a4aae4
            // one level. If we've already found a seq at this level, return
Packit a4aae4
            // false.
Packit a4aae4
            if (seq_found) {
Packit a4aae4
                linear = false;
Packit a4aae4
                break;
Packit a4aae4
            }
Packit a4aae4
            seq_found = true;
Packit a4aae4
            linear = static_cast<Sequence *>((*iter))->is_linear();
Packit a4aae4
        }
Packit a4aae4
        else if ((*iter)->type() == dods_structure_c) {
Packit a4aae4
            linear = static_cast<Structure*>((*iter))->is_linear();
Packit a4aae4
        }
Packit a4aae4
        else {
Packit a4aae4
            // A linear sequence cannot have Arrays, Lists or Grids.
Packit a4aae4
            linear = (*iter)->is_simple_type();
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    return linear;
Packit a4aae4
}
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
BaseTypeRow *
Packit a4aae4
Sequence::row_value(size_t row)
Packit a4aae4
{
Packit a4aae4
    if (row >= d_values.size()) return 0;   //nullptr
Packit a4aae4
    return d_values[row];
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Set value of this Sequence. This does not perform a deep copy, so data
Packit a4aae4
 should be allocated on the heap and freed only when the Sequence dtor is
Packit a4aae4
 called.
Packit a4aae4
 @see SequenceValues
Packit a4aae4
 @see BaseTypeRow
Packit a4aae4
 @param values Set the value of this Sequence. */
Packit a4aae4
void Sequence::set_value(SequenceValues &values)
Packit a4aae4
{
Packit a4aae4
    d_values = values;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Get the value for this sequence.
Packit a4aae4
 @return The SequenceValues object for this Sequence. */
Packit a4aae4
SequenceValues Sequence::value()
Packit a4aae4
{
Packit a4aae4
    return d_values;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Get the value for this sequence.
Packit a4aae4
 @return The SequenceValues object for this Sequence. */
Packit a4aae4
SequenceValues &
Packit a4aae4
Sequence::value_ref()
Packit a4aae4
{
Packit a4aae4
    return d_values;
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
Sequence::var_value(size_t row, const string &name)
Packit a4aae4
{
Packit a4aae4
    BaseTypeRow *bt_row_ptr = row_value(row);
Packit a4aae4
    if (!bt_row_ptr) return 0;
Packit a4aae4
Packit a4aae4
    BaseTypeRow::iterator bt_row_iter = bt_row_ptr->begin();
Packit a4aae4
    BaseTypeRow::iterator bt_row_end = bt_row_ptr->end();
Packit a4aae4
    while (bt_row_iter != bt_row_end && (*bt_row_iter)->name() != name)
Packit a4aae4
        ++bt_row_iter;
Packit a4aae4
Packit a4aae4
    if (bt_row_iter == bt_row_end)
Packit a4aae4
        return 0;
Packit a4aae4
    else
Packit a4aae4
        return *bt_row_iter;
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
Sequence::var_value(size_t row, size_t i)
Packit a4aae4
{
Packit a4aae4
    BaseTypeRow *bt_row_ptr = row_value(row);
Packit a4aae4
    if (!bt_row_ptr) return 0;
Packit a4aae4
Packit a4aae4
    if (i >= bt_row_ptr->size()) return 0;
Packit a4aae4
Packit a4aae4
    return (*bt_row_ptr)[i];
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// This version returns -1. Each API-specific subclass should define a more
Packit a4aae4
// reasonable version. jhrg 5/24/96
Packit a4aae4
Packit a4aae4
/** Returns the number of elements in a Sequence object. Note that
Packit a4aae4
 this is not the number of items in a row, but the number
Packit a4aae4
 of rows in the complete sequence object. To be meaningful, this
Packit a4aae4
 must be computed after constraint expression (CE) evaluation.
Packit a4aae4
 The purpose of this function is to facilitate translations
Packit a4aae4
 between Sequence objects and Array objects, particularly when
Packit a4aae4
 the Sequence is too large to be transferred from the server to
Packit a4aae4
 the client in its entirety.
Packit a4aae4
Packit a4aae4
 This function, to be useful, must be specialized for the API and
Packit a4aae4
 data format in use.
Packit a4aae4
Packit a4aae4
 @return The base implementation returns -1, indicating that the
Packit a4aae4
 length is not known.  Sub-classes specific to a particular API
Packit a4aae4
 will have a more complete implementation. */
Packit a4aae4
int Sequence::length() const
Packit a4aae4
{
Packit a4aae4
    return -1;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Hmmm. how is this different from length()?
Packit a4aae4
int Sequence::number_of_rows() const
Packit a4aae4
{
Packit a4aae4
    return d_values.size();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** When reading a nested sequence, use this method to reset the internal
Packit a4aae4
 row number counter. This is necessary so that the second, ... instances
Packit a4aae4
 of the inner/nested sequence will start off reading row zero. */
Packit a4aae4
void Sequence::reset_row_number()
Packit a4aae4
{
Packit a4aae4
    d_row_number = -1;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/**
Packit a4aae4
 * @brief A recursive version of reset_row_number()
Packit a4aae4
 *
Packit a4aae4
 * @param recur If true, reset the row number of child sequences as well
Packit a4aae4
 */
Packit a4aae4
void Sequence::reset_row_number(bool recur)
Packit a4aae4
{
Packit a4aae4
    reset_row_number();
Packit a4aae4
Packit a4aae4
    if (recur)
Packit a4aae4
        for (Vars_iter i = var_begin(), e = var_end(); i != e; ++i)
Packit a4aae4
            if ((*i)->type() == dods_sequence_c)
Packit a4aae4
                reset_row_number(true);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Notes:
Packit a4aae4
// Assume that read() is implemented so that, when reading data for a nested
Packit a4aae4
// sequence, only the outer most level is *actually* read.
Packit a4aae4
// This is a consequence of our current (12/7/99) implementation of
Packit a4aae4
// the JGOFS server (which is the only server to actually use nested
Packit a4aae4
// sequences). 12/7/99 jhrg
Packit a4aae4
//
Packit a4aae4
// Stop assuming this. This logic is being moved into the JGOFS server
Packit a4aae4
// itself. 6/1/2001 jhrg
Packit a4aae4
Packit a4aae4
// The read() function returns a boolean value, with TRUE
Packit a4aae4
// indicating that read() should be called again because there's
Packit a4aae4
// more data to read, and FALSE indicating there's no more data
Packit a4aae4
// to read. Note that this behavior is necessary to properly
Packit a4aae4
// handle variables that contain Sequences. Jose Garcia If an
Packit a4aae4
// error exists while reading, the implementers of the surrogate
Packit a4aae4
// library SHOULD throw an Error object which will propagate
Packit a4aae4
// beyond this point to to the original caller.
Packit a4aae4
// Jose Garcia
Packit a4aae4
Packit a4aae4
/** Read row number row of the Sequence. The values of the row
Packit a4aae4
 are obtained by calling the read() method of the sequence. The
Packit a4aae4
 current \e row just read is stored in the Sequence instance
Packit a4aae4
 along with its row number. If a selection expression has been
Packit a4aae4
 supplied, rows are counted only if they satisfy that expression.
Packit a4aae4
Packit a4aae4
 Note that we can only advance in a Sequence. It is not possible to back up
Packit a4aae4
 and read a row numbered lower than the current row. If you need that
Packit a4aae4
 you will need to replace the serialize() method with one of your own.
Packit a4aae4
Packit a4aae4
 Used on the server side.
Packit a4aae4
Packit a4aae4
 @note The first row is row number zero. A Sequence with 100 rows will
Packit a4aae4
 have row numbers 0 to 99.
Packit a4aae4
Packit a4aae4
 @todo This code ignores the main reason for nesting the sequences, that
Packit a4aae4
 if the outer Sequence's current instance fails the CE, there's no need to
Packit a4aae4
 look at the values of the inner Sequence. But in the code that calls this
Packit a4aae4
 method (serialize() and intern_data()) the CE is not evaluated until the
Packit a4aae4
 inner-most Sequence (i.e., the leaf Sequence) is read. That means that
Packit a4aae4
 each instance of the inner Sequence is read and the CE evaluated for each
Packit a4aae4
 of those reads. To fix this, and the overall problem of complexity here,
Packit a4aae4
 we need to re-think Sequences and how they behave. 11/13/2007 jhrg
Packit a4aae4
Packit a4aae4
 @return A boolean value, with TRUE indicating that read_row
Packit a4aae4
 should be called again because there's more data to be read.
Packit a4aae4
 FALSE indicates the end of the Sequence.
Packit a4aae4
 @param row The row number to read.
Packit a4aae4
 @param dds A reference to the DDS for this dataset.
Packit a4aae4
 @param eval Use this as the constraint expression evaluator.
Packit a4aae4
 @param ce_eval If True, evaluate any CE, otherwise do not.
Packit a4aae4
 */
Packit a4aae4
bool Sequence::read_row(int row, DDS &dds, ConstraintEvaluator &eval, bool ce_eval)
Packit a4aae4
{
Packit a4aae4
    DBG2(cerr << "Entering Sequence::read_row for " << name() << ", row number " << row << ", current row " << d_row_number << endl);
Packit a4aae4
    if (row < d_row_number) throw InternalErr("Trying to back up inside a sequence!");
Packit a4aae4
Packit a4aae4
    if (row == d_row_number) {
Packit a4aae4
        DBG2(cerr << "Leaving Sequence::read_row for " << name() << endl);
Packit a4aae4
        return false;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    bool eof = false;  // Start out assuming EOF is false.
Packit a4aae4
    while (!eof && d_row_number < row) {
Packit a4aae4
        if (!read_p()) {
Packit a4aae4
            // jhrg original version from 10/9/13 : eof = (read() == false);
Packit a4aae4
            eof = read();
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
        // Advance the row number if ce_eval is false (we're not supposed to
Packit a4aae4
        // evaluate the selection) or both ce_eval and the selection are
Packit a4aae4
        // true.
Packit a4aae4
        if (!eof && (!ce_eval || eval.eval_selection(dds, dataset()))) d_row_number++;
Packit a4aae4
Packit a4aae4
        set_read_p(false); // ...so that the next instance will be read
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    // Once we finish the above loop, set read_p to true so that the caller
Packit a4aae4
    // knows that data *has* been read. This is how the read() methods of the
Packit a4aae4
    // elements of the sequence know to not call read() but instead look for
Packit a4aae4
    // data values inside themselves.
Packit a4aae4
    set_read_p(true);
Packit a4aae4
Packit a4aae4
    // Return true if we have valid data, false if we've read to the EOF.
Packit a4aae4
    DBG2(cerr << "Leaving Sequence::read_row for " << name() << " with eof: " << eof << endl);
Packit a4aae4
    return !eof; // jhrg 10/10/13 was: eof == 0;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Private. This is used to process constraints on the rows of a sequence.
Packit a4aae4
// Starting with 3.2 we support constraints like Sequence[10:2:20]. This
Packit a4aae4
// odd-looking logic first checks if d_ending_row_number is the sentinel
Packit a4aae4
// value of -1. If so, the sequence was not constrained by row number and
Packit a4aae4
// this method should never return true (which indicates that we're at the
Packit a4aae4
// end of a row-number constraint). If d_ending_row_number is not -1, then is
Packit a4aae4
// \e i at the end point? 6/1/2001 jhrg
Packit a4aae4
inline bool Sequence::is_end_of_rows(int i)
Packit a4aae4
{
Packit a4aae4
    return ((d_ending_row_number == -1) ? false : (i > d_ending_row_number));
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Serialize a Sequence.
Packit a4aae4
Packit a4aae4
 Leaf Sequences must be marked as such (see DDS::tag_nested_sequence()),
Packit a4aae4
 as must the top most Sequence.
Packit a4aae4
Packit a4aae4
 How the code works. Methods called for various functions are named in
Packit a4aae4
 brackets:
Packit a4aae4
 
    Packit a4aae4
     
  1. Sending a one-level sequence:
  2. Packit a4aae4
     
    Packit a4aae4
     Dataset {
    Packit a4aae4
         Sequence {
    Packit a4aae4
             Int x;
    Packit a4aae4
             Int y;
    Packit a4aae4
         } flat;
    Packit a4aae4
     } case_1;
    Packit a4aae4
     
    Packit a4aae4
    Packit a4aae4
     Serialize case_1 by reading successive rows and sending all of those that
    Packit a4aae4
     satisfy the CE. Before each row, send a start of instance (SOI) marker.
    Packit a4aae4
     Once all rows have been sent, send an End of Sequence (EOS)
    Packit a4aae4
     marker.[serialize_leaf].
    Packit a4aae4
    Packit a4aae4
     
  3. Sending a nested sequence:
  4. Packit a4aae4
     
    Packit a4aae4
     Dataset {
    Packit a4aae4
         Sequence {
    Packit a4aae4
             Int t;
    Packit a4aae4
             Sequence {
    Packit a4aae4
                 Int z;
    Packit a4aae4
             } inner;
    Packit a4aae4
         } outer;
    Packit a4aae4
     } case_2;
    Packit a4aae4
     
    Packit a4aae4
    Packit a4aae4
     Serialize case_2 by reading the first row of outer and storing the values. Do
    Packit a4aae4
     not evaluate the CE [serialize_parent_part_one]. Call serialize() for inner
    Packit a4aae4
     and read each row for it, evaluating the CE for each row that is read.
    Packit a4aae4
     After the first row of inner is read and satisfies the CE, write out the
    Packit a4aae4
     SOI marker and values for outer [serialize_parent_part_two], then write
    Packit a4aae4
     the SOI and values for the first row of inner. Continue to read and send
    Packit a4aae4
     rows of inner until the last row has been read. Send EOS for inner
    Packit a4aae4
     [serialize_leaf]. Now read the next row of outer and repeat. Once outer
    Packit a4aae4
     is completely read, send its EOS marker.
    Packit a4aae4
     
    Packit a4aae4
    Packit a4aae4
     Notes:
    Packit a4aae4
     
      Packit a4aae4
       
    1. For a nested Sequence, the child sequence must follow all other types
    2. Packit a4aae4
       in the parent sequence (like the example). There may be only one nested
      Packit a4aae4
       Sequence per level.
      Packit a4aae4
      Packit a4aae4
       
    3. CE evaluation happens only in a leaf sequence.
    4. Packit a4aae4
      Packit a4aae4
       
    5. When no data satisfies a CE, the empty Sequence is signaled by a
    6. Packit a4aae4
       single EOS marker, regardless of the level of nesting of Sequences. That
      Packit a4aae4
       is, the EOS marker is sent for only the outer Sequence in the case of a
      Packit a4aae4
       completely empty response.
      Packit a4aae4
       
      Packit a4aae4
       */
      Packit a4aae4
      bool Sequence::serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval)
      Packit a4aae4
      {
      Packit a4aae4
          // Special case leaf sequences!
      Packit a4aae4
          bool status = false;
      Packit a4aae4
      Packit a4aae4
          if (is_leaf_sequence())
      Packit a4aae4
              status = serialize_leaf(dds, eval, m, ce_eval);
      Packit a4aae4
          else
      Packit a4aae4
              status = serialize_parent_part_one(dds, eval, m);
      Packit a4aae4
      Packit a4aae4
          return status;
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      // We know this is not a leaf Sequence. That means that this Sequence holds
      Packit a4aae4
      // another Sequence as one of its fields _and_ that child Sequence triggers
      Packit a4aae4
      // the actual transmission of values.
      Packit a4aae4
      Packit a4aae4
      bool Sequence::serialize_parent_part_one(DDS &dds, ConstraintEvaluator &eval, Marshaller &m)
      Packit a4aae4
      {
      Packit a4aae4
          DBG2(cerr << "Entering serialize_parent_part_one for " << name() << endl);
      Packit a4aae4
      Packit a4aae4
          int i = (d_starting_row_number != -1) ? d_starting_row_number : 0;
      Packit a4aae4
      Packit a4aae4
          // read_row returns true if valid data was read, false if the EOF was
      Packit a4aae4
          // found. 6/1/2001 jhrg
      Packit a4aae4
          // Since this is a parent sequence, read the row ignoring the CE (all of
      Packit a4aae4
          // the CE clauses will be evaluated by the leaf sequence).
      Packit a4aae4
          bool status = read_row(i, dds, eval, false);
      Packit a4aae4
          DBG2(cerr << "Sequence::serialize_parent_part_one::read_row() status: " << status << endl);
      Packit a4aae4
      Packit a4aae4
          while (status && !is_end_of_rows(i)) {
      Packit a4aae4
              i += d_row_stride;
      Packit a4aae4
      Packit a4aae4
              // DBG(cerr << "Writing Start of Instance marker" << endl);
      Packit a4aae4
              // write_start_of_instance(sink);
      Packit a4aae4
      Packit a4aae4
              // In this loop serialize will signal an error with an exception.
      Packit a4aae4
              for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
      Packit a4aae4
                  // Only call serialize for child Sequences; the leaf sequence
      Packit a4aae4
                  // will trigger the transmission of values for its parents (this
      Packit a4aae4
                  // sequence and maybe others) once it gets some valid data to
      Packit a4aae4
                  // send.
      Packit a4aae4
                  // Note that if the leaf sequence has no variables in the current
      Packit a4aae4
                  // projection, its serialize() method will never be called and that's
      Packit a4aae4
                  // the method that triggers actually sending values. Thus the leaf
      Packit a4aae4
                  // sequence must be the lowest level sequence with values whose send_p
      Packit a4aae4
                  // property is true.
      Packit a4aae4
                  if ((*iter)->send_p() && (*iter)->type() == dods_sequence_c) (*iter)->serialize(eval, dds, m);
      Packit a4aae4
              }
      Packit a4aae4
      Packit a4aae4
              set_read_p(false); // ...so this will read the next instance
      Packit a4aae4
      Packit a4aae4
              status = read_row(i, dds, eval, false);
      Packit a4aae4
              DBG(cerr << "Sequence::serialize_parent_part_one::read_row() status: " << status << endl);
      Packit a4aae4
          }
      Packit a4aae4
          // Reset current row number for next nested sequence element.
      Packit a4aae4
          d_row_number = -1;
      Packit a4aae4
      Packit a4aae4
          // Always write the EOS marker? 12/23/04 jhrg
      Packit a4aae4
          // Yes. According to DAP2, a completely empty response is signaled by
      Packit a4aae4
          // a return value of only the EOS marker for the outermost sequence.
      Packit a4aae4
          if (d_top_most || d_wrote_soi) {
      Packit a4aae4
              DBG(cerr << "Writing End of Sequence marker" << endl);
      Packit a4aae4
              write_end_of_sequence(m);
      Packit a4aae4
              d_wrote_soi = false;
      Packit a4aae4
          }
      Packit a4aae4
      Packit a4aae4
          return true;  // Signal errors with exceptions.
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      // If we are here then we know that this is 'parent sequence' and that the
      Packit a4aae4
      // leaf sequence has found valid data to send. We also know that
      Packit a4aae4
      // serialize_parent_part_one has been called so data are in the instance's
      Packit a4aae4
      // fields. This is where we send data. Whereas ..._part_one() contains a
      Packit a4aae4
      // loop to iterate over all of rows in a parent sequence, this does not. This
      Packit a4aae4
      // method assumes that the serialize_leaf() will call it each time it needs
      Packit a4aae4
      // to be called.
      Packit a4aae4
      //
      Packit a4aae4
      // NB: This code only works if the child sequences appear after all other
      Packit a4aae4
      // variables.
      Packit a4aae4
      void Sequence::serialize_parent_part_two(DDS &dds, ConstraintEvaluator &eval, Marshaller &m)
      Packit a4aae4
      {
      Packit a4aae4
          DBG(cerr << "Entering serialize_parent_part_two for " << name() << endl);
      Packit a4aae4
      Packit a4aae4
          BaseType *btp = get_parent();
      Packit a4aae4
          if (btp && btp->type() == dods_sequence_c) static_cast<Sequence&>(*btp).serialize_parent_part_two(dds, eval, m);
      Packit a4aae4
      Packit a4aae4
          if (d_unsent_data) {
      Packit a4aae4
              DBG(cerr << "Writing Start of Instance marker" << endl);
      Packit a4aae4
              d_wrote_soi = true;
      Packit a4aae4
              write_start_of_instance(m);
      Packit a4aae4
      Packit a4aae4
              // In this loop serialize will signal an error with an exception.
      Packit a4aae4
              for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
      Packit a4aae4
                  // Send all the non-sequence variables
      Packit a4aae4
                  DBG(cerr << "Sequence::serialize_parent_part_two(), serializing "
      Packit a4aae4
                          << (*iter)->name() << endl);
      Packit a4aae4
                  if ((*iter)->send_p() && (*iter)->type() != dods_sequence_c) {
      Packit a4aae4
                      DBG(cerr << "Send P is true, sending " << (*iter)->name() << endl);
      Packit a4aae4
                      (*iter)->serialize(eval, dds, m, false);
      Packit a4aae4
                  }
      Packit a4aae4
              }
      Packit a4aae4
      Packit a4aae4
              d_unsent_data = false;              // read should set this.
      Packit a4aae4
          }
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      // This code is only run by a leaf sequence. Note that a one level sequence
      Packit a4aae4
      // is also a leaf sequence.
      Packit a4aae4
      bool Sequence::serialize_leaf(DDS &dds, ConstraintEvaluator &eval, Marshaller &m, bool ce_eval)
      Packit a4aae4
      {
      Packit a4aae4
          DBG(cerr << "Entering Sequence::serialize_leaf for " << name() << endl);
      Packit a4aae4
          int i = (d_starting_row_number != -1) ? d_starting_row_number : 0;
      Packit a4aae4
      Packit a4aae4
          // read_row returns true if valid data was read, false if the EOF was
      Packit a4aae4
          // found. 6/1/2001 jhrg
      Packit a4aae4
          bool status = read_row(i, dds, eval, ce_eval);
      Packit a4aae4
          DBG(cerr << "Sequence::serialize_leaf::read_row() status: " << status << endl);
      Packit a4aae4
      Packit a4aae4
          // Once the first valid (satisfies the CE) row of the leaf sequence has
      Packit a4aae4
          // been read, we know we're going to send data. Send the current instance
      Packit a4aae4
          // of the parent/ancestor sequences now, if there are any. We only need
      Packit a4aae4
          // to do this once, hence it's not inside the while loop, but we only
      Packit a4aae4
          // send the parent seq data _if_ there's data in the leaf to send, that's
      Packit a4aae4
          // why we wait until after the first call to read_row() here in the leaf
      Packit a4aae4
          // sequence.
      Packit a4aae4
          //
      Packit a4aae4
          // NB: It's important to only call serialize_parent_part_two() for a
      Packit a4aae4
          // Sequence that really is the parent of a leaf sequence.
      Packit a4aae4
          if (status && !is_end_of_rows(i)) {
      Packit a4aae4
              BaseType *btp = get_parent();
      Packit a4aae4
              if (btp && btp->type() == dods_sequence_c) static_cast<Sequence&>(*btp).serialize_parent_part_two(dds, eval, m);
      Packit a4aae4
          }
      Packit a4aae4
      Packit a4aae4
          d_wrote_soi = false;
      Packit a4aae4
          while (status && !is_end_of_rows(i)) {
      Packit a4aae4
              i += d_row_stride;
      Packit a4aae4
      Packit a4aae4
              DBG(cerr << "Writing Start of Instance marker" << endl);
      Packit a4aae4
              d_wrote_soi = true;
      Packit a4aae4
              write_start_of_instance(m);
      Packit a4aae4
      Packit a4aae4
              // In this loop serialize will signal an error with an exception.
      Packit a4aae4
              for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
      Packit a4aae4
                  DBG(cerr << "Sequence::serialize_leaf(), serializing "
      Packit a4aae4
                          << (*iter)->name() << endl);
      Packit a4aae4
                  if ((*iter)->send_p()) {
      Packit a4aae4
                      DBG(cerr << "Send P is true, sending " << (*iter)->name() << endl);
      Packit a4aae4
                      (*iter)->serialize(eval, dds, m, false);
      Packit a4aae4
                  }
      Packit a4aae4
              }
      Packit a4aae4
      Packit a4aae4
              set_read_p(false); // ...so this will read the next instance
      Packit a4aae4
      Packit a4aae4
              status = read_row(i, dds, eval, ce_eval);
      Packit a4aae4
              DBG(cerr << "Sequence::serialize_leaf::read_row() status: " << status << endl);
      Packit a4aae4
          }
      Packit a4aae4
      Packit a4aae4
          // Only write the EOS marker if there's a matching Start Of Instance
      Packit a4aae4
          // Marker in the stream.
      Packit a4aae4
          if (d_wrote_soi || d_top_most) {
      Packit a4aae4
              DBG(cerr << "Writing End of Sequence marker" << endl);
      Packit a4aae4
              write_end_of_sequence(m);
      Packit a4aae4
          }
      Packit a4aae4
      Packit a4aae4
          return true;  // Signal errors with exceptions.
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      /** This method is used to evaluate a constraint and based on those results
      Packit a4aae4
       load the Sequence variable with data. This simulates having a server call
      Packit a4aae4
       the serialize() method and a client call the deserialize() method without
      Packit a4aae4
       the overhead of any IPC. Use this method on the server-side to 'load the
      Packit a4aae4
       d_values field with data' so that other code and work with those data.
      Packit a4aae4
      Packit a4aae4
       The somewhat odd algorithm used by serialize() is largely copied here, so
      Packit a4aae4
       comments about logic in serialize() and the related methods apply here
      Packit a4aae4
       as well.
      Packit a4aae4
      Packit a4aae4
       @note Even though each Sequence variable has a \e values field, only the
      Packit a4aae4
       top-most Sequence in a hierarchy of Sequences holds values. The field
      Packit a4aae4
       accessed by the var_value() method is a completely linked object; access
      Packit a4aae4
       the values of nested Sequences using the BaseType objects returned by
      Packit a4aae4
       var_value().
      Packit a4aae4
      Packit a4aae4
       @note Only call this method for top-most Sequences. Never call it for
      Packit a4aae4
       Sequences which have a parent (directly or indirectly) variable that is
      Packit a4aae4
       a Sequence.
      Packit a4aae4
      Packit a4aae4
       @param eval Use this constraint evaluator
      Packit a4aae4
       @param dds This DDS holds the variables for the data source */
      Packit a4aae4
      void Sequence::intern_data(ConstraintEvaluator &eval, DDS &dds)
      Packit a4aae4
      {
      Packit a4aae4
          DBG(cerr << "Sequence::intern_data - for " << name() << endl); DBG2(cerr << "    intern_data, values: " << &d_values << endl);
      Packit a4aae4
      Packit a4aae4
          // Why use a stack instead of return values? We need the stack because
      Packit a4aae4
          // Sequences nested three of more levels deep will loose the middle
      Packit a4aae4
          // instances when the intern_data_parent_part_two() code is run.
      Packit a4aae4
          sequence_values_stack_t sequence_values_stack;
      Packit a4aae4
      Packit a4aae4
          sequence_values_stack.push(&d_values);
      Packit a4aae4
      Packit a4aae4
          intern_data_private(eval, dds, sequence_values_stack);
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      void Sequence::intern_data_private(ConstraintEvaluator &eval, DDS &dds, sequence_values_stack_t &sequence_values_stack)
      Packit a4aae4
      {
      Packit a4aae4
          DBG(cerr << "Entering intern_data_private for " << name() << endl);
      Packit a4aae4
      Packit a4aae4
          if (is_leaf_sequence())
      Packit a4aae4
              intern_data_for_leaf(dds, eval, sequence_values_stack);
      Packit a4aae4
          else
      Packit a4aae4
              intern_data_parent_part_one(dds, eval, sequence_values_stack);
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      void Sequence::intern_data_parent_part_one(DDS & dds, ConstraintEvaluator & eval,
      Packit a4aae4
              sequence_values_stack_t & sequence_values_stack)
      Packit a4aae4
      {
      Packit a4aae4
          DBG(cerr << "Entering intern_data_parent_part_one for " << name() << endl);
      Packit a4aae4
      Packit a4aae4
          int i = (get_starting_row_number() != -1) ? get_starting_row_number() : 0;
      Packit a4aae4
      Packit a4aae4
          // read_row returns true if valid data was read, false if the EOF was
      Packit a4aae4
          // found. 6/1/2001 jhrg
      Packit a4aae4
          // Since this is a parent sequence, read the row ignoring the CE (all of
      Packit a4aae4
          // the CE clauses will be evaluated by the leaf sequence).
      Packit a4aae4
          bool status = read_row(i, dds, eval, false);
      Packit a4aae4
      Packit a4aae4
          // Grab the current size of the value stack. We do this because it is
      Packit a4aae4
          // possible that no nested sequences for this row happened to be
      Packit a4aae4
          // selected because of a constraint evaluation or the last row is not
      Packit a4aae4
          // selected because of a constraint evaluation. In either case, no
      Packit a4aae4
          // nested sequence d_values are pushed onto the stack, so there is
      Packit a4aae4
          // nothing to pop at the end of this function. pcw 07/14/08
      Packit a4aae4
          SequenceValues::size_type orig_stack_size = sequence_values_stack.size();
      Packit a4aae4
      Packit a4aae4
          while (status && (get_ending_row_number() == -1 || i <= get_ending_row_number())) {
      Packit a4aae4
              i += get_row_stride();
      Packit a4aae4
              for (Vars_iter iter = var_begin(); iter != var_end(); iter++) {
      Packit a4aae4
                  if ((*iter)->send_p()) {
      Packit a4aae4
                      switch ((*iter)->type()) {
      Packit a4aae4
                      case dods_sequence_c:
      Packit a4aae4
                          static_cast<Sequence&>(**iter).intern_data_private(eval, dds, sequence_values_stack);
      Packit a4aae4
                          break;
      Packit a4aae4
      Packit a4aae4
                      default:
      Packit a4aae4
                          (*iter)->intern_data(eval, dds);
      Packit a4aae4
                          break;
      Packit a4aae4
                      }
      Packit a4aae4
                  }
      Packit a4aae4
              }
      Packit a4aae4
      Packit a4aae4
              set_read_p(false);      // ...so this will read the next instance
      Packit a4aae4
      Packit a4aae4
              status = read_row(i, dds, eval, false);
      Packit a4aae4
          }
      Packit a4aae4
      Packit a4aae4
          // Reset current row number for next nested sequence element.
      Packit a4aae4
          reset_row_number();
      Packit a4aae4
      Packit a4aae4
          // if the size of the stack is larger than the original size (retrieved
      Packit a4aae4
          // above) then pop the top set of d_values from the stack. If it's the
      Packit a4aae4
          // same, then no nested sequences, or possibly the last nested sequence,
      Packit a4aae4
          // were pushed onto the stack, so there is nothing to pop.
      Packit a4aae4
          if (sequence_values_stack.size() > orig_stack_size) {
      Packit a4aae4
              DBG2(cerr << "    popping d_values (" << sequence_values_stack.top()
      Packit a4aae4
                      << ") off stack; size: " << sequence_values_stack.size() << endl);
      Packit a4aae4
              sequence_values_stack.pop();
      Packit a4aae4
          }
      Packit a4aae4
      Packit a4aae4
          DBG(cerr << "Leaving intern_data_parent_part_one for " << name() << endl);
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      void Sequence::intern_data_parent_part_two(DDS &dds, ConstraintEvaluator &eval,
      Packit a4aae4
              sequence_values_stack_t &sequence_values_stack)
      Packit a4aae4
      {
      Packit a4aae4
          DBG(cerr << "Entering intern_data_parent_part_two for " << name() << endl);
      Packit a4aae4
      Packit a4aae4
          BaseType *btp = get_parent();
      Packit a4aae4
          if (btp && btp->type() == dods_sequence_c) {
      Packit a4aae4
              static_cast<Sequence&>(*btp).intern_data_parent_part_two(dds, eval, sequence_values_stack);
      Packit a4aae4
          }
      Packit a4aae4
      Packit a4aae4
          DBG2(cerr << "    stack size: " << sequence_values_stack.size() << endl);
      Packit a4aae4
          SequenceValues *values = sequence_values_stack.top();
      Packit a4aae4
          DBG2(cerr << "    using values = " << (void *)values << endl);
      Packit a4aae4
      Packit a4aae4
          if (get_unsent_data()) {
      Packit a4aae4
              BaseTypeRow *row_data = new BaseTypeRow;
      Packit a4aae4
      Packit a4aae4
              // In this loop transfer_data will signal an error with an exception.
      Packit a4aae4
              for (Vars_iter iter = var_begin(); iter != var_end(); iter++) {
      Packit a4aae4
      Packit a4aae4
                  if ((*iter)->send_p() && (*iter)->type() != dods_sequence_c) {
      Packit a4aae4
                      row_data->push_back((*iter)->ptr_duplicate());
      Packit a4aae4
                  }
      Packit a4aae4
                  else if ((*iter)->send_p()) { //Sequence; must be the last variable
      Packit a4aae4
                      Sequence *tmp = dynamic_cast<Sequence*>((*iter)->ptr_duplicate());
      Packit a4aae4
                      if (!tmp) {
      Packit a4aae4
                          delete row_data;
      Packit a4aae4
                          throw InternalErr(__FILE__, __LINE__, "Expected a Sequence.");
      Packit a4aae4
                      }
      Packit a4aae4
                      row_data->push_back(tmp);
      Packit a4aae4
                      DBG2(cerr << "    pushing d_values of " << tmp->name()
      Packit a4aae4
                              << " (" << &(tmp->d_values)
      Packit a4aae4
                              << ") on stack; size: " << sequence_values_stack.size()
      Packit a4aae4
                              << endl);
      Packit a4aae4
                      // This pushes the d_values field of the newly created leaf
      Packit a4aae4
                      // Sequence onto the stack. The code then returns to intern
      Packit a4aae4
                      // _data_for_leaf() where this value will be used.
      Packit a4aae4
                      sequence_values_stack.push(&(tmp->d_values));
      Packit a4aae4
                  }
      Packit a4aae4
              }
      Packit a4aae4
      Packit a4aae4
              DBG2(cerr << "    pushing values for " << name()
      Packit a4aae4
                      << " to " << values << endl);
      Packit a4aae4
              values->push_back(row_data);
      Packit a4aae4
              set_unsent_data(false);
      Packit a4aae4
          }
      Packit a4aae4
      Packit a4aae4
          DBG(cerr << "Leaving intern_data_parent_part_two for " << name() << endl);
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      void Sequence::intern_data_for_leaf(DDS &dds, ConstraintEvaluator &eval, sequence_values_stack_t &sequence_values_stack)
      Packit a4aae4
      {
      Packit a4aae4
          DBG(cerr << "Entering intern_data_for_leaf for " << name() << endl);
      Packit a4aae4
      Packit a4aae4
          int i = (get_starting_row_number() != -1) ? get_starting_row_number() : 0;
      Packit a4aae4
      Packit a4aae4
          DBG2(cerr << "    reading row " << i << endl);
      Packit a4aae4
          bool status = read_row(i, dds, eval, true);
      Packit a4aae4
          DBG2(cerr << "    status: " << status << endl); DBG2(cerr << "    ending row number: " << get_ending_row_number() << endl);
      Packit a4aae4
      Packit a4aae4
          if (status && (get_ending_row_number() == -1 || i <= get_ending_row_number())) {
      Packit a4aae4
              BaseType *btp = get_parent();
      Packit a4aae4
              if (btp && btp->type() == dods_sequence_c) {
      Packit a4aae4
                  // This call will read the values for the parent sequences and
      Packit a4aae4
                  // then allocate a new instance for the leaf and push that onto
      Packit a4aae4
                  // the stack.
      Packit a4aae4
                  static_cast<Sequence&>(*btp).intern_data_parent_part_two(dds, eval, sequence_values_stack);
      Packit a4aae4
              }
      Packit a4aae4
      Packit a4aae4
              // intern_data_parent_part_two pushes the d_values field of the leaf
      Packit a4aae4
              // onto the stack, so this operation grabs that value and then loads
      Packit a4aae4
              // data into it.
      Packit a4aae4
              SequenceValues *values = sequence_values_stack.top();
      Packit a4aae4
              DBG2(cerr << "    using values = " << values << endl);
      Packit a4aae4
      Packit a4aae4
              while (status && (get_ending_row_number() == -1 || i <= get_ending_row_number())) {
      Packit a4aae4
                  i += get_row_stride();
      Packit a4aae4
      Packit a4aae4
                  // Copy data from the object's fields to this new BaeTypeRow instance
      Packit a4aae4
                  BaseTypeRow *row_data = new BaseTypeRow;
      Packit a4aae4
                  for (Vars_iter iter = var_begin(); iter != var_end(); iter++) {
      Packit a4aae4
                      if ((*iter)->send_p()) {
      Packit a4aae4
                          row_data->push_back((*iter)->ptr_duplicate());
      Packit a4aae4
                      }
      Packit a4aae4
                  }
      Packit a4aae4
      Packit a4aae4
                  DBG2(cerr << "    pushing values for " << name()
      Packit a4aae4
                          << " to " << values << endl);
      Packit a4aae4
                  // Save the row_data to values().
      Packit a4aae4
                  values->push_back(row_data);
      Packit a4aae4
      Packit a4aae4
                  set_read_p(false);      // ...so this will read the next instance
      Packit a4aae4
                  // Read the ith row into this object's fields
      Packit a4aae4
                  status = read_row(i, dds, eval, true);
      Packit a4aae4
              }
      Packit a4aae4
      Packit a4aae4
              DBG2(cerr << "    popping d_values (" << sequence_values_stack.top()
      Packit a4aae4
                      << ") off stack; size: " << sequence_values_stack.size() << endl);
      Packit a4aae4
              sequence_values_stack.pop();
      Packit a4aae4
          }
      Packit a4aae4
      Packit a4aae4
          DBG(cerr << "Leaving intern_data_for_leaf for " << name() << endl);
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      /** @brief Deserialize (read from the network) the entire Sequence.
      Packit a4aae4
      Packit a4aae4
       This method used to read a single row at a time. Now the entire
      Packit a4aae4
       sequence is read at once. The method used to return True to indicate
      Packit a4aae4
       that more data needed to be deserialized and False when the sequence
      Packit a4aae4
       was completely read. Now it simply returns false. This might seem odd,
      Packit a4aae4
       but making this method return false breaks existing software the least.
      Packit a4aae4
      Packit a4aae4
       @param um An UnMarshaller that knows how to deserialize data
      Packit a4aae4
       @param dds A DataDDS from which to read.
      Packit a4aae4
       @param reuse Passed to child objects when they are deserialized. Some
      Packit a4aae4
       implementations of deserialize() use this to determine if new storage should
      Packit a4aae4
       be allocated or existing storage reused.
      Packit a4aae4
       @exception Error if a sequence stream marker cannot be read.
      Packit a4aae4
       @exception InternalErr if the <tt>dds</tt> param is not a DataDDS.
      Packit a4aae4
       @return A return value of false indicates that an EOS ("end of
      Packit a4aae4
       Sequence") marker was found, while a value of true indicates
      Packit a4aae4
       that there are more rows to be read. This version always reads the
      Packit a4aae4
       entire sequence, so it always returns false.
      Packit a4aae4
       */
      Packit a4aae4
      bool Sequence::deserialize(UnMarshaller &um, DDS *dds, bool reuse)
      Packit a4aae4
      {
      Packit a4aae4
      #if 0
      Packit a4aae4
          // Nathan's tip - this is something that should never happen
      Packit a4aae4
          DataDDS *dd = dynamic_cast<DataDDS *>(dds);
      Packit a4aae4
          if (!dd) throw InternalErr("Expected argument 'dds' to be a DataDDS!");
      Packit a4aae4
      Packit a4aae4
          DBG2(cerr << "Reading from server/protocol version: "
      Packit a4aae4
                  << dd->get_protocol_major() << "." << dd->get_protocol_minor()
      Packit a4aae4
                  << endl);
      Packit a4aae4
      Packit a4aae4
          // Check for old servers.
      Packit a4aae4
          if (dd->get_protocol_major() < 2) {
      Packit a4aae4
              throw Error(
      Packit a4aae4
                      string("The protocl version (") + dd->get_protocol()
      Packit a4aae4
                              + ") indicates that this\nis an old server which may not correctly transmit Sequence variables.\nContact the server administrator.");
      Packit a4aae4
          }
      Packit a4aae4
      #endif
      Packit a4aae4
          while (true) {
      Packit a4aae4
              // Grab the sequence stream's marker.
      Packit a4aae4
              unsigned char marker = read_marker(um);
      Packit a4aae4
              if (is_end_of_sequence(marker))
      Packit a4aae4
                  break;  // EXIT the while loop here!!!
      Packit a4aae4
              else if (is_start_of_instance(marker)) {
      Packit a4aae4
                  d_row_number++;
      Packit a4aae4
                  DBG2(cerr << "Reading row " << d_row_number << " of "
      Packit a4aae4
                          << name() << endl);
      Packit a4aae4
                  BaseTypeRow *bt_row_ptr = new BaseTypeRow;
      Packit a4aae4
                  // Read the instance's values, building up the row
      Packit a4aae4
                  for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
      Packit a4aae4
                      BaseType *bt_ptr = (*iter)->ptr_duplicate();
      Packit a4aae4
                      bt_ptr->deserialize(um, dds, reuse);
      Packit a4aae4
                      DBG2(cerr << "Deserialized " << bt_ptr->name() << " ("
      Packit a4aae4
                              << bt_ptr << ") = "); DBG2(bt_ptr->print_val(stderr, ""));
      Packit a4aae4
                      bt_row_ptr->push_back(bt_ptr);
      Packit a4aae4
                  }
      Packit a4aae4
                  // Append this row to those accumulated.
      Packit a4aae4
                  d_values.push_back(bt_row_ptr);
      Packit a4aae4
              }
      Packit a4aae4
              else
      Packit a4aae4
                  throw Error("I could not read the expected Sequence data stream marker!");
      Packit a4aae4
          };
      Packit a4aae4
      Packit a4aae4
          return false;
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      // Return the current row number.
      Packit a4aae4
      Packit a4aae4
      /** Return the starting row number if the sequence was constrained using
      Packit a4aae4
       row numbers (instead of, or in addition to, a relational constraint).
      Packit a4aae4
       If a relational constraint was also given, the row number corresponds
      Packit a4aae4
       to the row number of the sequence after applying the relational
      Packit a4aae4
       constraint.
      Packit a4aae4
      Packit a4aae4
       If the bracket notation was not used to constrain this sequence, this
      Packit a4aae4
       method returns -1.
      Packit a4aae4
      Packit a4aae4
       @brief Get the starting row number.
      Packit a4aae4
       @return The starting row number. */
      Packit a4aae4
      int Sequence::get_starting_row_number()
      Packit a4aae4
      {
      Packit a4aae4
          return d_starting_row_number;
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      /** Return the row stride number if the sequence was constrained using
      Packit a4aae4
       row numbers (instead of, or in addition to, a relational constraint).
      Packit a4aae4
       If a relational constraint was also given, the row stride is applied
      Packit a4aae4
       to the sequence after applying the relational constraint.
      Packit a4aae4
      Packit a4aae4
       If the bracket notation was not used to constrain this sequence, this
      Packit a4aae4
       method returns -1.
      Packit a4aae4
      Packit a4aae4
       @brief Get the row stride.
      Packit a4aae4
       @return The row stride. */
      Packit a4aae4
      int Sequence::get_row_stride()
      Packit a4aae4
      {
      Packit a4aae4
          return d_row_stride;
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      /** Return the ending row number if the sequence was constrained using
      Packit a4aae4
       row numbers (instead of, or in addition to, a relational constraint).
      Packit a4aae4
       If a relational constraint was also given, the row number corresponds
      Packit a4aae4
       to the row number of the sequence after applying the
      Packit a4aae4
       relational constraint.
      Packit a4aae4
      Packit a4aae4
       If the bracket notation was not used to constrain this sequence, this
      Packit a4aae4
       method returns -1.
      Packit a4aae4
      Packit a4aae4
       @brief Get the ending row number.
      Packit a4aae4
       @return The ending row number. */
      Packit a4aae4
      int Sequence::get_ending_row_number()
      Packit a4aae4
      {
      Packit a4aae4
          return d_ending_row_number;
      Packit a4aae4
      }
      Packit a4aae4
      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
      void Sequence::set_row_number_constraint(int start, int stop, int stride)
      Packit a4aae4
      {
      Packit a4aae4
          if (stop < start) 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
      Packit a4aae4
      void Sequence::print_one_row(FILE *out, int row, string space, bool print_row_num)
      Packit a4aae4
      {
      Packit a4aae4
          ostringstream oss;
      Packit a4aae4
          print_one_row(oss, row, space, print_row_num);
      Packit a4aae4
          fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      void Sequence::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
          // 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)
      Packit a4aae4
                      static_cast<Sequence*>(bt_ptr)->print_val_by_rows(out, 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)
      Packit a4aae4
                      static_cast<Sequence*>(bt_ptr)->print_val_by_rows(out, 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 Sequence::print_val_by_rows(FILE *out, string space, bool print_decl_p, bool print_row_numbers)
      Packit a4aae4
      {
      Packit a4aae4
          ostringstream oss;
      Packit a4aae4
          print_val_by_rows(oss, space, print_decl_p, print_row_numbers);
      Packit a4aae4
          fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      void Sequence::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
          int rows = number_of_rows() - 1;
      Packit a4aae4
          int i;
      Packit a4aae4
          for (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, i, space, print_row_numbers);
      Packit a4aae4
      Packit a4aae4
          out << " }";
      Packit a4aae4
      Packit a4aae4
          if (print_decl_p) out << ";\n";
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      void Sequence::print_val(FILE *out, string space, bool print_decl_p)
      Packit a4aae4
      {
      Packit a4aae4
          print_val_by_rows(out, space, print_decl_p, false);
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      void Sequence::print_val(ostream &out, string space, bool print_decl_p)
      Packit a4aae4
      {
      Packit a4aae4
          print_val_by_rows(out, space, print_decl_p, false);
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      void Sequence::set_leaf_p(bool state)
      Packit a4aae4
      {
      Packit a4aae4
          d_leaf_sequence = state;
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      bool Sequence::is_leaf_sequence()
      Packit a4aae4
      {
      Packit a4aae4
          return d_leaf_sequence;
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      /** @brief Mark the Sequence which holds the leaf elements.
      Packit a4aae4
      Packit a4aae4
       In a nested Sequence, the Sequence which holds the leaf elements is special
      Packit a4aae4
       because it during the serialization of this Sequence's data that constraint
      Packit a4aae4
       Expressions must be evaluated. If CEs are evaluated at the upper levels,
      Packit a4aae4
       then valid data may not be sent because it was effectively hidden from the
      Packit a4aae4
       serialization and evaluation code (see the documentation for the serialize_leaf()
      Packit a4aae4
       method).
      Packit a4aae4
      Packit a4aae4
       The notion of the leaf Sequence needs to be modified to mean the lowest level
      Packit a4aae4
       of a Sequence where data are to be sent. Suppose there's a two level Sequence,
      Packit a4aae4
       but that only fields from the top level are to be sent. Then that top level
      Packit a4aae4
       is also the leaf Sequence and should be marked as such. If the lower level is
      Packit a4aae4
       marked as a leaf Sequence, then no values will ever be sent since the send_p
      Packit a4aae4
       property will always be false for each field and it's the call to
      Packit a4aae4
       serialize_leaf() that actually triggers transmission of values (because it's
      Packit a4aae4
       not until the code makes it into serialize_leaf() that it knows there are
      Packit a4aae4
       values to be sent.
      Packit a4aae4
      Packit a4aae4
       @note This method \e must not be called before the CE is parsed.
      Packit a4aae4
      Packit a4aae4
       @param lvl The current level of the Sequence. a \e lvl of 1 indicates the
      Packit a4aae4
       topmost Sequence. The default value is 1.
      Packit a4aae4
       @see Sequence::serialize_leaf() */
      Packit a4aae4
      void Sequence::set_leaf_sequence(int lvl)
      Packit a4aae4
      {
      Packit a4aae4
          bool has_child_sequence = false;
      Packit a4aae4
      Packit a4aae4
          if (lvl == 1) d_top_most = true;
      Packit a4aae4
      Packit a4aae4
          DBG2(cerr << "Processing sequence " << name() << endl);
      Packit a4aae4
      Packit a4aae4
          for (Vars_iter iter = d_vars.begin(); iter != d_vars.end(); iter++) {
      Packit a4aae4
              // About the test for send_p(): Only descend into a sequence if it has
      Packit a4aae4
              // fields that might be sent. Thus if, in a two-level sequence, nothing
      Packit a4aae4
              // in the lower level is to be sent, the upper level is marked as the
      Packit a4aae4
              // leaf sequence. This ensures that values _will_ be sent (see the comment
      Packit a4aae4
              // in serialize_leaf() and serialize_parent_part_one()).
      Packit a4aae4
              if ((*iter)->type() == dods_sequence_c && (*iter)->send_p()) {
      Packit a4aae4
                  if (has_child_sequence)
      Packit a4aae4
                      throw Error("This implementation does not support more than one nested sequence at a level. Contact the server administrator.");
      Packit a4aae4
      Packit a4aae4
                  has_child_sequence = true;
      Packit a4aae4
                  static_cast<Sequence&>(**iter).set_leaf_sequence(++lvl);
      Packit a4aae4
              }
      Packit a4aae4
              else if ((*iter)->type() == dods_structure_c) {
      Packit a4aae4
                  static_cast<Structure&>(**iter).set_leaf_sequence(lvl);
      Packit a4aae4
              }
      Packit a4aae4
          }
      Packit a4aae4
      Packit a4aae4
          if (!has_child_sequence)
      Packit a4aae4
              set_leaf_p(true);
      Packit a4aae4
          else
      Packit a4aae4
              set_leaf_p(false);
      Packit a4aae4
      Packit a4aae4
          DBG2(cerr << "is_leaf_sequence(): " << is_leaf_sequence() << " (" << name() << ")" << endl);
      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 Sequence::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_row_number << endl;
      Packit a4aae4
          strm << DapIndent::LMarg << "bracket notation information:" << endl;
      Packit a4aae4
          DapIndent::Indent();
      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
          DapIndent::UnIndent();
      Packit a4aae4
      Packit a4aae4
          strm << DapIndent::LMarg << "data been sent? " << d_unsent_data << endl;
      Packit a4aae4
          strm << DapIndent::LMarg << "start of instance? " << d_wrote_soi << endl;
      Packit a4aae4
          strm << DapIndent::LMarg << "is leaf sequence? " << d_leaf_sequence << endl;
      Packit a4aae4
          strm << DapIndent::LMarg << "top most in hierarchy? " << d_top_most << endl;
      Packit a4aae4
          DapIndent::UnIndent();
      Packit a4aae4
      }
      Packit a4aae4
      Packit a4aae4
      } // namespace libdap
      Packit a4aae4