|
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 |
Sending a one-level sequence:
|
|
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 |
Sending a nested sequence:
|
|
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 |
For a nested Sequence, the child sequence must follow all other types
|
|
Packit |
a4aae4 |
in the parent sequence (like the example). There may be only one nested
|
|
Packit |
a4aae4 |
Sequence per level.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
CE evaluation happens only in a leaf sequence.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
When no data satisfies a CE, the empty Sequence is signaled by a
|
|
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 |
|