Grid.cc
// -*- mode: c++; c-basic-offset:4 -*-
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.
// Copyright (c) 2002,2003 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
// (c) COPYRIGHT URI/MIT 1994-1999
// Please read the full copyright statement in the file COPYRIGHT_URI.
//
// Authors:
// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
// implementation for Grid.
//
// jhrg 9/15/94
#include "config.h"
#include <sstream>
#include <functional>
#include <algorithm>
#include "Grid.h"
#include "DDS.h"
#include "Array.h" // for downcasts
#include "util.h"
#include "InternalErr.h"
#include "escaping.h"
#include "XDRStreamMarshaller.h"
#include "debug.h"
#include "XMLWriter.h"
#include "DMR.h"
#include "D4Group.h"
#include "D4Maps.h"
#include "D4Attributes.h"
#include "DapIndent.h"
using namespace std;
namespace libdap {
void
Grid::m_duplicate(const Grid &s)
{
d_is_array_set = s.d_is_array_set;
}
Grid::Grid(const string &n) : Constructor(n, dods_grid_c), d_is_array_set(false)
{}
Grid::Grid(const string &n, const string &d)
: Constructor(n, d, dods_grid_c), d_is_array_set(false)
{}
Grid::Grid(const Grid &rhs) : Constructor(rhs)
{
m_duplicate(rhs);
}
Grid::~Grid()
{
//d_array_var = 0; // Weak pointer; object will be freed by Constructor
}
BaseType *
Grid::ptr_duplicate()
{
return new Grid(*this);
}
Grid &
Grid::operator=(const Grid &rhs)
{
if (this == &rhs)
return *this;
Constructor::operator=(rhs);
m_duplicate(rhs);
return *this;
}
void
Grid::transform_to_dap4(D4Group *root, Constructor *container)
{
DBG(cerr << __func__ << "() - BEGIN (name:"<< name() <<
")(type:"<< type_name()<<
")(root:'"<< root->name()<<"':"<<(void*)root <<
")(container:'"<< container->name()<<"':"<< (void *) container<< ")"
<< endl;);
vector<Array*> d4_map_arrays;
// We do the Map Arrays first because some people expect to see them
// declared prior to the coverage array the utilizes them - even though that
// is not a requirement of DAP4 I did it here to make people happier.
// We add the maps arrays to the current container if needed and make a
// vector of them so that we can add D4Map objects to our Precious down
// below.
for (Map_iter i = map_begin(), e = map_end(); i != e; ++i) {
DBG(cerr << __func__ << "() - Processing Map Array: '"<< (*i)->name() << "' ("<< (void *)(*i)<< ")" << endl;);
// Only add the map/array if it's not already present in the target DAP2 container.
// Given the scoping rules for DAP2 and the assumption the DDS is valid, testing for
// the same name is good enough. The point here is to be sure to only use the
// existing maps. This is an important issue when there are multiple Grids in the same
// dataset that utilize the same Map arrays data.
Array *the_map_array;
Array *container_map_array = static_cast<Array*>(container->var((*i)->name()));
if(!container_map_array){
DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the current DAP4 container ("<<container->name()<< ":"<<(void*)container<< "). Let's fix that..." << endl;);
// Not in the container, so we check root group
Array *root_map_array = static_cast<Array*>(root->var((*i)->name()));
if (!root_map_array) {
// Not in the root group so we transform a new array and add it to container.
DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the root Group ("<<root->name()<< ":"<<(void*)root<< "). Let's fix that..." << endl;);
// transform it and add it to the container
(*i)->transform_to_dap4(root, container);
// Recover the new dap4 version from the container.
the_map_array = static_cast<Array*>(container->var((*i)->name()));
DBG(cerr << __func__ << "() - Transformed array '"<< the_map_array->name() <<
"' to DAP4 Array (" << (void *) the_map_array << ") added to container: '"<<
container->name() <<"'" << endl;);
}
else {
the_map_array = root_map_array;
DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' (" <<
(void *) the_map_array << ") present in the root group ("<<root->name()<< ":"<<(void*)root <<
")"<< endl;);
}
}
else {
the_map_array = container_map_array;
DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' (" <<
(void *) the_map_array << ") present in the current DAP4 container ("<<container->name( )<< ":"<<
(void*)container<< ")" << endl;);
}
// We'll use these (below) to make D4Map objects for the coverage
d4_map_arrays.push_back(the_map_array);
}
// Adds the coverage array to the container.
array_var()->transform_to_dap4(root, container);
// Get the new coverage array
BaseType *btp = container->var(array_var()->name());
Array *coverage = static_cast<Array*>(btp);
DBG(cerr << __func__ << "() - Transformed and added DAP4 coverage Array '"<< coverage->name() <<
"' to parent container: '" << container->name() << "'" << endl;);
coverage->attributes()->transform_to_dap4(get_attr_table());
DBG(cerr << __func__ << "() - " << "Coverage Array '"<< coverage->name() << "' attributes: " << endl;
XMLWriter xmlw;
coverage->get_attr_table().print_dap4(xmlw);
cerr << xmlw.get_doc() << endl;);
// Add the D4Maps
vector<Array*>::iterator d4aItr=d4_map_arrays.begin();
vector<Array*>::iterator end=d4_map_arrays.end();
for( ; d4aItr!=end ; d4aItr++){
Array *the_map_array = *d4aItr;
// Here we use the Map Array that we saved the Map
// name and Map Array reference for our map.
// Removed this line in favor of the following one while re-working the D4Maps design.
// jhrg 9/16/22
// D4Map *d4_map = new D4Map(the_map_array->FQN(), the_map_array, coverage); // bind the 'map' to the coverage
D4Map *d4_map = new D4Map(the_map_array->FQN(), the_map_array);
coverage->maps()->add_map(d4_map); // bind the coverage to the map
// Clear the vector entry to ensure that ~Array doesn't
// get called when the (stack declared) vector goes out of scope.
*d4aItr = 0;
DBG(cerr << __func__ << "() - Added DAP4 Map Array: '"<< d4_map->name() <<
"' (" << (void *) d4_map->array() << ") to coverage: '" << coverage->name() << "'" << endl;);
}
DBG(cerr << __func__ << "() - END (grid:" << name() << ")" << endl;);
}
bool
Grid::is_dap2_only_type()
{
return true;
}
void
Grid::add_var(BaseType *bt, Part part)
{
if (!bt)
throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
if (bt->is_dap4())
throw Error(string("A method usable only with DAP2 variables was called on a DAP4 variable (").append(name()).append(")."), __FILE__, __LINE__);
if (part == array && d_is_array_set/*get_array()*/) {
// Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
}
// avoid obvious broken semantics
if (!dynamic_cast<Array*>(bt)) {
throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
}
// Set to the clone of bt if we get that far.
BaseType* bt_clone = 0;
switch (part) {
case array: {
// Add it as a copy to preserve old semantics. This sets parent too.
bt_clone = bt->ptr_duplicate();
set_array(static_cast<Array*>(bt_clone));
}
break;
case maps: {
bt_clone = bt->ptr_duplicate();
bt_clone->set_parent(this);
d_vars.push_back(bt_clone);
}
break;
default: {
if (!d_is_array_set) {
// Add it as a copy to preserve old semantics. This sets parent too.
bt_clone = bt->ptr_duplicate();
set_array(static_cast<Array*>(bt_clone));
}
else {
bt_clone = bt->ptr_duplicate();
bt_clone->set_parent(this);
d_vars.push_back(bt_clone);
}
}
break;
}
}
void
Grid::add_var_nocopy(BaseType *bt, Part part)
{
if (!bt)
throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
if (bt->is_dap4())
throw Error(string("A method usable only with DAP2 variables was called on a DAP4 variable (").append(name()).append(")."), __FILE__, __LINE__);
if (part == array && d_is_array_set/*get_array()*/) {
// Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
}
// avoid obvious broken semantics
if (!dynamic_cast<Array*>(bt)) {
throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
}
bt->set_parent(this);
switch (part) {
case array: {
// Refactored to use new set_array ([mjohnson 11 nov 2009])
set_array(static_cast<Array*>(bt));
}
break;
case maps: {
// FIXME Why is this commented out?
//bt->set_parent(this);
d_vars.push_back(bt);
}
break;
default: {
if (!d_is_array_set) {
// Refactored to use new set_array ([mjohnson 11 nov 2009])
// avoid obvious broken semantics
set_array(static_cast<Array*>(bt));
}
else {
d_vars.push_back(bt);
}
}
break;
}
}
void Grid::set_array(Array* p_new_arr)
{
if (!p_new_arr) {
throw InternalErr(__FILE__, __LINE__, "Grid::set_array(): Cannot set to null!");
}
// Make sure not same memory, this would be evil.
if (p_new_arr == get_array()) {
return;
}
p_new_arr->set_parent(this);
// Three cases: 1. There are no variables set for this grid at all
// 2. There are maps but no array
// 3. There is already an array set (and maybe maps).
// NB: d_array_var is a weak pointer to the Grid's Array
if (d_vars.size() == 0) {
d_vars.push_back(p_new_arr);
}
else if (!d_is_array_set) {
d_vars.insert(d_vars.begin(), p_new_arr);
}
else {
// clean out old array
delete get_array();
d_vars[0] = p_new_arr;
}
d_is_array_set = true;
#if 0
// store the array pointer locally
d_array_var = p_new_arr;
// Set the parent
d_array_var->set_parent(this);
#endif
}
Array*
Grid::add_map(Array* p_new_map, bool add_as_copy)
{
if (!p_new_map)
throw InternalErr(__FILE__, __LINE__, "Grid::add_map(): cannot have p_new_map null!");
if (add_as_copy)
p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
p_new_map->set_parent(this);
d_vars.push_back(p_new_map);
// return the one that got put into the Grid.
return p_new_map;
}
Array*
Grid::prepend_map(Array* p_new_map, bool add_copy)
{
if (add_copy)
{
p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
}
p_new_map->set_parent(this);
d_vars.insert(map_begin(), p_new_map);
return p_new_map;
}
BaseType *
Grid::array_var()
{
return d_is_array_set ? *d_vars.begin() : nullptr;
}
Array *
Grid::get_array()
{
return dynamic_cast<Array*>(array_var());
}
Grid::Map_iter
Grid::map_begin()
{
// The maps are stored in the second and subsequent elements of the
// d_var vector<BaseType*> of Constructor _unless_ the Array part
// has yet to be set. In the latter case, there are only maps in
// d_vars
return d_is_array_set ? d_vars.begin() + 1: d_vars.begin();
}
Grid::Map_iter
Grid::map_end()
{
return d_vars.end();
}
Grid::Map_riter
Grid::map_rbegin()
{
// see above
return d_vars.rbegin();
}
Grid::Map_riter
Grid::map_rend()
{
return d_is_array_set ? d_vars.rend() - 1: d_vars.rend();
}
Grid::Map_iter
Grid::get_map_iter(int i)
{
return d_is_array_set ? d_vars.begin() + 1 + i : d_vars.begin() + i;
}
int
Grid::components(bool constrained)
{
int comp;
if (constrained) {
comp = get_array()->send_p() ? 1 : 0;
for (Map_iter i = map_begin(); i != map_end(); i++) {
if ((*i)->send_p()) {
comp++;
}
}
}
else {
comp = d_vars.size();
}
return comp;
}
void Grid::transfer_attributes(AttrTable *at_container)
{
DBG( cerr << __func__ << "() - BEGIN "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
// The variable 'at' should be the attribute table for the Grid
AttrTable *at = at_container->get_attr_table(name());
if (at) {
DBG( cerr << __func__ << "() - Found AttrTable ("<< at->get_name() << ":" << (void*)at<< ")" << endl;);
at->set_is_global_attribute(false);
#if 0
// Removing this is left over from a previous version, unknown date.
// If the line is added back, some of the DMR round trip tests fail
// and the dapreader behavior is changed - tests that build responses
// from .dods and .das files fail when they include Grids. jhrg 5/23/18
//
// See also HYARX-766
array_var()->transfer_attributes(at);
#endif
// If the AttrTable with the name of this Grid (which is also the
// name of the Grid's Array) contains a child AttrTable with that
// name, mark the attributes as 'not global' and ignore them. This
// code has been here for some time; I just added this comment. jhrg 5/23/18
AttrTable *dvat = at->get_attr_table(array_var()->name());
if (dvat) {
dvat->set_is_global_attribute(false);
}
Map_iter map = map_begin();
while (map != map_end()) {
(*map)->transfer_attributes(at);
map++;
}
// Trick: If an attribute that's within the container 'at' still has its
// is_global_attribute property set, then it's not really a global attr
// but instead an attribute that belongs to this Grid.
AttrTable::Attr_iter at_p = at->attr_begin();
while (at_p != at->attr_end()) {
if (at->is_global_attribute(at_p)) {
DBG( cerr << __func__ << "() - " <<
"Adding unclaimed Attribute ("<<
at->get_type(at_p)<< ":" << at->get_name(at_p) << ":" << (void*)(*map)<<
") from AttrTable (" << at->get_name() << ":" << (void*)at << ")" <<
" to the variable " << type_name() << " " << name() << endl;);
if (at->get_attr_type(at_p) == Attr_container)
get_attr_table().append_container(new AttrTable(*at->get_attr_table(at_p)), at->get_name(at_p));
else
get_attr_table().append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p),(*at_p)->is_utf8_str);
}
at_p++;
}
}
else {
DBG( cerr << __func__ << "() - No AttrTable named '"<< name() << "' was found in at_container ("<<at_container->get_name()<<":" << (void*)at<< ")" << endl;);
}
DBG( cerr << __func__ << "() - END "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
}
// When projected (using whatever the current constraint provides in the way
// of a projection), is the object still a Grid?
bool
Grid::projection_yields_grid()
{
// For each dimension in the Array part, check the corresponding Map
// vector to make sure it is present in the projected Grid. If for each
// projected dimension in the Array component, there is a matching Map
// vector, then the Grid is valid.
bool valid = true;
Array *a = get_array();
// Don't bother checking if the Array component is not included.
if (!a->send_p())
return false;
// If only one part is being sent, it's clearly not a grid (it must be
// the array part of the Grid that's being sent (given that the above
// test passed and the array is being sent).
if (components(true) == 1)
return false;
Array::Dim_iter d = a->dim_begin() ;
Map_iter m = map_begin() ;
while (valid && d != a->dim_end() && m != map_end()) {
Array &map = dynamic_cast<Array&>(**m);
if (a->dimension_size(d, true) && map.send_p()) {
// Check the matching Map vector; the Map projection must equal
// the Array dimension projection
Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
valid = map.dimension_start(fd, true) == a->dimension_start(d, true)
&& map.dimension_stop(fd, true) == a->dimension_stop(d, true)
&& map.dimension_stride(fd, true) == a->dimension_stride(d, true);
}
else {
valid = false;
}
d++, m++;
}
return valid;
}
void
Grid::clear_constraint()
{
get_array()->clear_constraint();
for (Map_iter m = map_begin(); m != map_end(); ++m)
dynamic_cast<Array&>(*(*m)).clear_constraint();
}
void
Grid::print_decl(FILE *out, string space, bool print_semi,
bool constraint_info, bool constrained)
{
ostringstream oss;
print_decl(oss, space, print_semi, constraint_info, constrained);
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
}
void
Grid::print_decl(ostream &out, string space, bool print_semi,
bool constraint_info, bool constrained)
{
if (constrained && !send_p())
return;
// See comment for the FILE* version of this method.
if (constrained && !projection_yields_grid()) {
out << space << "Structure {\n" ;
get_array()->print_decl(out, space + " ", true, constraint_info,
constrained);
for (Map_citer i = map_begin(); i != map_end(); i++) {
(*i)->print_decl(out, space + " ", true,
constraint_info, constrained);
}
out << space << "} " << id2www(name()) ;
}
else {
// The number of elements in the (projected) Grid must be such that
// we have a valid Grid object; send it as such.
out << space << type_name() << " {\n" ;
out << space << " Array:\n" ;
get_array()->print_decl(out, space + " ", true, constraint_info,
constrained);
out << space << " Maps:\n" ;
for (Map_citer i = map_begin(); i != map_end(); i++) {
(*i)->print_decl(out, space + " ", true,
constraint_info, constrained);
}
out << space << "} " << id2www(name()) ;
}
if (constraint_info) {
if (send_p())
out << ": Send True";
else
out << ": Send False";
}
if (print_semi)
out << ";\n" ;
return;
}
void
Grid::print_xml(FILE *out, string space, bool constrained)
{
XMLWriter xml(space);
print_xml_writer(xml, constrained);
fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
}
void
Grid::print_xml(ostream &out, string space, bool constrained)
{
XMLWriter xml(space);
print_xml_writer(xml, constrained);
out << xml.get_doc();
}
class PrintGridFieldXMLWriter : public unary_function<BaseType *, void>
{
XMLWriter &d_xml;
bool d_constrained;
string d_tag;
public:
PrintGridFieldXMLWriter(XMLWriter &x, bool c, const string &t = "Map")
: d_xml(x), d_constrained(c), d_tag(t)
{}
void operator()(BaseType *btp)
{
Array *a = dynamic_cast<Array*>(btp);
if (!a)
throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
a->print_xml_writer_core(d_xml, d_constrained, d_tag);
}
};
void
Grid::print_xml_writer(XMLWriter &xml, bool constrained)
{
if (constrained && !send_p())
return;
if (constrained && !projection_yields_grid()) {
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Structure") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write Structure element");
if (!name().empty())
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
get_attr_table().print_xml_writer(xml);
get_array()->print_xml_writer(xml, constrained);
for_each(map_begin(), map_end(),
PrintGridFieldXMLWriter(xml, constrained, "Array"));
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end Structure element");
}
else {
// The number of elements in the (projected) Grid must be such that
// we have a valid Grid object; send it as such.
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Grid") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write Grid element");
if (!name().empty())
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
get_attr_table().print_xml_writer(xml);
get_array()->print_xml_writer(xml, constrained);
for_each(map_begin(), map_end(),
PrintGridFieldXMLWriter(xml, constrained, "Map"));
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end Grid element");
}
}
void
Grid::print_val(FILE *out, string space, bool print_decl_p)
{
ostringstream oss;
print_val(oss, space, print_decl_p);
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
}
void Grid::print_val(ostream &out, string space, bool print_decl_p)
{
if (print_decl_p) {
print_decl(out, space, false);
out << " = ";
}
// If we are printing a value on the client-side, projection_yields_grid
// should not be called since we don't *have* a projection without a
// Constraint. I think that if we are here and send_p() is not true, then
// the value of this function should be ignored. 4/6/2000 jhrg
bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
if (pyg || !send_p())
out << "{ Array: ";
else
out << "{";
get_array()->print_val(out, "", false);
if (pyg || !send_p()) out << " Maps: ";
for (Map_citer i = map_begin(); i != map_end(); i++, (void) (i != map_end() && out << ", ")) {
(*i)->print_val(out, "", false);
}
out << " }";
if (print_decl_p) out << ";\n";
}
// Grids have ugly semantics.
bool
Grid::check_semantics(string &msg, bool all)
{
if (!BaseType::check_semantics(msg))
return false;
msg = "";
if (!get_array()) {
msg += "Null grid base array in `" + name() + "'\n";
return false;
}
// Is it an array?
if (get_array()->type() != dods_array_c) {
msg += "Grid `" + name() + "'s' member `" + get_array()->name() + "' must be an array\n";
return false;
}
Array *av = (Array *)get_array(); // past test above, must be an array
// Array must be of a simple_type.
if (!av->var()->is_simple_type()) {
msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
return false;
}
// enough maps?
if ((unsigned)d_vars.size()-1 != av->dimensions()) {
msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
msg += av->name() + "'\n";
return false;
}
const string array_var_name = av->name();
Array::Dim_iter asi = av->dim_begin() ;
for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++, asi++) {
BaseType *mv = *mvi;
// check names
if (array_var_name == mv->name()) {
msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
return false;
}
// check types
if (mv->type() != dods_array_c) {
msg += "Grid map variable `" + mv->name() + "' is not an array\n";
return false;
}
Array *mv_a = (Array *)mv; // downcast to (Array *)
// Array must be of a simple_type.
if (!mv_a->var()->is_simple_type()) {
msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
return false;
}
// check shape
if (mv_a->dimensions() != 1) {// maps must have one dimension
msg += "Grid map variable `" + mv_a->name() + "' must be only one dimension\n";
return false;
}
// size of map must match corresponding array dimension
Array::Dim_iter mv_asi = mv_a->dim_begin() ;
int mv_a_size = mv_a->dimension_size(mv_asi) ;
int av_size = av->dimension_size(asi) ;
if (mv_a_size != av_size) {
msg += "Grid map variable `" + mv_a->name() + "'s' size does not match the size of array variable '";
msg += get_array()->name() + "'s' cooresponding dimension\n";
return false;
}
}
if (all) {
if (!get_array()->check_semantics(msg, true))
return false;
for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++) {
if (!(*mvi)->check_semantics(msg, true)) {
return false;
}
}
}
return true;
}
void
Grid::dump(ostream &strm) const
{
strm << DapIndent::LMarg << "Grid::dump - ("
<< (void *)this << ")" << endl ;
DapIndent::Indent() ;
Constructor::dump(strm) ;
DapIndent::UnIndent() ;
}
} // namespace libdap
libdap::Array
A multidimensional array of identical data types.
Definition Array.h:123
libdap::Array::dimension_start
virtual int dimension_start(Dim_iter i, bool constrained=false)
Return the start index of a dimension.
Definition Array.cc:849
libdap::Array::clear_constraint
virtual void clear_constraint()
Clears the projection; add each projected dimension explicitly using add_constraint.
Definition Array.cc:639
libdap::Array::dim_end
Dim_iter dim_end()
Definition Array.cc:768
libdap::Array::dimension_stop
virtual int dimension_stop(Dim_iter i, bool constrained=false)
Return the stop index of the constraint.
Definition Array.cc:876
libdap::Array::print_decl
void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false) override
Prints a DDS entry for the Array.
Definition Array.cc:1163
libdap::Array::print_val
void print_val(ostream &out, string space="", bool print_decl_p=true) override
Prints the value of the variable.
Definition Array.cc:1395
libdap::Array::ptr_duplicate
BaseType * ptr_duplicate() override
Definition Array.cc:181
libdap::Array::Dim_iter
std::vector< dimension >::iterator Dim_iter
Definition Array.h:241
libdap::Array::dimension_size
virtual int dimension_size(Dim_iter i, bool constrained=false)
Returns the size of the dimension.
Definition Array.cc:805
libdap::Array::print_xml_writer
void print_xml_writer(XMLWriter &xml, bool constrained=false) override
Definition Array.cc:1248
libdap::Array::dim_begin
Dim_iter dim_begin()
Definition Array.cc:762
libdap::Array::dimensions
virtual unsigned int dimensions(bool constrained=false)
Return the total number of dimensions in the array.
Definition Array.cc:783
libdap::Array::dimension_stride
virtual int dimension_stride(Dim_iter i, bool constrained=false)
Returns the stride value of the constraint.
Definition Array.cc:904
libdap::AttrTable
Contains the attributes for a dataset.
Definition AttrTable.h:154
libdap::AttrTable::append_container
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition AttrTable.cc:554
libdap::AttrTable::get_attr_table
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition AttrTable.cc:751
libdap::AttrTable::append_attr
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition AttrTable.cc:335
libdap::AttrTable::print_dap4
void print_dap4(XMLWriter &xml)
Definition AttrTable.cc:1703
libdap::AttrTable::get_name
virtual string get_name() const
Get the name of this attribute table.
Definition AttrTable.cc:266
libdap::AttrTable::print_xml_writer
void print_xml_writer(XMLWriter &xml)
Definition AttrTable.cc:1614
libdap::BaseType
The basic data type for the DODS DAP types.
Definition BaseType.h:120
libdap::BaseType::type_name
virtual string type_name() const
Returns the type of the class instance as a string.
Definition BaseType.cc:376
libdap::BaseType::get_attr_table
virtual AttrTable & get_attr_table()
Definition BaseType.cc:579
libdap::BaseType::name
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:317
libdap::BaseType::set_parent
virtual void set_parent(BaseType *parent)
Definition BaseType.cc:730
libdap::BaseType::attributes
virtual D4Attributes * attributes()
Definition BaseType.cc:596
libdap::BaseType::FQN
virtual std::string FQN() const
Definition BaseType.cc:329
libdap::BaseType::send_p
virtual bool send_p()
Should this variable be sent?
Definition BaseType.cc:551
libdap::BaseType::is_simple_type
virtual bool is_simple_type() const
Returns true if the instance is a numeric, string or URL type variable.
Definition BaseType.cc:390
libdap::BaseType::ptr_duplicate
virtual BaseType * ptr_duplicate()=0
libdap::BaseType::transform_to_dap4
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition BaseType.cc:212
libdap::BaseType::transfer_attributes
virtual void transfer_attributes(AttrTable *at)
Definition BaseType.cc:641
libdap::BaseType::check_semantics
virtual bool check_semantics(string &msg, bool all=false)
Compare an object's current state with the semantics of its type.
Definition BaseType.cc:1215
libdap::BaseType::type
virtual Type type() const
Returns the type of the class instance.
Definition BaseType.cc:362
libdap::Constructor
Definition Constructor.h:44
libdap::Constructor::var
BaseType * var(const string &name, bool exact_match=true, btp_stack *s=nullptr) override
btp_stack no longer needed; use back pointers (BaseType::get_parent())
Definition Constructor.cc:210
libdap::Constructor::dump
void dump(ostream &strm) const override
dumps information about this object
Definition Constructor.cc:845
libdap::D4Attributes::transform_to_dap4
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
Definition D4Attributes.cc:197
libdap::D4Group
Definition D4Group.h:44
libdap::D4Map
Definition D4Maps.h:71
libdap::D4Map::array
Array * array(D4Group *root)
This will always return the correct pointer for a valid data set.
Definition D4Maps.cc:36
libdap::D4Maps::add_map
void add_map(D4Map *map)
Definition D4Maps.h:159
libdap::Error
A class for error processing.
Definition Error.h:94
libdap::Grid
Holds the Grid data type.
Definition Grid.h:123
libdap::Grid::ptr_duplicate
virtual BaseType * ptr_duplicate()
Definition Grid.cc:108
libdap::Grid::array_var
BaseType * array_var()
Returns the Grid Array.
Definition Grid.cc:489
libdap::Grid::transform_to_dap4
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition Grid.cc:127
libdap::Grid::print_xml
virtual void print_xml(ostream &out, string space=" ", bool constrained=false)
Definition Grid.cc:797
libdap::Grid::map_begin
Map_iter map_begin()
Returns an iterator referencing the first Map vector.
Definition Grid.cc:505
libdap::Grid::get_map_iter
Map_iter get_map_iter(int i)
Definition Grid.cc:542
libdap::Grid::set_array
virtual void set_array(Array *p_new_arr)
Definition Grid.cc:377
libdap::Grid::clear_constraint
virtual void clear_constraint()
Definition Grid.cc:714
libdap::Grid::print_val
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition Grid.cc:878
libdap::Grid::print_decl
virtual void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Print an ASCII representation of the variable structure.
Definition Grid.cc:731
libdap::Grid::prepend_map
virtual Array * prepend_map(Array *p_new_map, bool add_copy)
Definition Grid.cc:472
libdap::Grid::Grid
Grid(const string &n)
The Grid constructor.
Definition Grid.cc:78
libdap::Grid::get_array
Array * get_array()
Returns the Grid Array. This method returns the array using an Array*, so no cast is required.
Definition Grid.cc:498
libdap::Grid::transfer_attributes
virtual void transfer_attributes(AttrTable *at_container)
Definition Grid.cc:588
libdap::Grid::projection_yields_grid
virtual bool projection_yields_grid()
Definition Grid.cc:670
libdap::Grid::map_end
Map_iter map_end()
Definition Grid.cc:517
libdap::Grid::map_rend
Map_riter map_rend()
Definition Grid.cc:533
libdap::Grid::dump
virtual void dump(ostream &strm) const
dumps information about this object
Definition Grid.cc:1011
libdap::Grid::add_map
virtual Array * add_map(Array *p_new_map, bool add_copy)
Definition Grid.cc:443
libdap::Grid::components
virtual int components(bool constrained=false)
Returns the number of components in the Grid object.
Definition Grid.cc:563
libdap::Grid::print_xml_writer
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition Grid.cc:825
libdap::Grid::check_semantics
virtual bool check_semantics(string &msg, bool all=false)
Return true if this Grid is well formed.
Definition Grid.cc:915
libdap::Grid::add_var
virtual void add_var(BaseType *bt, Part part)
Definition Grid.cc:246
libdap::Grid::add_var_nocopy
virtual void add_var_nocopy(BaseType *bt, Part part)
Definition Grid.cc:315
libdap::Grid::map_rbegin
Map_riter map_rbegin()
Returns an iterator referencing the first Map vector.
Definition Grid.cc:524
libdap::Grid::is_dap2_only_type
virtual bool is_dap2_only_type()
Definition Grid.cc:228
libdap::InternalErr
A class for software fault reporting.
Definition InternalErr.h:65
libdap::Vector::var
BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=nullptr) override
Definition Vector.cc:486
libdap::XMLWriter
Definition XMLWriter.h:39
libdap
top level DAP object to house generic methods
Definition AlarmHandler.h:36
libdap::Part
Part
Names the parts of multi-section constructor data types.
Definition Type.h:48
libdap::id2www
string id2www(string in, const string &allowable)
Definition escaping.cc:153