Array.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 Array.
//
// jhrg 9/13/94
#include "config.h"
// #define DODS_DEBUG
#include <algorithm>
#include <functional>
#include <sstream>
#include "Array.h"
#include "Grid.h"
#include "D4Attributes.h"
#include "DMR.h"
#include "D4Dimensions.h"
#include "D4Maps.h"
#include "D4Group.h"
#include "D4EnumDefs.h"
#include "D4Enum.h"
#include "XMLWriter.h"
#include "util.h"
#include "debug.h"
#include "InternalErr.h"
#include "escaping.h"
using namespace std;
namespace libdap {
Array::dimension::dimension(D4Dimension *d) : dim(d), use_sdim_for_slice(true)
{
size = d->size();
name = d->name();
start = 0;
stop = size - 1;
stride = 1;
c_size = size;
}
void
Array::_duplicate(const Array &a)
{
_shape = a._shape;
// Deep copy the Maps if they are being used.
if (a.d_maps) {
d_maps = new D4Maps(*(a.d_maps));
}
else {
d_maps = 0;
}
// d_maps = a.d_maps ? new D4Maps(*(a.d_maps)) : 0;
}
// The first method of calculating length works when only one dimension is
// constrained and you want the others to appear in total. This is important
// when selecting from grids since users may not select from all dimensions
// in which case that means they want the whole thing. Array projection
// should probably work this way too, but it doesn't. 9/21/2001 jhrg
void
Array::update_length(int)
{
int length = 1;
for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
#if 0
// If the size of any dimension is zero, then the array is not
// capable of storing any values. jhrg 1/28/16
length *= (*i).c_size > 0 ? (*i).c_size : 1;
#endif
length *= (*i).c_size;
}
set_length(length);
}
// Construct an instance of Array. The (BaseType *) is assumed to be
// allocated using new - The dtor for Vector will delete this object.
Array::Array(const string &n, BaseType *v, bool is_dap4 /* default:false */)
: Vector(n, 0, dods_array_c, is_dap4), d_maps(0)
{
add_var(v); // Vector::add_var() stores null if v is null
}
Array::Array(const string &n, const string &d, BaseType *v, bool is_dap4 /* default:false */)
: Vector(n, d, 0, dods_array_c, is_dap4), d_maps(0)
{
add_var(v); // Vector::add_var() stores null if v is null
}
Array::Array(const Array &rhs) : Vector(rhs)
{
_duplicate(rhs);
}
Array::~Array()
{
delete d_maps;
}
BaseType *
Array::ptr_duplicate()
{
return new Array(*this);
}
Array &
Array::operator=(const Array &rhs)
{
if (this == &rhs)
return *this;
dynamic_cast<Vector &>(*this) = rhs;
_duplicate(rhs);
return *this;
}
void
Array::transform_to_dap4(D4Group *root, Constructor *container)
{
DBG(cerr << __func__ << "() - BEGIN (array:" << name() << ")" << endl;);
Array *dest = static_cast<Array*>(ptr_duplicate());
// If it's already a DAP4 object then we can just return it!
if(is_dap4()){
DBG(cerr << __func__ << "() - Already DAP4 type: Just making a copy and adding to container. " << endl;);
container->add_var_nocopy(dest);
DBG(cerr << __func__ << "() - END (Already DAP4 type)" << endl;);
}
// Process the Array's dimensions, making D4 shared dimensions for
// D2 dimensions that are named. If there is just a size, don't make
// a D4Dimension (In DAP4 you cannot share a dimension unless it has
// a name). jhrg 3/18/14
D4Dimensions *root_dims = root->dims();
for (Array::Dim_iter dap2_dim = dest->dim_begin(), e = dest->dim_end(); dap2_dim != e; ++dap2_dim) {
if (!(*dap2_dim).name.empty()) {
DBG(cerr << __func__ << "() - Processing the array dimension '" << (*dap2_dim).name << "'" << endl;);
// If a D4Dimension with the name already exists, use it.
D4Dimension *d4_dim = root_dims->find_dim((*dap2_dim).name);
if (!d4_dim) {
d4_dim = new D4Dimension((*dap2_dim).name, (*dap2_dim).size);
root_dims->add_dim_nocopy(d4_dim);
DBG(cerr << __func__ << "() -" <<
" Added NEW D4Dimension '"<< d4_dim->name() << "' (" <<
(void *)d4_dim << ") to root->dims()"<< endl;);
}
else {
DBG(cerr << __func__ << "() -" <<
" Using Existing D4Dimension '"<< d4_dim->name() << "' (" <<
(void *)d4_dim << ")"<< endl;);
if (d4_dim->size() != (unsigned long) (*dap2_dim).size) {
// TODO Revisit this decision. jhrg 3/18/14
// ...in case the name/size are different, make a unique D4Dimension
// but don't fiddle with the name. Not sure I like this idea, so I'm
// making the case explicit (could be rolled in to the block above).
// jhrg 3/18/14
//
// This is causing problems in the FITS handler because there are cases
// where two arrays have dimensions with the same name but different
// sizes. The deserializing code is using the first size listed, which is
// wrong in some cases. I'm going to try making this new D4Dimension using
// the dim name along with the variable name. jhrg 8/15/14
d4_dim = new D4Dimension((*dap2_dim).name + "_" + name(), (*dap2_dim).size);
DBG(cerr << __func__ << "() -" <<
" Utilizing Name/Size Conflict Naming Artifice. name'"<< d4_dim->name() << "' (" <<
(void *)d4_dim << ")"<< endl;);
root_dims->add_dim_nocopy(d4_dim);
}
}
// At this point d4_dim's name and size == those of (*d) so just set
// the D4Dimension pointer so it matches the one in the D4Group.
(*dap2_dim).dim = d4_dim;
}
}
// Copy the D2 attributes to D4 Attributes
dest->attributes()->transform_to_dap4(get_attr_table());
dest->set_is_dap4(true);
container->add_var_nocopy(dest);
DBG(cerr << __func__ << "() - END (array:" << name() << ")" << endl;);
}
bool Array::is_dap2_grid(){
bool is_grid = false;
if(this->is_dap4()){
DBG( cerr << __func__ << "() - Array '"<< name() << "' is DAP4 object!" << endl;)
D4Maps *d4_maps = this->maps();
is_grid = d4_maps->size(); // It can't be a grid if there are no maps...
if(is_grid){
DBG( cerr << __func__ << "() - Array '"<< name() << "' has D4Maps." << endl;)
// hmmm this might be a DAP2 Grid...
D4Maps::D4MapsIter i = d4_maps->map_begin();
D4Maps::D4MapsIter e = d4_maps->map_end();
while(i!=e){
DBG( cerr << __func__ << "() - Map '"<< (*i)->array()->name() << " has " << (*i)->array()->_shape.size() << " dimension(s)." << endl;)
if((*i)->array()->_shape.size() > 1){
is_grid = false;
i = e;
}
else {
i++;
}
}
}
else {
DBG( cerr << __func__ << "() - Array '"<< name() << "' has no D4Maps." << endl;)
}
}
DBG( cerr << __func__ << "() - is_grid: "<< (is_grid?"true":"false") << endl;)
return is_grid;
}
std::vector<BaseType *> *
Array::transform_to_dap2(AttrTable *){
DBG(cerr << __func__ << "() - BEGIN Array '"<< name() << "'" << endl;);
BaseType *dest;
if(is_dap4()){ // Don't convert a DAP2 thing
// Can Precious be represented as a DAP2 Grid
if(is_dap2_grid()){
// Oh yay! Grids are special.
DBG(cerr << __func__ << "() - Array '"<< name() << "' is dap2 Grid!" << endl;);
Grid *g = new Grid(name());
dest = g;
Array *grid_array = (Array *) this->ptr_duplicate();
g->set_array(grid_array);
// Get the metadata into the Grid
AttrTable *grid_attrs = attributes()->get_AttrTable(name());
g->set_attr_table(*grid_attrs); // Copy it into the Grid object.
// grid_array->set_attr_table(*grid_attrs); // Copy it into the data Array.
delete grid_attrs;
// Clear the Grid data Array attributes.
AttrTable at;
at.set_name(name());
grid_array->set_attr_table(at);
// Process the Map Arrays.
D4Maps *d4_maps = this->maps();
vector<BaseType *> dropped_maps;
D4Maps::D4MapsIter miter = d4_maps->map_begin();
D4Maps::D4MapsIter end = d4_maps->map_end();
for( ; miter!=end; miter++){
D4Map *d4_map = (*miter);
Array *d4_map_array = const_cast<Array*>(d4_map->array());
vector<BaseType *> *d2_result = d4_map_array->transform_to_dap2(&(g->get_attr_table()));
if(d2_result){
if(d2_result->size()>1)
throw Error(internal_error,string(__func__)+"() - ERROR: D4Map Array conversion resulted in multiple DAP2 objects.");
// TODO - This is probably slow and needs a better pattern. const_cast? static_cast?
Array *d2_map_array = dynamic_cast<Array *>((*d2_result)[0]);
if(d2_map_array){
if(d2_map_array->dimensions()!=1)
throw Error(internal_error,string(__func__)+"() - ERROR: DAP2 array from D4Map Array conversion has more than 1 dimension.");
g->add_map(d2_map_array,false);
AttrTable at = d2_map_array->get_attr_table();
DBG( cerr << __func__ << "() - " <<
"DAS For Grid Map '" << d2_map_array->name() << "':" << endl;
at.print(cerr); );
}
else {
throw Error(internal_error,string(__func__)+"() - Unable to interpret returned DAP2 content.");
}
delete d2_result;
}
else {
dropped_maps.push_back(d4_map_array);
}
}
// Did we have a transform failure?
if(!dropped_maps.empty()){
// Yup... tell the story in the attributes.
AttrTable *dv_table = Constructor::make_dropped_vars_attr_table(&dropped_maps);
dest->get_attr_table().append_container(dv_table,dv_table->get_name());
}
}
else {
// It's not a Grid so we can make a simple copy of our Precious.
DBG( cerr << __func__ << "() - Array '"<< name() << "' is not a Grid!" << endl);
BaseType *proto = this->prototype();
switch(proto->type()){
case dods_int64_c:
case dods_uint64_c:
case dods_enum_c:
case dods_opaque_c:
{
// For now we punt on these type as they have no easy representation in
// the DAP2 data model. By setting this to NULL we cause the Array to be
// dropped and this will be reflected in the metadata (DAS).
dest = NULL;
break;
}
default:
{
dest = this->ptr_duplicate();
// convert the d4 attributes to a dap2 attribute table.
AttrTable *attrs = this->attributes()->get_AttrTable(name());
dest->set_attr_table(*attrs);
dest->set_is_dap4(false);
AttrTable at = dest->get_attr_table();
DBG( cerr << __func__ << "() - " <<
"DAS for new Array '" << dest->name() << "':" << endl;
at.print(cerr); )
break;
}
}
}
}
else {
// If it's a DAP2 Array already then we just make a copy of our Precious.
dest = this->ptr_duplicate();
}
// attrs->print(cerr,"",true);
vector<BaseType *> *result;
if(dest){
result = new vector<BaseType *>();
result->push_back(dest);
}
else {
result = NULL;
}
DBG( cerr << __func__ << "() - END Array '"<< name() << "'" << endl;);
return result;
}
void
Array::update_dimension_pointers(D4Dimensions *old_dims, D4Dimensions *new_dims)
{
std::vector<dimension>::iterator i = _shape.begin(), e = _shape.end();
while (i != e) {
D4Dimensions::D4DimensionsIter old_i = old_dims->dim_begin(), old_e = old_dims->dim_end();
while (old_i != old_e) {
if ((*i).dim == *old_i) {
(*i).dim = new_dims->find_dim((*old_i)->name());
}
++old_i;
}
++i;
}
}
void
Array::add_var(BaseType *v, Part)
{
// If 'v' is an Array, add the template instance to this object and
// then copy the dimension information. Odd semantics; I wonder if this
//is ever used. jhrg 6/13/12
if (v && v->type() == dods_array_c) {
Array *a = static_cast<Array*>(v);
Vector::add_var(a->var());
Dim_iter i = a->dim_begin();
Dim_iter i_end = a->dim_end();
while (i != i_end) {
append_dim(a->dimension_size(i), a->dimension_name(i));
++i;
}
}
else {
Vector::add_var(v);
}
}
void
Array::add_var_nocopy(BaseType *v, Part)
{
// If 'v' is an Array, add the template instance to this object and
// then copy the dimension information. Odd semantics; I wonder if this
//is ever used. jhrg 6/13/12
if (v && v->type() == dods_array_c) {
Array &a = dynamic_cast<Array&>(*v);
Vector::add_var_nocopy(a.var());
Dim_iter i = a.dim_begin();
Dim_iter i_end = a.dim_end();
while (i != i_end) {
append_dim(a.dimension_size(i), a.dimension_name(i));
++i;
}
}
else {
Vector::add_var_nocopy(v);
}
}
void
Array::append_dim(int size, const string &name)
{
dimension d(size, www2id(name));
_shape.push_back(d);
update_length();
}
void
Array::append_dim(D4Dimension *dim)
{
dimension d(/*dim->size(), www2id(dim->name()),*/ dim);
_shape.push_back(d);
update_length();
}
void
Array::prepend_dim(int size, const string& name/* = "" */)
{
dimension d(size, www2id(name));
// Shifts the whole array, but it's tiny in general
_shape.insert(_shape.begin(), d);
update_length(); // the number is ignored...
}
void
Array::prepend_dim(D4Dimension *dim)
{
dimension d(/*dim->size(), www2id(dim->name()),*/ dim);
// Shifts the whole array, but it's tiny in general
_shape.insert(_shape.begin(), d);
update_length(); // the number is ignored...
}
void
Array::clear_all_dims()
{
_shape.clear();
}
void
Array::reset_constraint()
{
set_length(-1);
for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
(*i).start = 0;
(*i).stop = (*i).size - 1;
(*i).stride = 1;
(*i).c_size = (*i).size;
update_length();
}
}
void
Array::clear_constraint()
{
reset_constraint();
}
// Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n
// is explicit.
static const char *array_sss = \
"Invalid constraint parameters: At least one of the start, stride or stop \n\
specified do not match the array variable.";
void
Array::add_constraint(Dim_iter i, int start, int stride, int stop)
{
dimension &d = *i ;
// if stop is -1, set it to the array's max element index
// jhrg 12/20/12
if (stop == -1)
stop = d.size - 1;
// Check for bad constraints.
// Jose Garcia
// Usually invalid data for a constraint is the user's mistake
// because they build a wrong URL in the client side.
if (start >= d.size || stop >= d.size || stride > d.size || stride <= 0)
throw Error(malformed_expr, array_sss);
if (((stop - start) / stride + 1) > d.size)
throw Error(malformed_expr, array_sss);
d.start = start;
d.stop = stop;
d.stride = stride;
d.c_size = (stop - start) / stride + 1;
DBG(cerr << "add_constraint: c_size = " << d.c_size << endl);
update_length();
d.use_sdim_for_slice = false;
}
void
Array::add_constraint(Dim_iter i, D4Dimension *dim)
{
dimension &d = *i ;
if (dim->constrained())
add_constraint(i, dim->c_start(), dim->c_stride(), dim->c_stop());
dim->set_used_by_projected_var(true);
// In this case the value below overrides the value for use_sdim_for_slice
// set in the above call. jhrg 12/20/13
d.use_sdim_for_slice = true;
}
Array::Dim_iter
Array::dim_begin()
{
return _shape.begin() ;
}
Array::Dim_iter
Array::dim_end()
{
return _shape.end() ;
}
//TODO Many of these methods take a bool parameter that serves no use; remove.
unsigned int
Array::dimensions(bool /*constrained*/)
{
return _shape.size();
}
int
Array::dimension_size(Dim_iter i, bool constrained)
{
int size = 0;
if (!_shape.empty()) {
if (constrained)
size = (*i).c_size;
else
size = (*i).size;
}
return size;
}
int
Array::dimension_start(Dim_iter i, bool /*constrained*/)
{
return (!_shape.empty()) ? (*i).start : 0;
}
int
Array::dimension_stop(Dim_iter i, bool /*constrained*/)
{
return (!_shape.empty()) ? (*i).stop : 0;
}
int
Array::dimension_stride(Dim_iter i, bool /*constrained*/)
{
return (!_shape.empty()) ? (*i).stride : 0;
}
string
Array::dimension_name(Dim_iter i)
{
// Jose Garcia
// Since this method is public, it is possible for a user
// to call it before the Array object has been properly set
// this will cause an exception which is the user's fault.
// (User in this context is the developer of the surrogate library.)
if (_shape.empty())
throw InternalErr(__FILE__, __LINE__,
"*This* array has no dimensions.");
return (*i).name;
}
D4Dimension *
Array::dimension_D4dim(Dim_iter i)
{
return (!_shape.empty()) ? (*i).dim : 0;
}
D4Maps *
Array::maps()
{
if (!d_maps) d_maps = new D4Maps(this); // init with this as parent
return d_maps;
}
#if 0
unsigned int Array::width(bool constrained) const
{
if (constrained) {
// This preserves the original method's semantics when we ask for the
// size of the constrained array but no constraint has been applied.
// In this case, length will be -1. Wrong, I know...
return length() * var()->width(constrained);
}
else {
int length = 1;
for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
length *= dimension_size(i, false);
}
return length * var()->width(false);
}
}
#endif
class PrintD4ArrayDimXMLWriter: public unary_function<Array::dimension&, void> {
XMLWriter &xml;
// Was this variable constrained using local/direct slicing? i.e., is d_local_constraint set?
// If so, don't use shared dimensions; instead emit Dim elements that are anonymous.
bool d_constrained;
public:
PrintD4ArrayDimXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) { }
void operator()(Array::dimension &d)
{
// This duplicates code in D4Dimensions (where D4Dimension::print_dap4() is defined
// because of the need to print the constrained size of a dimension. I think that
// the constraint information has to be kept here and not in the dimension (since they
// are shared dims). Could hack print_dap4() to take the constrained size, however.
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dim") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write Dim element");
string name = (d.dim) ? d.dim->fully_qualified_name() : d.name;
// If there is a name, there must be a Dimension (named dimension) in scope
// so write its name but not its size.
if (!d_constrained && !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");
}
else if (d.use_sdim_for_slice) {
assert(!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");
}
else {
ostringstream size;
size << (d_constrained ? d.c_size : d.size);
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size",
(const xmlChar*) size.str().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
}
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end Dim element");
}
};
class PrintD4ConstructorVarXMLWriter: public unary_function<BaseType*, void> {
XMLWriter &xml;
bool d_constrained;
public:
PrintD4ConstructorVarXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) { }
void operator()(BaseType *btp)
{
btp->print_dap4(xml, d_constrained);
}
};
class PrintD4MapXMLWriter: public unary_function<D4Map*, void> {
XMLWriter &xml;
public:
PrintD4MapXMLWriter(XMLWriter &xml) : xml(xml) { }
void operator()(D4Map *m)
{
m->print_dap4(xml);
}
};
void
Array::print_dap4(XMLWriter &xml, bool constrained /* default: false*/)
{
if (constrained && !send_p()) return;
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) var()->type_name().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write " + type_name() + " 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");
// Hack job... Copied from D4Enum::print_xml_writer. jhrg 11/12/13
if (var()->type() == dods_enum_c) {
D4Enum *e = static_cast<D4Enum*>(var());
string path = e->enumeration()->name();
if (e->enumeration()->parent()) {
// print the FQN for the enum def; D4Group::FQN() includes the trailing '/'
path = static_cast<D4Group*>(e->enumeration()->parent()->parent())->FQN() + path;
}
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "enum", (const xmlChar*)path.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for enum");
}
if (prototype()->is_constructor_type()) {
Constructor &c = static_cast<Constructor&>(*prototype());
for_each(c.var_begin(), c.var_end(), PrintD4ConstructorVarXMLWriter(xml, constrained));
// bind2nd(mem_fun_ref(&BaseType::print_dap4), xml));
}
// Drop the local_constraint which is per-array and use a per-dimension on instead
for_each(dim_begin(), dim_end(), PrintD4ArrayDimXMLWriter(xml, constrained));
attributes()->print_dap4(xml);
for_each(maps()->map_begin(), maps()->map_end(), PrintD4MapXMLWriter(xml));
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end " + type_name() + " element");
}
void
Array::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 Array::print_decl(ostream &out, string space, bool print_semi, bool constraint_info, bool constrained)
{
if (constrained && !send_p()) return;
// print it, but w/o semicolon
var()->print_decl(out, space, false, constraint_info, constrained);
for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
out << "[";
if ((*i).name != "") {
out << id2www((*i).name) << " = ";
}
if (constrained) {
out << (*i).c_size << "]";
}
else {
out << (*i).size << "]";
}
}
if (print_semi) {
out << ";\n";
}
}
void
Array::print_xml(FILE *out, string space, bool constrained)
{
XMLWriter xml(space);
print_xml_writer_core(xml, constrained, "Array");
fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
}
void
Array::print_xml(ostream &out, string space, bool constrained)
{
XMLWriter xml(space);
print_xml_writer_core(xml, constrained, "Array");
out << xml.get_doc();
}
void
Array::print_as_map_xml(FILE *out, string space, bool constrained)
{
XMLWriter xml(space);
print_xml_writer_core(xml, constrained, "Map");
fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
}
void
Array::print_as_map_xml(ostream &out, string space, bool constrained)
{
XMLWriter xml(space);
print_xml_writer_core(xml, constrained, "Map");
out << xml.get_doc();
}
void
Array::print_xml_core(FILE *out, string space, bool constrained, string tag)
{
XMLWriter xml(space);
print_xml_writer_core(xml, constrained, tag);
fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
}
void
Array::print_xml_core(ostream &out, string space, bool constrained, string tag)
{
XMLWriter xml(space);
print_xml_writer_core(xml, constrained, tag);
out << xml.get_doc();
}
void
Array::print_xml_writer(XMLWriter &xml, bool constrained)
{
print_xml_writer_core(xml, constrained, "Array");
}
void
Array::print_as_map_xml_writer(XMLWriter &xml, bool constrained)
{
print_xml_writer_core(xml, constrained, "Map");
}
class PrintArrayDimXMLWriter : public unary_function<Array::dimension&, void>
{
XMLWriter &xml;
bool d_constrained;
public:
PrintArrayDimXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) {}
void operator()(Array::dimension &d)
{
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"dimension") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write dimension element");
if (!d.name.empty())
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d.name.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
ostringstream size;
size << (d_constrained ? d.c_size : d.size);
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size", (const xmlChar*)size.str().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end dimension element");
}
};
void
Array::print_xml_writer_core(XMLWriter &xml, bool constrained, string tag)
{
if (constrained && !send_p())
return;
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)tag.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write " + tag + " 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);
BaseType *btp = var();
string tmp_name = btp->name();
btp->set_name("");
btp->print_xml_writer(xml, constrained);
btp->set_name(tmp_name);
for_each(dim_begin(), dim_end(), PrintArrayDimXMLWriter(xml, constrained));
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end " + tag + " element");
}
unsigned int
Array::print_array(FILE *out, unsigned int index, unsigned int dims,
unsigned int shape[])
{
ostringstream oss;
unsigned int i = print_array(oss, index, dims, shape);
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
return i;
}
unsigned int Array::print_array(ostream &out, unsigned int index, unsigned int dims, unsigned int shape[])
{
if (dims == 1) {
out << "{";
// Added test in case this method is passed an array with no elements. jhrg 1/27/16
if (shape[0] >= 1) {
for (unsigned i = 0; i < shape[0] - 1; ++i) {
var(index++)->print_val(out, "", false);
out << ", ";
}
var(index++)->print_val(out, "", false);
}
out << "}";
return index;
}
else {
out << "{";
// Fixed an off-by-one error in the following loop. Since the array
// length is shape[dims-1]-1 *and* since we want one less dimension
// than that, the correct limit on this loop is shape[dims-2]-1. From
// Todd Karakasian.
//
// The saga continues; the loop test should be `i < shape[0]-1'. jhrg
// 9/12/96.
//
// For arrays that hold zero values but have rank > 1, the print out
// may look a little odd (e.g., x[4][0] will print as { {}, {}, {}, {} })
// but it's not wrong and this is really for debugging mostly. jhrg 1/28/16
if (shape[0] > 0) {
for (unsigned i = 0; i < shape[0] - 1; ++i) {
index = print_array(out, index, dims - 1, shape + 1);
out << ",";
}
index = print_array(out, index, dims - 1, shape + 1);
}
out << "}";
return index;
}
}
void
Array::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
Array::print_val(ostream &out, string space, bool print_decl_p)
{
// print the declaration if print decl is true.
// for each dimension,
// for each element,
// print the array given its shape, number of dimensions.
// Add the `;'
if (print_decl_p) {
print_decl(out, space, false, false, false);
out << " = " ;
}
unsigned int *shape = new unsigned int[dimensions(true)];
unsigned int index = 0;
for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i)
shape[index++] = dimension_size(i, true);
print_array(out, 0, dimensions(true), shape);
delete [] shape; shape = 0;
if (print_decl_p) {
out << ";\n" ;
}
}
bool
Array::check_semantics(string &msg, bool)
{
bool sem = BaseType::check_semantics(msg) && !_shape.empty();
if (!sem)
msg = "An array variable must have dimensions";
return sem;
}
void
Array::dump(ostream &strm) const
{
strm << DapIndent::LMarg << "Array::dump - ("
<< (void *)this << ")" << endl ;
DapIndent::Indent() ;
Vector::dump(strm) ;
strm << DapIndent::LMarg << "shape:" << endl ;
DapIndent::Indent() ;
Dim_citer i = _shape.begin() ;
Dim_citer ie = _shape.end() ;
unsigned int dim_num = 0 ;
for (; i != ie; i++) {
strm << DapIndent::LMarg << "dimension " << dim_num++ << ":"
<< endl ;
DapIndent::Indent() ;
strm << DapIndent::LMarg << "name: " << (*i).name << endl ;
strm << DapIndent::LMarg << "size: " << (*i).size << endl ;
strm << DapIndent::LMarg << "start: " << (*i).start << endl ;
strm << DapIndent::LMarg << "stop: " << (*i).stop << endl ;
strm << DapIndent::LMarg << "stride: " << (*i).stride << endl ;
strm << DapIndent::LMarg << "constrained size: " << (*i).c_size
<< endl ;
DapIndent::UnIndent() ;
}
DapIndent::UnIndent() ;
DapIndent::UnIndent() ;
}
} // namespace libdap
libdap::Array::print_xml_writer
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: Array.cc:1141
libdap::Array::reset_constraint
virtual void reset_constraint()
Reset constraint to select entire array.
Definition: Array.cc:591
libdap::Array::add_constraint
virtual void add_constraint(Dim_iter i, int start, int stride, int stop)
Adds a constraint to an Array dimension.
Definition: Array.cc:648
libdap::BaseType::name
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:311
libdap::Array::check_semantics
virtual bool check_semantics(string &msg, bool all=false)
Check semantic features of the Array.
Definition: Array.cc:1330
libdap::Array::print_xml_core
virtual void print_xml_core(FILE *out, string space, bool constrained, string tag)
Definition: Array.cc:1122
libdap::D4Dimensions::D4DimensionsIter
vector< D4Dimension * >::iterator D4DimensionsIter
Iterator used for D4Dimensions.
Definition: D4Dimensions.h:122
libdap::Array::dump
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Array.cc:1349
libdap::BaseType::print_decl
virtual void print_decl(FILE *out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Print an ASCII representation of the variable structure.
Definition: BaseType.cc:994
libdap::Array::Array
Array(const string &n, BaseType *v, bool is_dap4=false)
Array constructor.
Definition: Array.cc:137
libdap::D4Attributes::get_AttrTable
AttrTable * get_AttrTable(const std::string name)
copy attributes from DAP4 to DAP2
Definition: D4Attributes.cc:343
libdap::Array::dimensions
virtual unsigned int dimensions(bool constrained=false)
Return the total number of dimensions in the array.
Definition: Array.cc:720
libdap::Part
Part
Names the parts of multi-section constructor data types.
Definition: Type.h:48
libdap::Array::add_var
void add_var(BaseType *v, Part p=nil)
Add the BaseType pointer to this constructor type instance.
Definition: Array.cc:480
libdap::AttrTable
Contains the attributes for a dataset.
Definition: AttrTable.h:142
libdap::BaseType::set_name
virtual void set_name(const string &n)
Sets the name of the class instance.
Definition: BaseType.cc:335
libdap::Array::dimension::stop
int stop
The constraint end index.
Definition: Array.h:149
libdap::Vector
Holds a one-dimensional collection of DAP2 data types.
Definition: Vector.h:80
libdap::Vector::width
virtual unsigned int width(bool constrained=false) const
Returns the width of the data, in bytes.
Definition: Vector.cc:543
libdap::BaseType::print_xml_writer
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: BaseType.cc:1125
libdap::AttrTable::get_name
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:237
libdap::Array::Dim_citer
std::vector< dimension >::const_iterator Dim_citer
Definition: Array.h:198
libdap::Array::dimension::use_sdim_for_slice
bool use_sdim_for_slice
Used to control printing the DMR in data responses.
Definition: Array.h:146
libdap::Array::dimension::start
int start
The constraint start index.
Definition: Array.h:148
libdap::BaseType::BaseType
BaseType(const string &n, const Type &t, bool is_dap4=false)
The BaseType constructor.
Definition: BaseType.cc:125
libdap::Vector::add_var
virtual void add_var(BaseType *v, Part p=nil)
Add the BaseType pointer to this constructor type instance.
Definition: Vector.cc:1975
libdap::D4Dimensions::dim_end
D4DimensionsIter dim_end()
Get an iterator to the end of the dimensions.
Definition: D4Dimensions.h:166
std
STL namespace.
libdap::AttrTable::print_xml_writer
void print_xml_writer(XMLWriter &xml)
Definition: AttrTable.cc:1424
libdap::D4Map
Definition: D4Maps.h:54
libdap::Constructor::add_var_nocopy
virtual void add_var_nocopy(BaseType *bt, Part part=nil)
Definition: Constructor.cc:432
libdap::AttrTable::print
virtual void print(FILE *out, string pad=" ", bool dereference=false)
Prints the attribute table.
Definition: AttrTable.cc:1242
libdap::Array::append_dim
void append_dim(int size, const string &name="")
Add a dimension of a given size.
Definition: Array.cc:534
libdap::Array::update_length
virtual void update_length(int size=0)
Definition: Array.cc:104
libdap::D4Dimensions::dim_begin
D4DimensionsIter dim_begin()
Get an iterator to the start of the dimensions.
Definition: D4Dimensions.h:163
libdap
Definition: AlarmHandler.h:35
libdap::InternalErr
A class for software fault reporting.
Definition: InternalErr.h:64
libdap::Array::dim_end
Dim_iter dim_end()
Definition: Array.cc:704
libdap::BaseType::FQN
virtual std::string FQN() const
Definition: BaseType.cc:323
libdap::Vector::var
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Definition: Vector.cc:434
libdap::Array::print_as_map_xml
virtual void print_as_map_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Array.cc:1111
libdap::D4Maps
Definition: D4Maps.h:84
libdap::Array::transform_to_dap2
virtual std::vector< BaseType * > * transform_to_dap2(AttrTable *parent_attr_table)
Transforms this instance of a D4Array into the corresponding DAP2 object.
Definition: Array.cc:308
libdap::D4Enum
Holds a DAP4 enumeration.
Definition: D4Enum.h:61
libdap::Array::dimension_size
virtual int dimension_size(Dim_iter i, bool constrained=false)
Returns the size of the dimension.
Definition: Array.cc:743
libdap::BaseType::print_val
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: BaseType.cc:1081
libdap::BaseType::is_constructor_type
virtual bool is_constructor_type() const
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable...
Definition: BaseType.cc:403
libdap::Array::dimension
Definition: Array.h:125
libdap::AttrTable::get_attr_table
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition: AttrTable.cc:606
libdap::BaseType::type
virtual Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:356
libdap::Array::Dim_iter
std::vector< dimension >::iterator Dim_iter
Definition: Array.h:206
libdap::Array::clear_all_dims
void clear_all_dims()
Definition: Array.cc:580
libdap::Array::dimension_name
virtual string dimension_name(Dim_iter i)
Returns the name of the specified dimension.
Definition: Array.cc:841
libdap::Array::ptr_duplicate
virtual BaseType * ptr_duplicate()
Definition: Array.cc:175
libdap::Array::dimension_stride
virtual int dimension_stride(Dim_iter i, bool constrained=false)
Returns the stride value of the constraint.
Definition: Array.cc:825
libdap::Grid
Holds the Grid data type.
Definition: Grid.h:122
libdap::Array::dimension::stride
int stride
The constraint stride.
Definition: Array.h:150
libdap::Array::print_decl
virtual void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Prints a DDS entry for the Array.
Definition: Array.cc:1049
libdap::Array::dimension::c_size
int c_size
Size of dimension once constrained.
Definition: Array.h:151
libdap::BaseType::attributes
virtual D4Attributes * attributes()
Definition: BaseType.cc:590
libdap::Array::prepend_dim
void prepend_dim(int size, const string &name="")
Definition: Array.cc:557
libdap::Array::print_xml
virtual void print_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Array.cc:1089
libdap::www2id
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:220
libdap::Array::dimension_stop
virtual int dimension_stop(Dim_iter i, bool constrained=false)
Return the stop index of the constraint.
Definition: Array.cc:800
libdap::Constructor
Definition: Constructor.h:43
libdap::D4Dimensions
Definition: D4Dimensions.h:101
libdap::Array::dimension_start
virtual int dimension_start(Dim_iter i, bool constrained=false)
Return the start index of a dimension.
Definition: Array.cc:776
libdap::BaseType::get_attr_table
virtual AttrTable & get_attr_table()
Definition: BaseType.cc:573
libdap::Array::print_dap4
virtual void print_dap4(XMLWriter &xml, bool constrained=false)
Print the DAP4 representation of an array.
Definition: Array.cc:966
libdap::Array::~Array
virtual ~Array()
The Array destructor.
Definition: Array.cc:169
libdap::Array::dimension::size
int size
The unconstrained dimension size.
Definition: Array.h:135
libdap::Array::dimension::name
string name
The name of this dimension.
Definition: Array.h:136
libdap::BaseType
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
libdap::Array::dim_begin
Dim_iter dim_begin()
Definition: Array.cc:697
libdap::BaseType::type_name
virtual string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:370
libdap::Constructor::var_begin
Vars_iter var_begin()
Definition: Constructor.cc:356
libdap::BaseType::set_attr_table
virtual void set_attr_table(const AttrTable &at)
Definition: BaseType.cc:581
libdap::Vector::length
virtual int length() const
Definition: Vector.cc:555
libdap::Constructor::var_end
Vars_iter var_end()
Definition: Constructor.cc:364
libdap::D4Group
Definition: D4Group.h:43
libdap::Vector::set_length
virtual void set_length(int l)
Definition: Vector.cc:562
libdap::XMLWriter
Definition: XMLWriter.h:39
libdap::Error
A class for error processing.
Definition: Error.h:90
libdap::AttrTable::set_name
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition: AttrTable.cc:244
libdap::Array::print_array
unsigned int print_array(FILE *out, unsigned int index, unsigned int dims, unsigned int shape[])
Print the value given the current constraint.
Definition: Array.cc:1217
libdap::Array
A multidimensional array of identical data types.
Definition: Array.h:112
libdap::Array::print_val
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: Array.cc:1293
libdap::BaseType::width
virtual unsigned int width(bool constrained=false) const
How many bytes does this use Return the number of bytes of storage this variable uses. For scalar types, this is pretty simple (an int32 uses 4 bytes, etc.). For arrays and Constructors, it is a bit more complex. Note that a scalar String variable uses sizeof(String*) bytes, not the length of the string. In other words, the value returned is independent of the type. Also note width() of a String array returns the number of elements in the array times sizeof(String*). That is, each different array size is a different data type.
Definition: BaseType.cc:1292
libdap::BaseType::send_p
virtual bool send_p()
Should this variable be sent?
Definition: BaseType.cc:545
libdap::Array::transform_to_dap4
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: Array.cc:194
libdap::Vector::dump
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Vector.cc:2058
libdap::id2www
string id2www(string in, const string &allowable)
Definition: escaping.cc:153
libdap::D4Dimension
Definition: D4Dimensions.h:41
libdap::D4Group::dims
D4Dimensions * dims()
Get the dimensions defined for this Group.
Definition: D4Group.h:82
libdap::Array::clear_constraint
virtual void clear_constraint()
Clears the projection; add each projected dimension explicitly using add_constraint.
Definition: Array.cc:616
libdap::BaseType::check_semantics
virtual bool check_semantics(string &msg, bool all=false)
Compare an object&#39;s current state with the semantics of its type.
Definition: BaseType.cc:1200