Blame Grid.cc

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