|
Packit |
a4aae4 |
|
|
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 Grid.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// jhrg 9/15/94
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "config.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// #define DODS_DEBUG
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <sstream>
|
|
Packit |
a4aae4 |
#include <functional>
|
|
Packit |
a4aae4 |
#include <algorithm>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "Grid.h"
|
|
Packit |
a4aae4 |
#include "DDS.h"
|
|
Packit |
a4aae4 |
#include "Array.h" // for downcasts
|
|
Packit |
a4aae4 |
#include "util.h"
|
|
Packit |
a4aae4 |
#include "InternalErr.h"
|
|
Packit |
a4aae4 |
#include "escaping.h"
|
|
Packit |
a4aae4 |
#include "XDRStreamMarshaller.h"
|
|
Packit |
a4aae4 |
#include "debug.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "XMLWriter.h"
|
|
Packit |
a4aae4 |
#include "DMR.h"
|
|
Packit |
a4aae4 |
#include "D4Group.h"
|
|
Packit |
a4aae4 |
#include "D4Maps.h"
|
|
Packit |
a4aae4 |
#include "D4Attributes.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
using namespace std;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
namespace libdap {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Grid::m_duplicate(const Grid &s)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// TODO revisit this code once/if the class is switched from using it's
|
|
Packit |
a4aae4 |
// own vars to those in Constructor. jhrg 4/3/13
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// copy the weak pointer - Constructor will take care of copying
|
|
Packit |
a4aae4 |
// the 'strong' pointers.
|
|
Packit |
a4aae4 |
//d_array_var = s.d_array_var;
|
|
Packit |
a4aae4 |
d_is_array_set = s.d_is_array_set;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** The Grid 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 Grid constructor.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
Grid::Grid(const string &n) : Constructor(n, dods_grid_c), d_is_array_set(false)
|
|
Packit |
a4aae4 |
{}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** The Grid server-side constructor requires the name of the variable
|
|
Packit |
a4aae4 |
to be created and the dataset name from which this variable is created.
|
|
Packit |
a4aae4 |
Used when creating variables on the server side.
|
|
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 Grid constructor.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
Grid::Grid(const string &n, const string &d)
|
|
Packit |
a4aae4 |
: Constructor(n, d, dods_grid_c), d_is_array_set(false)
|
|
Packit |
a4aae4 |
{}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief The Grid copy constructor. */
|
|
Packit |
a4aae4 |
Grid::Grid(const Grid &rhs) : Constructor(rhs)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
m_duplicate(rhs);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Grid::~Grid()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
//d_array_var = 0; // Weak pointer; object will be freed by Constructor
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *
|
|
Packit |
a4aae4 |
Grid::ptr_duplicate()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return new Grid(*this);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Grid &
|
|
Packit |
a4aae4 |
Grid::operator=(const Grid &rhs)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (this == &rhs)
|
|
Packit |
a4aae4 |
return *this;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Removed this; it makes this operator= work differently than the rest
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
delete d_array_var; d_array_var = 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
|
|
Packit |
a4aae4 |
BaseType *btp = *i ;
|
|
Packit |
a4aae4 |
delete btp ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dynamic_cast<Constructor &>(*this) = rhs;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
m_duplicate(rhs);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return *this;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Grid::transform_to_dap4(D4Group *root, Constructor *container)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - BEGIN (name:"<< name() <<
|
|
Packit |
a4aae4 |
")(type:"<< type_name()<<
|
|
Packit |
a4aae4 |
")(root:'"<< root->name()<<"':"<<(void*)root <<
|
|
Packit |
a4aae4 |
")(container:'"<< container->name()<<"':"<< (void *) container<< ")"
|
|
Packit |
a4aae4 |
<< endl;);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
vector<Array*> d4_map_arrays;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// We do the Map Arrays first because some people expect to see them
|
|
Packit |
a4aae4 |
// delclared prior to the coverage array the utilizes them - even though that
|
|
Packit |
a4aae4 |
// is not a requirement of DAP4 I did it here to make people happier.
|
|
Packit |
a4aae4 |
// We add the maps arrays to the current container if needed and make a
|
|
Packit |
a4aae4 |
// a vector of them so we can add D4Map objects to our Precious down
|
|
Packit |
a4aae4 |
// below.
|
|
Packit |
a4aae4 |
for (Map_iter i = map_begin(), e = map_end(); i != e; ++i) {
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - Processing Map Array: '"<< (*i)->name() << "' ("<< (void *)(*i)<< ")" << endl;);
|
|
Packit |
a4aae4 |
// Only add the map/array if it's not already present in the target DAP2 container.
|
|
Packit |
a4aae4 |
// Given the scoping rules for DAP2 and the assumption the DDS is valid, testing for
|
|
Packit |
a4aae4 |
// the same name is good enough. The point here is to be sure to only use the
|
|
Packit |
a4aae4 |
// existing maps. This is an important issue when there are multiple Grids in the same
|
|
Packit |
a4aae4 |
// dataset that utilize the same Map arrays data.
|
|
Packit |
a4aae4 |
Array *the_map_array;;
|
|
Packit |
a4aae4 |
Array *container_map_array = static_cast<Array*>(container->var((*i)->name()));
|
|
Packit |
a4aae4 |
if(!container_map_array){
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the current DAP4 container ("<<container->name()<< ":"<<(void*)container<< "). Let's fix that..." << endl;);
|
|
Packit |
a4aae4 |
// Not in the container, so we check root group
|
|
Packit |
a4aae4 |
Array *root_map_array = static_cast<Array*>(root->var((*i)->name()));
|
|
Packit |
a4aae4 |
if (!root_map_array) {
|
|
Packit |
a4aae4 |
// Not in the root group so we transform a new array and add it to container.
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the root Group ("<<root->name()<< ":"<<(void*)root<< "). Let's fix that..." << endl;);
|
|
Packit |
a4aae4 |
// transform it and add it to the container
|
|
Packit |
a4aae4 |
(*i)->transform_to_dap4(root, container);
|
|
Packit |
a4aae4 |
// Recover the new dap4 version from the container.
|
|
Packit |
a4aae4 |
the_map_array = static_cast<Array*>(container->var((*i)->name()));
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - Transformed array '"<< the_map_array->name() <<
|
|
Packit |
a4aae4 |
"' to DAP4 Array (" << (void *) the_map_array << ") added to container: '"<<
|
|
Packit |
a4aae4 |
container->name() <<"'" << endl;);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
the_map_array = root_map_array;
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' (" <<
|
|
Packit |
a4aae4 |
(void *) the_map_array << ") present in the root group ("<<root->name()<< ":"<<(void*)root <<
|
|
Packit |
a4aae4 |
")"<< endl;);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
the_map_array = container_map_array;
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' (" <<
|
|
Packit |
a4aae4 |
(void *) the_map_array << ") present in the current DAP4 container ("<<container->name( )<< ":"<<
|
|
Packit |
a4aae4 |
(void*)container<< ")" << endl;);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// We'll use these (below) to make D4Map objects for the coverage
|
|
Packit |
a4aae4 |
d4_map_arrays.push_back(the_map_array);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Adds the coverage array to the container.
|
|
Packit |
a4aae4 |
array_var()->transform_to_dap4(root, container);
|
|
Packit |
a4aae4 |
// Get the new coverage array
|
|
Packit |
a4aae4 |
BaseType *btp = container->var(array_var()->name());
|
|
Packit |
a4aae4 |
Array *coverage = static_cast<Array*>(btp);
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - Transformed and added DAP4 coverage Array '"<< coverage->name() <<
|
|
Packit |
a4aae4 |
"' to parent container: '" << container->name() << "'" << endl;);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
coverage->attributes()->transform_to_dap4(get_attr_table());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - " << "Coverage Array '"<< coverage->name() << "' attributes: " << endl;
|
|
Packit |
a4aae4 |
XMLWriter xmlw;
|
|
Packit |
a4aae4 |
coverage->get_attr_table().print_dap4(xmlw);
|
|
Packit |
a4aae4 |
cerr << xmlw.get_doc() << endl;);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Add the D4Maps
|
|
Packit |
a4aae4 |
vector<Array*>::iterator d4aItr=d4_map_arrays.begin();
|
|
Packit |
a4aae4 |
vector<Array*>::iterator end=d4_map_arrays.end();
|
|
Packit |
a4aae4 |
for( ; d4aItr!=end ; d4aItr++){
|
|
Packit |
a4aae4 |
Array *the_map_array = *d4aItr;
|
|
Packit |
a4aae4 |
// Here we use the Map Array that we saved the Map
|
|
Packit |
a4aae4 |
// name and Map Array reference for our map.
|
|
Packit |
a4aae4 |
D4Map *d4_map = new D4Map(the_map_array->FQN(), the_map_array, coverage); // bind the 'map' to the coverage
|
|
Packit |
a4aae4 |
coverage->maps()->add_map(d4_map); // bind the coverage to the map
|
|
Packit |
a4aae4 |
// Clear the vector entry to ensure that ~Array doesn't
|
|
Packit |
a4aae4 |
// get called when the (stack declared) vector goes out of scope.
|
|
Packit |
a4aae4 |
*d4aItr = 0;
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - Added DAP4 Map Array: '"<< d4_map->name() <<
|
|
Packit |
a4aae4 |
"' (" << (void *) d4_map->array() << ") to coverage: '" << coverage->name() << "'" << endl;);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - END (grid:" << name() << ")" << endl;);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Grid can only be used for DAP2.
|
|
Packit |
a4aae4 |
* @note This might change depending on just how complex DAP4Array becomes,
|
|
Packit |
a4aae4 |
* for example.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
bool
|
|
Packit |
a4aae4 |
Grid::is_dap2_only_type()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Add an array or map to the Grid.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
The original version of this method required that the \c part parameter
|
|
Packit |
a4aae4 |
be present. However, this complicates using the class from a parser
|
|
Packit |
a4aae4 |
(e.g., the schema-based XML parser). I have modified the method so that
|
|
Packit |
a4aae4 |
if \c part is nil (the default), then the first variable added is the
|
|
Packit |
a4aae4 |
array and subsequent variables are maps. This matches the behavior in the
|
|
Packit |
a4aae4 |
Java DAP implementation.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param bt Array or Map variable
|
|
Packit |
a4aae4 |
@param part is this an array or a map. If not present, first \c bt is the
|
|
Packit |
a4aae4 |
array and subsequent <tt>bt</tt>s are maps. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Grid::add_var(BaseType *bt, Part part)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!bt)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (part == array && d_is_array_set/*get_array()*/) {
|
|
Packit |
a4aae4 |
// Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// avoid obvious broken semantics
|
|
Packit |
a4aae4 |
if (!dynamic_cast<Array*>(bt)) {
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Set to the clone of bt if we get that far.
|
|
Packit |
a4aae4 |
BaseType* bt_clone = 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (part) {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case array: {
|
|
Packit |
a4aae4 |
// Add it as a copy to preserve old semantics. This sets parent too.
|
|
Packit |
a4aae4 |
bt_clone = bt->ptr_duplicate();
|
|
Packit |
a4aae4 |
set_array(static_cast<Array*>(bt_clone));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case maps: {
|
|
Packit |
a4aae4 |
bt_clone = bt->ptr_duplicate();
|
|
Packit |
a4aae4 |
bt_clone->set_parent(this);
|
|
Packit |
a4aae4 |
d_vars.push_back(bt_clone);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default: {
|
|
Packit |
a4aae4 |
if (!d_is_array_set/*!d_array_var*/) {
|
|
Packit |
a4aae4 |
// Add it as a copy to preserve old semantics. This sets parent too.
|
|
Packit |
a4aae4 |
bt_clone = bt->ptr_duplicate();
|
|
Packit |
a4aae4 |
set_array(static_cast<Array*>(bt_clone));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
bt_clone = bt->ptr_duplicate();
|
|
Packit |
a4aae4 |
bt_clone->set_parent(this);
|
|
Packit |
a4aae4 |
d_vars.push_back(bt_clone);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Add an array or map to the Grid.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@note The original version of this method required that the \c part parameter
|
|
Packit |
a4aae4 |
be present. However, this complicates using the class from a parser
|
|
Packit |
a4aae4 |
(e.g., the schema-based XML parser). I have modified the method so that
|
|
Packit |
a4aae4 |
if \c part is nil (the default), then the first variable added is the
|
|
Packit |
a4aae4 |
array and subsequent variables are maps. This matches the behavior in the
|
|
Packit |
a4aae4 |
Java DAP implementation.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@note This version of the method does not the BaseType before adding it.
|
|
Packit |
a4aae4 |
The caller must not free the BaseType object.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param bt Array or Map variable
|
|
Packit |
a4aae4 |
@param part is this an array or a map. If not present, first \c bt is the
|
|
Packit |
a4aae4 |
array and subsequent <tt>bt</tt>s are maps. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Grid::add_var_nocopy(BaseType *bt, Part part)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!bt)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (part == array && d_is_array_set/*get_array()*/) {
|
|
Packit |
a4aae4 |
// Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// avoid obvious broken semantics
|
|
Packit |
a4aae4 |
if (!dynamic_cast<Array*>(bt)) {
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
bt->set_parent(this);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (part) {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case array: {
|
|
Packit |
a4aae4 |
// Refactored to use new set_array ([mjohnson 11 nov 2009])
|
|
Packit |
a4aae4 |
set_array(static_cast<Array*>(bt));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case maps: {
|
|
Packit |
a4aae4 |
// FIXME Why is this commented out?
|
|
Packit |
a4aae4 |
//bt->set_parent(this);
|
|
Packit |
a4aae4 |
d_vars.push_back(bt);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default: {
|
|
Packit |
a4aae4 |
if (!d_is_array_set/*!get_array()*/) {
|
|
Packit |
a4aae4 |
// Refactored to use new set_array ([mjohnson 11 nov 2009])
|
|
Packit |
a4aae4 |
// avoid obvious broken semantics
|
|
Packit |
a4aae4 |
set_array(static_cast<Array*>(bt));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
d_vars.push_back(bt);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Set the Array part of the Grid to point to the memory
|
|
Packit |
a4aae4 |
* p_new_arr. Grid takes control of the memory (no copy
|
|
Packit |
a4aae4 |
* is made).
|
|
Packit |
a4aae4 |
* If there already exists an array portion, the old
|
|
Packit |
a4aae4 |
* one will be deleted to avoid leaks.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @note This code has been modified to use a new storage for
|
|
Packit |
a4aae4 |
* the Grid's variables (the storage defined by Constructor).
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param p_new_arr the object to store as the array
|
|
Packit |
a4aae4 |
* part of the grid.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void Grid::set_array(Array* p_new_arr)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!p_new_arr) {
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Grid::set_array(): Cannot set to null!");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Make sure not same memory, this would be evil.
|
|
Packit |
a4aae4 |
if (p_new_arr == get_array()) {
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
p_new_arr->set_parent(this);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Three cases: 1. There are no variables set for this grid at all
|
|
Packit |
a4aae4 |
// 2. There are maps but no array
|
|
Packit |
a4aae4 |
// 3. There is already an array set (and maybe maps).
|
|
Packit |
a4aae4 |
// NB: d_array_var is a weak pointer to the Grid's Array
|
|
Packit |
a4aae4 |
if (d_vars.size() == 0) {
|
|
Packit |
a4aae4 |
d_vars.push_back(p_new_arr);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (!d_is_array_set/*!d_array_var*/) {
|
|
Packit |
a4aae4 |
d_vars.insert(d_vars.begin(), p_new_arr);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
// clean out old array
|
|
Packit |
a4aae4 |
delete get_array();
|
|
Packit |
a4aae4 |
d_vars[0] = p_new_arr;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_is_array_set = true;
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
// store the array pointer locally
|
|
Packit |
a4aae4 |
d_array_var = p_new_arr;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Set the parent
|
|
Packit |
a4aae4 |
d_array_var->set_parent(this);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Add the given array p_new_map as a new map
|
|
Packit |
a4aae4 |
* vector for the Grid.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* If add_as_copy, p_new_map will be cloned
|
|
Packit |
a4aae4 |
* and the copy added, leaving p_new_map
|
|
Packit |
a4aae4 |
* in the control of the caller.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* If !add_as_copy, p_new_map will be explicitly
|
|
Packit |
a4aae4 |
* added as the new map vector.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* The actual Array* in the Grid will be returned,
|
|
Packit |
a4aae4 |
* either the address of the COPY if add_as_copy,
|
|
Packit |
a4aae4 |
* else p_new_map itself if !add_as_copy.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* It is an exception for p_new_map to be null.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param p_new_map the map we want to add
|
|
Packit |
a4aae4 |
* @param add_as_copy whether to add p_new_map
|
|
Packit |
a4aae4 |
* explicitly and take onwership of memory
|
|
Packit |
a4aae4 |
* or to add a clone of it and leave control
|
|
Packit |
a4aae4 |
* to caller.
|
|
Packit |
a4aae4 |
* @return the actual object stored in the Grid, whether
|
|
Packit |
a4aae4 |
* p_new_map, or the address of the copy.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
Array*
|
|
Packit |
a4aae4 |
Grid::add_map(Array* p_new_map, bool add_as_copy)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!p_new_map)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Grid::add_map(): cannot have p_new_map null!");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (add_as_copy)
|
|
Packit |
a4aae4 |
p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
p_new_map->set_parent(this);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_vars.push_back(p_new_map);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// return the one that got put into the Grid.
|
|
Packit |
a4aae4 |
return p_new_map;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Add pMap (or a clone if addAsCopy) to the
|
|
Packit |
a4aae4 |
* FRONT of the maps list. This is needed if
|
|
Packit |
a4aae4 |
* we are preserving Grid semantics but want to
|
|
Packit |
a4aae4 |
* add a new OUTER dimension, whereas add_map
|
|
Packit |
a4aae4 |
* appends to the end making a new INNER dimension.
|
|
Packit |
a4aae4 |
* @param p_new_map the map to add or copy and add
|
|
Packit |
a4aae4 |
* @param add_copy if true, copy pMap and add the copy.
|
|
Packit |
a4aae4 |
* @return The actual memory stored in the Grid,
|
|
Packit |
a4aae4 |
* either pMap (if !add_copy) or the ptr to
|
|
Packit |
a4aae4 |
* the clone (if add_copy).
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
Array*
|
|
Packit |
a4aae4 |
Grid::prepend_map(Array* p_new_map, bool add_copy)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (add_copy)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
p_new_map->set_parent(this);
|
|
Packit |
a4aae4 |
d_vars.insert(map_begin(), p_new_map);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return p_new_map;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Returns the Grid Array.
|
|
Packit |
a4aae4 |
@deprecated
|
|
Packit |
a4aae4 |
@see get_array() */
|
|
Packit |
a4aae4 |
BaseType *
|
|
Packit |
a4aae4 |
Grid::array_var()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
//return d_array_var;
|
|
Packit |
a4aae4 |
// FIXME Should really test that the array has not be set; maps might be added first. jhrg 5/9/13
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
if (d_array_var)
|
|
Packit |
a4aae4 |
cerr << "In array_var(), d_array_var holds a " << d_array_var->type_name() << endl;
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
cerr << "In array_var(), d_array_var is null" << endl;
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
return d_is_array_set /*d_vars.size() > 0*/ ? *d_vars.begin() : 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Returns the Grid Array.
|
|
Packit |
a4aae4 |
This method returns the array using an Array*, so no cast is required.
|
|
Packit |
a4aae4 |
@return A pointer to the Grid's (dependent) data array */
|
|
Packit |
a4aae4 |
Array *
|
|
Packit |
a4aae4 |
Grid::get_array()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return dynamic_cast<Array*>(array_var());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Returns an iterator referencing the first Map vector. */
|
|
Packit |
a4aae4 |
Grid::Map_iter
|
|
Packit |
a4aae4 |
Grid::map_begin()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// The maps are stored in the second and subsequent elements of the
|
|
Packit |
a4aae4 |
// d_var vector<BaseType*> of Constructor _unless_ the Array part
|
|
Packit |
a4aae4 |
// has yet to be set. In the latter case, there are only maps in
|
|
Packit |
a4aae4 |
// d_vars
|
|
Packit |
a4aae4 |
return d_is_array_set/*(d_array_var != 0)*/ ? d_vars.begin() + 1: d_vars.begin();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Returns an iterator referencing the end of the list of Map vectors.
|
|
Packit |
a4aae4 |
It does not reference the last Map vector */
|
|
Packit |
a4aae4 |
Grid::Map_iter
|
|
Packit |
a4aae4 |
Grid::map_end()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_vars.end();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Returns an iterator referencing the first Map vector. */
|
|
Packit |
a4aae4 |
Grid::Map_riter
|
|
Packit |
a4aae4 |
Grid::map_rbegin()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// see above
|
|
Packit |
a4aae4 |
// return d_is_array_set/*(d_array_var != 0)*/ ? d_vars.rbegin() + 1: d_vars.rbegin();
|
|
Packit |
a4aae4 |
return d_vars.rbegin();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Returns an iterator referencing the end of the list of Map vectors.
|
|
Packit |
a4aae4 |
It does not reference the last Map vector */
|
|
Packit |
a4aae4 |
Grid::Map_riter
|
|
Packit |
a4aae4 |
Grid::map_rend()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_is_array_set ? d_vars.rend() - 1: d_vars.rend();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Return the iterator for the \e ith map.
|
|
Packit |
a4aae4 |
@param i the index
|
|
Packit |
a4aae4 |
@return The corresponding Vars_iter */
|
|
Packit |
a4aae4 |
Grid::Map_iter
|
|
Packit |
a4aae4 |
Grid::get_map_iter(int i)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// return map_begin() + i;
|
|
Packit |
a4aae4 |
return d_is_array_set ? map_begin() + 1 + i : map_begin() + i;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Returns the number of components in the Grid object. This is
|
|
Packit |
a4aae4 |
equal to one plus the number of Map vectors. If there is a
|
|
Packit |
a4aae4 |
constraint expression in effect, the number of dimensions needed
|
|
Packit |
a4aae4 |
may be smaller than the actual number in the stored data. (Or
|
|
Packit |
a4aae4 |
the Array might not even be requested.) In this case, a user can
|
|
Packit |
a4aae4 |
request the smaller number with the constrained flag.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Returns the number of components in the Grid object.
|
|
Packit |
a4aae4 |
@return The number of components in the Grid object.
|
|
Packit |
a4aae4 |
@param constrained If TRUE, the function returns the number of
|
|
Packit |
a4aae4 |
components contained in the constrained Grid. Since a
|
|
Packit |
a4aae4 |
constraint expression might well eliminate one or more of the
|
|
Packit |
a4aae4 |
Grid dimensions, this number can be lower than the actual number
|
|
Packit |
a4aae4 |
of components. If this parameter is FALSE (the default), the
|
|
Packit |
a4aae4 |
actual number of components will be returned. */
|
|
Packit |
a4aae4 |
int
|
|
Packit |
a4aae4 |
Grid::components(bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
int comp;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (constrained) {
|
|
Packit |
a4aae4 |
comp = get_array()->send_p() ? 1 : 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for (Map_iter i = map_begin(); i != map_end(); i++) {
|
|
Packit |
a4aae4 |
if ((*i)->send_p()) {
|
|
Packit |
a4aae4 |
comp++;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
comp = d_vars.size();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return comp;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void Grid::transfer_attributes(AttrTable *at_container)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - BEGIN "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// At should be the attribute table for the Grid
|
|
Packit |
a4aae4 |
AttrTable *at = at_container->get_attr_table(name());
|
|
Packit |
a4aae4 |
if (at) {
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - Found AttrTable ("<< at->get_name() << ":" << (void*)at<< ")" << endl;);
|
|
Packit |
a4aae4 |
at->set_is_global_attribute(false);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// We don't monkey with the data array attributes because it usually just makes
|
|
Packit |
a4aae4 |
// a mess. but:
|
|
Packit |
a4aae4 |
// TODO We should come back and decide if we want to but configuration
|
|
Packit |
a4aae4 |
// controls on this or do something smarter like check for duplicate values
|
|
Packit |
a4aae4 |
// before merging the Array metadata into the Grid metadata
|
|
Packit |
a4aae4 |
// SO - We don't copy the attributes like we used to:
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// array_var()->transfer_attributes(at);
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// And then to seal the deal we have to
|
|
Packit |
a4aae4 |
// Mark them as not "global" so they don't get copied.
|
|
Packit |
a4aae4 |
AttrTable *dvat = at->get_attr_table(array_var()->name());
|
|
Packit |
a4aae4 |
if(dvat){
|
|
Packit |
a4aae4 |
dvat->set_is_global_attribute(false);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Map_iter map = map_begin();
|
|
Packit |
a4aae4 |
while (map != map_end()) {
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - Processing Map Array ("<< (*map)->name() << ":" << (void*)(*map)<< ")" << endl;);
|
|
Packit |
a4aae4 |
(*map)->transfer_attributes(at);
|
|
Packit |
a4aae4 |
map++;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Trick: If an attribute that's within the container 'at' still has its
|
|
Packit |
a4aae4 |
// is_global_attribute property set, then it's not really a global attr
|
|
Packit |
a4aae4 |
// but instead an attribute that belongs to this Grid.
|
|
Packit |
a4aae4 |
AttrTable::Attr_iter at_p = at->attr_begin();
|
|
Packit |
a4aae4 |
while (at_p != at->attr_end()) {
|
|
Packit |
a4aae4 |
if (at->is_global_attribute(at_p)) {
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - " <<
|
|
Packit |
a4aae4 |
"Adding unclaimed Attribute ("<<
|
|
Packit |
a4aae4 |
at->get_type(at_p)<< ":" << at->get_name(at_p) << ":" << (void*)(*map)<<
|
|
Packit |
a4aae4 |
") from AttrTable (" << at->get_name() << ":" << (void*)at << ")" <<
|
|
Packit |
a4aae4 |
" to the variable " << type_name() << " " << name() << endl;);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (at->get_attr_type(at_p) == Attr_container)
|
|
Packit |
a4aae4 |
get_attr_table().append_container(new AttrTable(*at->get_attr_table(at_p)), at->get_name(at_p));
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
get_attr_table().append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
at_p++;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - No AttrTable named '"<< name() << "' was found in at_container ("<<at_container->get_name()<<":" << (void*)at<< ")" << endl;);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - END "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// When projected (using whatever the current constraint provides in the way
|
|
Packit |
a4aae4 |
// of a projection), is the object still a Grid?
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Returns TRUE if the current projection will yield a Grid that
|
|
Packit |
a4aae4 |
will pass the <tt>check_semantics()</tt> function. A Grid that, when
|
|
Packit |
a4aae4 |
projected, will not pass the <tt>check_semantics()</tt> function must
|
|
Packit |
a4aae4 |
be sent as either a Structure of Arrays or a single Array
|
|
Packit |
a4aae4 |
depending on the projection.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
The function first checks to see whether the Array is present.
|
|
Packit |
a4aae4 |
Then, for each dimension in the Array part, the function checks
|
|
Packit |
a4aae4 |
the corresponding Map vector to make sure it is present in the
|
|
Packit |
a4aae4 |
projected Grid. If for each projected dimension in the Array
|
|
Packit |
a4aae4 |
component, there is a matching Map vector, then the Grid is
|
|
Packit |
a4aae4 |
valid.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@return TRUE if the projected grid is still a Grid. FALSE
|
|
Packit |
a4aae4 |
otherwise.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
bool
|
|
Packit |
a4aae4 |
Grid::projection_yields_grid()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// For each dimension in the Array part, check the corresponding Map
|
|
Packit |
a4aae4 |
// vector to make sure it is present in the projected Grid. If for each
|
|
Packit |
a4aae4 |
// projected dimension in the Array component, there is a matching Map
|
|
Packit |
a4aae4 |
// vector, then the Grid is valid.
|
|
Packit |
a4aae4 |
bool valid = true;
|
|
Packit |
a4aae4 |
Array *a = get_array();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Don't bother checking if the Array component is not included.
|
|
Packit |
a4aae4 |
if (!a->send_p())
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If only one part is being sent, it's clearly not a grid (it must be
|
|
Packit |
a4aae4 |
// the array part of the Grid that's being sent (given that the above
|
|
Packit |
a4aae4 |
// test passed and the array is being sent).
|
|
Packit |
a4aae4 |
if (components(true) == 1)
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Array::Dim_iter d = a->dim_begin() ;
|
|
Packit |
a4aae4 |
Map_iter m = map_begin() ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
while (valid && d != a->dim_end() && m != map_end()) {
|
|
Packit |
a4aae4 |
Array &map = dynamic_cast<Array&>(**m);
|
|
Packit |
a4aae4 |
if (a->dimension_size(d, true) && map.send_p()) {
|
|
Packit |
a4aae4 |
// Check the matching Map vector; the Map projection must equal
|
|
Packit |
a4aae4 |
// the Array dimension projection
|
|
Packit |
a4aae4 |
Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
|
|
Packit |
a4aae4 |
valid = map.dimension_start(fd, true) == a->dimension_start(d, true)
|
|
Packit |
a4aae4 |
&& map.dimension_stop(fd, true) == a->dimension_stop(d, true)
|
|
Packit |
a4aae4 |
&& map.dimension_stride(fd, true) == a->dimension_stride(d, true);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
valid = false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d++, m++;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return valid;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** For each of the Array and Maps in this Grid, call clear_constraint(). */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Grid::clear_constraint()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
get_array()->clear_constraint();
|
|
Packit |
a4aae4 |
for (Map_iter m = map_begin(); m != map_end(); ++m)
|
|
Packit |
a4aae4 |
dynamic_cast<Array&>(*(*m)).clear_constraint();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Grid::print_decl(FILE *out, string space, bool print_semi,
|
|
Packit |
a4aae4 |
bool constraint_info, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
ostringstream oss;
|
|
Packit |
a4aae4 |
print_decl(oss, space, print_semi, constraint_info, constrained);
|
|
Packit |
a4aae4 |
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Grid::print_decl(ostream &out, string space, bool print_semi,
|
|
Packit |
a4aae4 |
bool constraint_info, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (constrained && !send_p())
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// See comment for the FILE* version of this method.
|
|
Packit |
a4aae4 |
if (constrained && !projection_yields_grid()) {
|
|
Packit |
a4aae4 |
out << space << "Structure {\n" ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
get_array()->print_decl(out, space + " ", true, constraint_info,
|
|
Packit |
a4aae4 |
constrained);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for (Map_citer i = map_begin(); i != map_end(); i++) {
|
|
Packit |
a4aae4 |
(*i)->print_decl(out, space + " ", true,
|
|
Packit |
a4aae4 |
constraint_info, constrained);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << space << "} " << id2www(name()) ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
// The number of elements in the (projected) Grid must be such that
|
|
Packit |
a4aae4 |
// we have a valid Grid object; send it as such.
|
|
Packit |
a4aae4 |
out << space << type_name() << " {\n" ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << space << " Array:\n" ;
|
|
Packit |
a4aae4 |
get_array()->print_decl(out, space + " ", true, constraint_info,
|
|
Packit |
a4aae4 |
constrained);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << space << " Maps:\n" ;
|
|
Packit |
a4aae4 |
for (Map_citer i = map_begin(); i != map_end(); i++) {
|
|
Packit |
a4aae4 |
(*i)->print_decl(out, space + " ", true,
|
|
Packit |
a4aae4 |
constraint_info, constrained);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << space << "} " << id2www(name()) ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (constraint_info) {
|
|
Packit |
a4aae4 |
if (send_p())
|
|
Packit |
a4aae4 |
out << ": Send True";
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
out << ": Send False";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (print_semi)
|
|
Packit |
a4aae4 |
out << ";\n" ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @deprecated
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Grid::print_xml(FILE *out, string space, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
XMLWriter xml(space);
|
|
Packit |
a4aae4 |
print_xml_writer(xml, constrained);
|
|
Packit |
a4aae4 |
fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @deprecated
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Grid::print_xml(ostream &out, string space, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
XMLWriter xml(space);
|
|
Packit |
a4aae4 |
print_xml_writer(xml, constrained);
|
|
Packit |
a4aae4 |
out << xml.get_doc();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
class PrintGridFieldXMLWriter : public unary_function<BaseType *, void>
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
XMLWriter &d_xml;
|
|
Packit |
a4aae4 |
bool d_constrained;
|
|
Packit |
a4aae4 |
string d_tag;
|
|
Packit |
a4aae4 |
public:
|
|
Packit |
a4aae4 |
PrintGridFieldXMLWriter(XMLWriter &x, bool c, const string &t = "Map")
|
|
Packit |
a4aae4 |
: d_xml(x), d_constrained(c), d_tag(t)
|
|
Packit |
a4aae4 |
{}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void operator()(BaseType *btp)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
Array *a = dynamic_cast<Array*>(btp);
|
|
Packit |
a4aae4 |
if (!a)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
|
|
Packit |
a4aae4 |
a->print_xml_writer_core(d_xml, d_constrained, d_tag);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
};
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Grid::print_xml_writer(XMLWriter &xml, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (constrained && !send_p())
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (constrained && !projection_yields_grid()) {
|
|
Packit |
a4aae4 |
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Structure") < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not write Structure element");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!name().empty())
|
|
Packit |
a4aae4 |
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
get_attr_table().print_xml_writer(xml);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
get_array()->print_xml_writer(xml, constrained);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for_each(map_begin(), map_end(),
|
|
Packit |
a4aae4 |
PrintGridFieldXMLWriter(xml, constrained, "Array"));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not end Structure element");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
// The number of elements in the (projected) Grid must be such that
|
|
Packit |
a4aae4 |
// we have a valid Grid object; send it as such.
|
|
Packit |
a4aae4 |
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Grid") < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not write Grid element");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!name().empty())
|
|
Packit |
a4aae4 |
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
get_attr_table().print_xml_writer(xml);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
get_array()->print_xml_writer(xml, constrained);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for_each(map_begin(), map_end(),
|
|
Packit |
a4aae4 |
PrintGridFieldXMLWriter(xml, constrained, "Map"));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not end Grid element");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Grid::print_val(FILE *out, string space, bool print_decl_p)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
ostringstream oss;
|
|
Packit |
a4aae4 |
print_val(oss, space, print_decl_p);
|
|
Packit |
a4aae4 |
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void Grid::print_val(ostream &out, string space, bool print_decl_p)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (print_decl_p) {
|
|
Packit |
a4aae4 |
print_decl(out, space, false);
|
|
Packit |
a4aae4 |
out << " = ";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If we are printing a value on the client-side, projection_yields_grid
|
|
Packit |
a4aae4 |
// should not be called since we don't *have* a projection without a
|
|
Packit |
a4aae4 |
// Constraint. I think that if we are here and send_p() is not true, then
|
|
Packit |
a4aae4 |
// the value of this function should be ignored. 4/6/2000 jhrg
|
|
Packit |
a4aae4 |
bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
|
|
Packit |
a4aae4 |
if (pyg || !send_p())
|
|
Packit |
a4aae4 |
out << "{ Array: ";
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
out << "{";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
get_array()->print_val(out, "", false);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (pyg || !send_p()) out << " Maps: ";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for (Map_citer i = map_begin(); i != map_end(); i++, (void) (i != map_end() && out << ", ")) {
|
|
Packit |
a4aae4 |
(*i)->print_val(out, "", false);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << " }";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (print_decl_p) out << ";\n";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Grids have ugly semantics.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Return true if this Grid is well formed.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
The array dimensions and number of map vectors must match and
|
|
Packit |
a4aae4 |
both the array and maps must be of simple-type elements. */
|
|
Packit |
a4aae4 |
bool
|
|
Packit |
a4aae4 |
Grid::check_semantics(string &msg, bool all)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!BaseType::check_semantics(msg))
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
msg = "";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!get_array()) {
|
|
Packit |
a4aae4 |
msg += "Null grid base array in `" + name() + "'\n";
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Is it an array?
|
|
Packit |
a4aae4 |
if (get_array()->type() != dods_array_c) {
|
|
Packit |
a4aae4 |
msg += "Grid `" + name() + "'s' member `" + get_array()->name() + "' must be an array\n";
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Array *av = (Array *)get_array(); // past test above, must be an array
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Array must be of a simple_type.
|
|
Packit |
a4aae4 |
if (!av->var()->is_simple_type()) {
|
|
Packit |
a4aae4 |
msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// enough maps?
|
|
Packit |
a4aae4 |
if ((unsigned)d_vars.size()-1 != av->dimensions()) {
|
|
Packit |
a4aae4 |
msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
|
|
Packit |
a4aae4 |
msg += av->name() + "'\n";
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
const string array_var_name = av->name();
|
|
Packit |
a4aae4 |
Array::Dim_iter asi = av->dim_begin() ;
|
|
Packit |
a4aae4 |
for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++, asi++) {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *mv = *mvi;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// check names
|
|
Packit |
a4aae4 |
if (array_var_name == mv->name()) {
|
|
Packit |
a4aae4 |
msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// check types
|
|
Packit |
a4aae4 |
if (mv->type() != dods_array_c) {
|
|
Packit |
a4aae4 |
msg += "Grid map variable `" + mv->name() + "' is not an array\n";
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Array *mv_a = (Array *)mv; // downcast to (Array *)
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Array must be of a simple_type.
|
|
Packit |
a4aae4 |
if (!mv_a->var()->is_simple_type()) {
|
|
Packit |
a4aae4 |
msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// check shape
|
|
Packit |
a4aae4 |
if (mv_a->dimensions() != 1) {// maps must have one dimension
|
|
Packit |
a4aae4 |
msg += "Grid map variable `" + mv_a->name() + "' must be only one dimension\n";
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// size of map must match corresponding array dimension
|
|
Packit |
a4aae4 |
Array::Dim_iter mv_asi = mv_a->dim_begin() ;
|
|
Packit |
a4aae4 |
int mv_a_size = mv_a->dimension_size(mv_asi) ;
|
|
Packit |
a4aae4 |
int av_size = av->dimension_size(asi) ;
|
|
Packit |
a4aae4 |
if (mv_a_size != av_size) {
|
|
Packit |
a4aae4 |
msg += "Grid map variable `" + mv_a->name() + "'s' size does not match the size of array variable '";
|
|
Packit |
a4aae4 |
msg += get_array()->name() + "'s' cooresponding dimension\n";
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (all) {
|
|
Packit |
a4aae4 |
if (!get_array()->check_semantics(msg, true))
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++) {
|
|
Packit |
a4aae4 |
if (!(*mvi)->check_semantics(msg, true)) {
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return true;
|
|
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
|
|
Packit |
a4aae4 |
Grid::dump(ostream &strm) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "Grid::dump - ("
|
|
Packit |
a4aae4 |
<< (void *)this << ")" << endl ;
|
|
Packit |
a4aae4 |
DapIndent::Indent() ;
|
|
Packit |
a4aae4 |
Constructor::dump(strm) ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DapIndent::UnIndent() ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // namespace libdap
|
|
Packit |
a4aae4 |
|