|
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 Array.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// jhrg 9/13/94
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "config.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// #define DODS_DEBUG
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <algorithm>
|
|
Packit |
a4aae4 |
#include <functional>
|
|
Packit |
a4aae4 |
#include <sstream>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "Array.h"
|
|
Packit |
a4aae4 |
#include "Grid.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "D4Attributes.h"
|
|
Packit |
a4aae4 |
#include "DMR.h"
|
|
Packit |
a4aae4 |
#include "D4Dimensions.h"
|
|
Packit |
a4aae4 |
#include "D4Maps.h"
|
|
Packit |
a4aae4 |
#include "D4Group.h"
|
|
Packit |
a4aae4 |
#include "D4EnumDefs.h"
|
|
Packit |
a4aae4 |
#include "D4Enum.h"
|
|
Packit |
a4aae4 |
#include "XMLWriter.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "util.h"
|
|
Packit |
a4aae4 |
#include "debug.h"
|
|
Packit |
a4aae4 |
#include "InternalErr.h"
|
|
Packit |
a4aae4 |
#include "escaping.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
using namespace std;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
namespace libdap {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Array::dimension::dimension(D4Dimension *d) : dim(d), use_sdim_for_slice(true)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
size = d->size();
|
|
Packit |
a4aae4 |
name = d->name();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
start = 0;
|
|
Packit |
a4aae4 |
stop = size - 1;
|
|
Packit |
a4aae4 |
stride = 1;
|
|
Packit |
a4aae4 |
c_size = size;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::_duplicate(const Array &a)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
_shape = a._shape;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Deep copy the Maps if they are being used.
|
|
Packit |
a4aae4 |
if (a.d_maps) {
|
|
Packit |
a4aae4 |
d_maps = new D4Maps(*(a.d_maps));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
d_maps = 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// d_maps = a.d_maps ? new D4Maps(*(a.d_maps)) : 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// The first method of calculating length works when only one dimension is
|
|
Packit |
a4aae4 |
// constrained and you want the others to appear in total. This is important
|
|
Packit |
a4aae4 |
// when selecting from grids since users may not select from all dimensions
|
|
Packit |
a4aae4 |
// in which case that means they want the whole thing. Array projection
|
|
Packit |
a4aae4 |
// should probably work this way too, but it doesn't. 9/21/2001 jhrg
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @deprecated Calling this method should never be necessary. It is used
|
|
Packit |
a4aae4 |
internally called whenever the size of the Array is changed, e.g., by a
|
|
Packit |
a4aae4 |
constraint.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Changes the length property of the array.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::update_length(int)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
int length = 1;
|
|
Packit |
a4aae4 |
for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
// If the size of any dimension is zero, then the array is not
|
|
Packit |
a4aae4 |
// capable of storing any values. jhrg 1/28/16
|
|
Packit |
a4aae4 |
length *= (*i).c_size > 0 ? (*i).c_size : 1;
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
length *= (*i).c_size;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
set_length(length);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Construct an instance of Array. The (BaseType *) is assumed to be
|
|
Packit |
a4aae4 |
// allocated using new - The dtor for Vector will delete this object.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Build an array with a name and an element type. The name may be omitted,
|
|
Packit |
a4aae4 |
which will create a nameless variable. The template (element type) pointer
|
|
Packit |
a4aae4 |
may also be omitted, but if it is omitted when the Array is created, it
|
|
Packit |
a4aae4 |
\e must be added (with \c add_var()) before \c read() or \c deserialize()
|
|
Packit |
a4aae4 |
is called.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@todo Force the Array::add_var() method to be used to add \e v.
|
|
Packit |
a4aae4 |
This version of add_var() calls Vector::add_var().
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param n A string containing the name of the variable to be
|
|
Packit |
a4aae4 |
created.
|
|
Packit |
a4aae4 |
@param v A pointer to a variable of the type to be included
|
|
Packit |
a4aae4 |
in the Array. May be null and set later using add_var() or add_var_nocopy()
|
|
Packit |
a4aae4 |
@brief Array constructor
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
Array::Array(const string &n, BaseType *v, bool is_dap4 /* default:false */)
|
|
Packit |
a4aae4 |
: Vector(n, 0, dods_array_c, is_dap4), d_maps(0)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_var(v); // Vector::add_var() stores null if v is null
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Build an array on the server-side with a name, a dataset name from which
|
|
Packit |
a4aae4 |
this Array is being created, and an element type.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@todo Force the Array::add_var() method to be used to add \e v.
|
|
Packit |
a4aae4 |
This version of add_var() calls Vector::add_var().
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param n A string containing the name of the variable to be created.
|
|
Packit |
a4aae4 |
@param d A string containing the name of the dataset from which this
|
|
Packit |
a4aae4 |
variable is being created.
|
|
Packit |
a4aae4 |
@param v A pointer to a variable of the type to be included
|
|
Packit |
a4aae4 |
in the Array.
|
|
Packit |
a4aae4 |
@brief Array constructor
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
Array::Array(const string &n, const string &d, BaseType *v, bool is_dap4 /* default:false */)
|
|
Packit |
a4aae4 |
: Vector(n, d, 0, dods_array_c, is_dap4), d_maps(0)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
add_var(v); // Vector::add_var() stores null if v is null
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief The Array copy constructor. */
|
|
Packit |
a4aae4 |
Array::Array(const Array &rhs) : Vector(rhs)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
_duplicate(rhs);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief The Array destructor. */
|
|
Packit |
a4aae4 |
Array::~Array()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
delete d_maps;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *
|
|
Packit |
a4aae4 |
Array::ptr_duplicate()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return new Array(*this);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Array &
|
|
Packit |
a4aae4 |
Array::operator=(const Array &rhs)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (this == &rhs)
|
|
Packit |
a4aae4 |
return *this;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dynamic_cast<Vector &>(*this) = rhs;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
_duplicate(rhs);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return *this;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::transform_to_dap4(D4Group *root, Constructor *container)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - BEGIN (array:" << name() << ")" << endl;);
|
|
Packit |
a4aae4 |
Array *dest = static_cast<Array*>(ptr_duplicate());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If it's already a DAP4 object then we can just return it!
|
|
Packit |
a4aae4 |
if(is_dap4()){
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - Already DAP4 type: Just making a copy and adding to container. " << endl;);
|
|
Packit |
a4aae4 |
container->add_var_nocopy(dest);
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - END (Already DAP4 type)" << endl;);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// Process the Array's dimensions, making D4 shared dimensions for
|
|
Packit |
a4aae4 |
// D2 dimensions that are named. If there is just a size, don't make
|
|
Packit |
a4aae4 |
// a D4Dimension (In DAP4 you cannot share a dimension unless it has
|
|
Packit |
a4aae4 |
// a name). jhrg 3/18/14
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
D4Dimensions *root_dims = root->dims();
|
|
Packit |
a4aae4 |
for (Array::Dim_iter dap2_dim = dest->dim_begin(), e = dest->dim_end(); dap2_dim != e; ++dap2_dim) {
|
|
Packit |
a4aae4 |
if (!(*dap2_dim).name.empty()) {
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - Processing the array dimension '" << (*dap2_dim).name << "'" << endl;);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If a D4Dimension with the name already exists, use it.
|
|
Packit |
a4aae4 |
D4Dimension *d4_dim = root_dims->find_dim((*dap2_dim).name);
|
|
Packit |
a4aae4 |
if (!d4_dim) {
|
|
Packit |
a4aae4 |
d4_dim = new D4Dimension((*dap2_dim).name, (*dap2_dim).size);
|
|
Packit |
a4aae4 |
root_dims->add_dim_nocopy(d4_dim);
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() -" <<
|
|
Packit |
a4aae4 |
" Added NEW D4Dimension '"<< d4_dim->name() << "' (" <<
|
|
Packit |
a4aae4 |
(void *)d4_dim << ") to root->dims()"<< endl;);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() -" <<
|
|
Packit |
a4aae4 |
" Using Existing D4Dimension '"<< d4_dim->name() << "' (" <<
|
|
Packit |
a4aae4 |
(void *)d4_dim << ")"<< endl;);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d4_dim->size() != (unsigned long) (*dap2_dim).size) {
|
|
Packit |
a4aae4 |
// TODO Revisit this decision. jhrg 3/18/14
|
|
Packit |
a4aae4 |
// ...in case the name/size are different, make a unique D4Dimension
|
|
Packit |
a4aae4 |
// but don't fiddle with the name. Not sure I like this idea, so I'm
|
|
Packit |
a4aae4 |
// making the case explicit (could be rolled in to the block above).
|
|
Packit |
a4aae4 |
// jhrg 3/18/14
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This is causing problems in the FITS handler because there are cases
|
|
Packit |
a4aae4 |
// where two arrays have dimensions with the same name but different
|
|
Packit |
a4aae4 |
// sizes. The deserializing code is using the first size listed, which is
|
|
Packit |
a4aae4 |
// wrong in some cases. I'm going to try making this new D4Dimension using
|
|
Packit |
a4aae4 |
// the dim name along with the variable name. jhrg 8/15/14
|
|
Packit |
a4aae4 |
d4_dim = new D4Dimension((*dap2_dim).name + "_" + name(), (*dap2_dim).size);
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() -" <<
|
|
Packit |
a4aae4 |
" Utilizing Name/Size Conflict Naming Artifice. name'"<< d4_dim->name() << "' (" <<
|
|
Packit |
a4aae4 |
(void *)d4_dim << ")"<< endl;);
|
|
Packit |
a4aae4 |
root_dims->add_dim_nocopy(d4_dim);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// At this point d4_dim's name and size == those of (*d) so just set
|
|
Packit |
a4aae4 |
// the D4Dimension pointer so it matches the one in the D4Group.
|
|
Packit |
a4aae4 |
(*dap2_dim).dim = d4_dim;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Copy the D2 attributes to D4 Attributes
|
|
Packit |
a4aae4 |
dest->attributes()->transform_to_dap4(get_attr_table());
|
|
Packit |
a4aae4 |
dest->set_is_dap4(true);
|
|
Packit |
a4aae4 |
container->add_var_nocopy(dest);
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - END (array:" << name() << ")" << endl;);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
bool Array::is_dap2_grid(){
|
|
Packit |
a4aae4 |
bool is_grid = false;
|
|
Packit |
a4aae4 |
if(this->is_dap4()){
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - Array '"<< name() << "' is DAP4 object!" << endl;)
|
|
Packit |
a4aae4 |
D4Maps *d4_maps = this->maps();
|
|
Packit |
a4aae4 |
is_grid = d4_maps->size(); // It can't be a grid if there are no maps...
|
|
Packit |
a4aae4 |
if(is_grid){
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - Array '"<< name() << "' has D4Maps." << endl;)
|
|
Packit |
a4aae4 |
// hmmm this might be a DAP2 Grid...
|
|
Packit |
a4aae4 |
D4Maps::D4MapsIter i = d4_maps->map_begin();
|
|
Packit |
a4aae4 |
D4Maps::D4MapsIter e = d4_maps->map_end();
|
|
Packit |
a4aae4 |
while(i!=e){
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - Map '"<< (*i)->array()->name() << " has " << (*i)->array()->_shape.size() << " dimension(s)." << endl;)
|
|
Packit |
a4aae4 |
if((*i)->array()->_shape.size() > 1){
|
|
Packit |
a4aae4 |
is_grid = false;
|
|
Packit |
a4aae4 |
i = e;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
i++;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - Array '"<< name() << "' has no D4Maps." << endl;)
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - is_grid: "<< (is_grid?"true":"false") << endl;)
|
|
Packit |
a4aae4 |
return is_grid;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Transforms this instance of a D4Array into the corresponding DAP2 object.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* This transformation may return an Array or a Grid object. The DAP2 Grid construct
|
|
Packit |
a4aae4 |
* is semantically contained in the DAP4 concept of arrays with Map arrays. If all
|
|
Packit |
a4aae4 |
* of the Maps are one dimensional then the D4Array can be represented as a
|
|
Packit |
a4aae4 |
* Grid object.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param The AttrTable pointer parent_attr_table is used by Groups, which disappear
|
|
Packit |
a4aae4 |
* from the DAP2 representation. Their children are returned in the the BAseType vector
|
|
Packit |
a4aae4 |
* their attributes are added to parent_attr_table.
|
|
Packit |
a4aae4 |
* @return A pointer to a vector of BaseType pointers (right?). In this D4Array case
|
|
Packit |
a4aae4 |
* returned vector may contain a DAP2 Array or a Grid. Or, if the Array' prototype is
|
|
Packit |
a4aae4 |
* a type that cannot be represented in DAP2 the return will be NULL.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
std::vector<BaseType *> *
|
|
Packit |
a4aae4 |
Array::transform_to_dap2(AttrTable *){
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - BEGIN Array '"<< name() << "'" << endl;);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *dest;
|
|
Packit |
a4aae4 |
if(is_dap4()){ // Don't convert a DAP2 thing
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Can Precious be represented as a DAP2 Grid
|
|
Packit |
a4aae4 |
if(is_dap2_grid()){
|
|
Packit |
a4aae4 |
// Oh yay! Grids are special.
|
|
Packit |
a4aae4 |
DBG(cerr << __func__ << "() - Array '"<< name() << "' is dap2 Grid!" << endl;);
|
|
Packit |
a4aae4 |
Grid *g = new Grid(name());
|
|
Packit |
a4aae4 |
dest = g;
|
|
Packit |
a4aae4 |
Array *grid_array = (Array *) this->ptr_duplicate();
|
|
Packit |
a4aae4 |
g->set_array(grid_array);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Get the metadata into the Grid
|
|
Packit |
a4aae4 |
AttrTable *grid_attrs = attributes()->get_AttrTable(name());
|
|
Packit |
a4aae4 |
g->set_attr_table(*grid_attrs); // Copy it into the Grid object.
|
|
Packit |
a4aae4 |
// grid_array->set_attr_table(*grid_attrs); // Copy it into the data Array.
|
|
Packit |
a4aae4 |
delete grid_attrs;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Clear the Grid data Array attributes.
|
|
Packit |
a4aae4 |
AttrTable at;
|
|
Packit |
a4aae4 |
at.set_name(name());
|
|
Packit |
a4aae4 |
grid_array->set_attr_table(at);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Process the Map Arrays.
|
|
Packit |
a4aae4 |
D4Maps *d4_maps = this->maps();
|
|
Packit |
a4aae4 |
vector<BaseType *> dropped_maps;
|
|
Packit |
a4aae4 |
D4Maps::D4MapsIter miter = d4_maps->map_begin();
|
|
Packit |
a4aae4 |
D4Maps::D4MapsIter end = d4_maps->map_end();
|
|
Packit |
a4aae4 |
for( ; miter!=end; miter++){
|
|
Packit |
a4aae4 |
D4Map *d4_map = (*miter);
|
|
Packit |
a4aae4 |
Array *d4_map_array = const_cast<Array*>(d4_map->array());
|
|
Packit |
a4aae4 |
vector<BaseType *> *d2_result = d4_map_array->transform_to_dap2(&(g->get_attr_table()));
|
|
Packit |
a4aae4 |
if(d2_result){
|
|
Packit |
a4aae4 |
if(d2_result->size()>1)
|
|
Packit |
a4aae4 |
throw Error(internal_error,string(__func__)+"() - ERROR: D4Map Array conversion resulted in multiple DAP2 objects.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// TODO - This is probably slow and needs a better pattern. const_cast? static_cast?
|
|
Packit |
a4aae4 |
Array *d2_map_array = dynamic_cast<Array *>((*d2_result)[0]);
|
|
Packit |
a4aae4 |
if(d2_map_array){
|
|
Packit |
a4aae4 |
if(d2_map_array->dimensions()!=1)
|
|
Packit |
a4aae4 |
throw Error(internal_error,string(__func__)+"() - ERROR: DAP2 array from D4Map Array conversion has more than 1 dimension.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
g->add_map(d2_map_array,false);
|
|
Packit |
a4aae4 |
AttrTable at = d2_map_array->get_attr_table();
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - " <<
|
|
Packit |
a4aae4 |
"DAS For Grid Map '" << d2_map_array->name() << "':" << endl;
|
|
Packit |
a4aae4 |
at.print(cerr); );
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
throw Error(internal_error,string(__func__)+"() - Unable to interpret returned DAP2 content.");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
delete d2_result;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
dropped_maps.push_back(d4_map_array);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Did we have a transform failure?
|
|
Packit |
a4aae4 |
if(!dropped_maps.empty()){
|
|
Packit |
a4aae4 |
// Yup... tell the story in the attributes.
|
|
Packit |
a4aae4 |
AttrTable *dv_table = Constructor::make_dropped_vars_attr_table(&dropped_maps);
|
|
Packit |
a4aae4 |
dest->get_attr_table().append_container(dv_table,dv_table->get_name());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
// It's not a Grid so we can make a simple copy of our Precious.
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - Array '"<< name() << "' is not a Grid!" << endl);
|
|
Packit |
a4aae4 |
BaseType *proto = this->prototype();
|
|
Packit |
a4aae4 |
switch(proto->type()){
|
|
Packit |
a4aae4 |
case dods_int64_c:
|
|
Packit |
a4aae4 |
case dods_uint64_c:
|
|
Packit |
a4aae4 |
case dods_enum_c:
|
|
Packit |
a4aae4 |
case dods_opaque_c:
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// For now we punt on these type as they have no easy representation in
|
|
Packit |
a4aae4 |
// the DAP2 data model. By setting this to NULL we cause the Array to be
|
|
Packit |
a4aae4 |
// dropped and this will be reflected in the metadata (DAS).
|
|
Packit |
a4aae4 |
dest = NULL;
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
dest = this->ptr_duplicate();
|
|
Packit |
a4aae4 |
// convert the d4 attributes to a dap2 attribute table.
|
|
Packit |
a4aae4 |
AttrTable *attrs = this->attributes()->get_AttrTable(name());
|
|
Packit |
a4aae4 |
dest->set_attr_table(*attrs);
|
|
Packit |
a4aae4 |
dest->set_is_dap4(false);
|
|
Packit |
a4aae4 |
AttrTable at = dest->get_attr_table();
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - " <<
|
|
Packit |
a4aae4 |
"DAS for new Array '" << dest->name() << "':" << endl;
|
|
Packit |
a4aae4 |
at.print(cerr); )
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
// If it's a DAP2 Array already then we just make a copy of our Precious.
|
|
Packit |
a4aae4 |
dest = this->ptr_duplicate();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// attrs->print(cerr,"",true);
|
|
Packit |
a4aae4 |
vector<BaseType *> *result;
|
|
Packit |
a4aae4 |
if(dest){
|
|
Packit |
a4aae4 |
result = new vector<BaseType *>();
|
|
Packit |
a4aae4 |
result->push_back(dest);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
result = NULL;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
DBG( cerr << __func__ << "() - END Array '"<< name() << "'" << endl;);
|
|
Packit |
a4aae4 |
return result;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Hackery that helps build a new D4Group from an old one. We need to re-wire the
|
|
Packit |
a4aae4 |
* D4Dimension (note the lack of an 's' at then end) that the copied Array objects
|
|
Packit |
a4aae4 |
* hold. This code does that. Note that these are 'weak pointers' so they should
|
|
Packit |
a4aae4 |
* never be freed - the D4Group object will take care of that.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @note The order of the D4Dimension instances matches in 'old_dims' and 'new_dims'.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param old_dims The Old D4Dimension objects (held in a D4Dimensions instance)
|
|
Packit |
a4aae4 |
* @param new_dims The New D4Dimension objects.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::update_dimension_pointers(D4Dimensions *old_dims, D4Dimensions *new_dims)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
std::vector<dimension>::iterator i = _shape.begin(), e = _shape.end();
|
|
Packit |
a4aae4 |
while (i != e) {
|
|
Packit |
a4aae4 |
D4Dimensions::D4DimensionsIter old_i = old_dims->dim_begin(), old_e = old_dims->dim_end();
|
|
Packit |
a4aae4 |
while (old_i != old_e) {
|
|
Packit |
a4aae4 |
if ((*i).dim == *old_i) {
|
|
Packit |
a4aae4 |
(*i).dim = new_dims->find_dim((*old_i)->name());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
++old_i;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
++i;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Add the BaseType pointer to this constructor type
|
|
Packit |
a4aae4 |
instance.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Propagate the name of the BaseType instance to this instance. This
|
|
Packit |
a4aae4 |
ensures that variables at any given level of the DDS table have
|
|
Packit |
a4aae4 |
unique names (i.e., that Arrays do not have their default name ""). If
|
|
Packit |
a4aae4 |
<tt>v</tt>'s name is null, then assume that the array \e is named and
|
|
Packit |
a4aae4 |
don't overwrite it with <tt>v</tt>'s null name.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@note It is possible for the BaseType pointer to be null when this
|
|
Packit |
a4aae4 |
method is called, a behavior that differs considerably from that of
|
|
Packit |
a4aae4 |
the other 'add_var()' methods.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@note This version checks to see if \e v is an array. If so, it calls
|
|
Packit |
a4aae4 |
Vector::add_var() using the template variable of \e v and then appends
|
|
Packit |
a4aae4 |
the dimensions of \e v to this array. This somewhat obscure behavior
|
|
Packit |
a4aae4 |
simplifies 'translating' Sequences to arrays when the actual variable
|
|
Packit |
a4aae4 |
being translated is not a regular Sequence but an array of Sequences.
|
|
Packit |
a4aae4 |
This is of very debatable usefulness, but it's here all the same.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param v The template variable for the array
|
|
Packit |
a4aae4 |
@param p The Part parameter defaults to nil and is ignored by this method.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::add_var(BaseType *v, Part)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// If 'v' is an Array, add the template instance to this object and
|
|
Packit |
a4aae4 |
// then copy the dimension information. Odd semantics; I wonder if this
|
|
Packit |
a4aae4 |
//is ever used. jhrg 6/13/12
|
|
Packit |
a4aae4 |
if (v && v->type() == dods_array_c) {
|
|
Packit |
a4aae4 |
Array *a = static_cast<Array*>(v);
|
|
Packit |
a4aae4 |
Vector::add_var(a->var());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Dim_iter i = a->dim_begin();
|
|
Packit |
a4aae4 |
Dim_iter i_end = a->dim_end();
|
|
Packit |
a4aae4 |
while (i != i_end) {
|
|
Packit |
a4aae4 |
append_dim(a->dimension_size(i), a->dimension_name(i));
|
|
Packit |
a4aae4 |
++i;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
Vector::add_var(v);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::add_var_nocopy(BaseType *v, Part)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// If 'v' is an Array, add the template instance to this object and
|
|
Packit |
a4aae4 |
// then copy the dimension information. Odd semantics; I wonder if this
|
|
Packit |
a4aae4 |
//is ever used. jhrg 6/13/12
|
|
Packit |
a4aae4 |
if (v && v->type() == dods_array_c) {
|
|
Packit |
a4aae4 |
Array &a = dynamic_cast<Array&>(*v);
|
|
Packit |
a4aae4 |
Vector::add_var_nocopy(a.var());
|
|
Packit |
a4aae4 |
Dim_iter i = a.dim_begin();
|
|
Packit |
a4aae4 |
Dim_iter i_end = a.dim_end();
|
|
Packit |
a4aae4 |
while (i != i_end) {
|
|
Packit |
a4aae4 |
append_dim(a.dimension_size(i), a.dimension_name(i));
|
|
Packit |
a4aae4 |
++i;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
Vector::add_var_nocopy(v);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Given a size and a name, this function adds a dimension to the
|
|
Packit |
a4aae4 |
array. For example, if the Array is already 10 elements long,
|
|
Packit |
a4aae4 |
calling <tt>append_dim</tt> with a size of 5 will transform the array
|
|
Packit |
a4aae4 |
into a 10x5 matrix. Calling it again with a size of 2 will
|
|
Packit |
a4aae4 |
create a 10x5x2 array, and so on. This sets Vector's length
|
|
Packit |
a4aae4 |
member as a side effect.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param size The size of the desired new row.
|
|
Packit |
a4aae4 |
@param name The name of the new dimension. This defaults to
|
|
Packit |
a4aae4 |
an empty string.
|
|
Packit |
a4aae4 |
@brief Add a dimension of a given size. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::append_dim(int size, const string &name)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
dimension d(size, www2id(name));
|
|
Packit |
a4aae4 |
_shape.push_back(d);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
update_length();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::append_dim(D4Dimension *dim)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
dimension d(/*dim->size(), www2id(dim->name()),*/ dim);
|
|
Packit |
a4aae4 |
_shape.push_back(d);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
update_length();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Creates a new OUTER dimension (slowest varying in rowmajor)
|
|
Packit |
a4aae4 |
* for the array by prepending rather than appending it.
|
|
Packit |
a4aae4 |
* @param size cardinality of the new dimension
|
|
Packit |
a4aae4 |
* @param name optional name for the new dimension
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::prepend_dim(int size, const string& name/* = "" */)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
dimension d(size, www2id(name));
|
|
Packit |
a4aae4 |
// Shifts the whole array, but it's tiny in general
|
|
Packit |
a4aae4 |
_shape.insert(_shape.begin(), d);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
update_length(); // the number is ignored...
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::prepend_dim(D4Dimension *dim)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
dimension d(/*dim->size(), www2id(dim->name()),*/ dim);
|
|
Packit |
a4aae4 |
// Shifts the whole array, but it's tiny in general
|
|
Packit |
a4aae4 |
_shape.insert(_shape.begin(), d);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
update_length(); // the number is ignored...
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Remove all the dimensions currently set for the Array. This also
|
|
Packit |
a4aae4 |
* removes all constraint information.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::clear_all_dims()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
_shape.clear();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
/** Resets the dimension constraint information so that the entire
|
|
Packit |
a4aae4 |
array is selected.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Reset constraint to select entire array.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::reset_constraint()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
set_length(-1);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
|
|
Packit |
a4aae4 |
(*i).start = 0;
|
|
Packit |
a4aae4 |
(*i).stop = (*i).size - 1;
|
|
Packit |
a4aae4 |
(*i).stride = 1;
|
|
Packit |
a4aae4 |
(*i).c_size = (*i).size;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
update_length();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Tell the Array object to clear the constraint information about
|
|
Packit |
a4aae4 |
dimensions. Do this once before calling <tt>add_constraint()</tt>
|
|
Packit |
a4aae4 |
for each new constraint expression. Only the dimensions explicitly
|
|
Packit |
a4aae4 |
selected using <tt>add_constraint()</tt> will be sent.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@deprecated This should never be used.
|
|
Packit |
a4aae4 |
@brief Clears the projection; add each projected dimension explicitly using
|
|
Packit |
a4aae4 |
<tt>add_constraint</tt>.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::clear_constraint()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
reset_constraint();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n
|
|
Packit |
a4aae4 |
// is explicit.
|
|
Packit |
a4aae4 |
static const char *array_sss = \
|
|
Packit |
a4aae4 |
"Invalid constraint parameters: At least one of the start, stride or stop \n\
|
|
Packit |
a4aae4 |
specified do not match the array variable.";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Once a dimension has been created (see append_dim()), it can
|
|
Packit |
a4aae4 |
be constrained. This will make the array appear to the rest
|
|
Packit |
a4aae4 |
of the world to be smaller than it is. This functions sets the
|
|
Packit |
a4aae4 |
projection for a dimension, and marks that dimension as part of the
|
|
Packit |
a4aae4 |
current projection.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@note A stride value <= 0 or > the array size is an error and causes
|
|
Packit |
a4aae4 |
add_constraint to throw an Error. Similarly, start or stop values >
|
|
Packit |
a4aae4 |
size also cause an Error exception to be thrown.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Adds a constraint to an Array dimension.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param i An iterator pointing to the dimension in the list of
|
|
Packit |
a4aae4 |
dimensions.
|
|
Packit |
a4aae4 |
@param start The start index of the constraint.
|
|
Packit |
a4aae4 |
@param stride The stride value of the constraint.
|
|
Packit |
a4aae4 |
@param stop The stop index of the constraint. A value of -1 indicates
|
|
Packit |
a4aae4 |
'to the end' of the array.
|
|
Packit |
a4aae4 |
@exception Error Thrown if the any of values of start, stop or stride
|
|
Packit |
a4aae4 |
cannot be applied to this array. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::add_constraint(Dim_iter i, int start, int stride, int stop)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
dimension &d = *i ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// if stop is -1, set it to the array's max element index
|
|
Packit |
a4aae4 |
// jhrg 12/20/12
|
|
Packit |
a4aae4 |
if (stop == -1)
|
|
Packit |
a4aae4 |
stop = d.size - 1;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Check for bad constraints.
|
|
Packit |
a4aae4 |
// Jose Garcia
|
|
Packit |
a4aae4 |
// Usually invalid data for a constraint is the user's mistake
|
|
Packit |
a4aae4 |
// because they build a wrong URL in the client side.
|
|
Packit |
a4aae4 |
if (start >= d.size || stop >= d.size || stride > d.size || stride <= 0)
|
|
Packit |
a4aae4 |
throw Error(malformed_expr, array_sss);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (((stop - start) / stride + 1) > d.size)
|
|
Packit |
a4aae4 |
throw Error(malformed_expr, array_sss);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d.start = start;
|
|
Packit |
a4aae4 |
d.stop = stop;
|
|
Packit |
a4aae4 |
d.stride = stride;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d.c_size = (stop - start) / stride + 1;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBG(cerr << "add_constraint: c_size = " << d.c_size << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
update_length();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d.use_sdim_for_slice = false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::add_constraint(Dim_iter i, D4Dimension *dim)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
dimension &d = *i ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (dim->constrained())
|
|
Packit |
a4aae4 |
add_constraint(i, dim->c_start(), dim->c_stride(), dim->c_stop());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dim->set_used_by_projected_var(true);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// In this case the value below overrides the value for use_sdim_for_slice
|
|
Packit |
a4aae4 |
// set in the above call. jhrg 12/20/13
|
|
Packit |
a4aae4 |
d.use_sdim_for_slice = true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Returns an iterator to the first dimension of the Array. */
|
|
Packit |
a4aae4 |
Array::Dim_iter
|
|
Packit |
a4aae4 |
Array::dim_begin()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return _shape.begin() ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Returns an iterator past the last dimension of the Array. */
|
|
Packit |
a4aae4 |
Array::Dim_iter
|
|
Packit |
a4aae4 |
Array::dim_end()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return _shape.end() ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
//TODO Many of these methods take a bool parameter that serves no use; remove.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Return the total number of dimensions contained in the array.
|
|
Packit |
a4aae4 |
When constrained is TRUE, return the number of dimensions
|
|
Packit |
a4aae4 |
given the most recently evaluated constraint expression.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Return the total number of dimensions in the array.
|
|
Packit |
a4aae4 |
@param constrained A boolean flag to indicate whether the array is
|
|
Packit |
a4aae4 |
constrained or not. Ignored.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
unsigned int
|
|
Packit |
a4aae4 |
Array::dimensions(bool /*constrained*/)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return _shape.size();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Return the size of the array dimension referred to by i.
|
|
Packit |
a4aae4 |
If the dimension is constrained the constrained size is returned if
|
|
Packit |
a4aae4 |
constrained is \c true.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Returns the size of the dimension.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param i The dimension.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param constrained If this parameter is TRUE, the method returns the
|
|
Packit |
a4aae4 |
constrained size of the array so long as a constraint has been applied to
|
|
Packit |
a4aae4 |
this dimension. If TRUE and no constraint has been applied, this method
|
|
Packit |
a4aae4 |
returns zero. If it is FALSE, the method ignores any constraint that
|
|
Packit |
a4aae4 |
has been applied to this dimension and returns the full size of the
|
|
Packit |
a4aae4 |
dimension. The default value is FALSE.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@return An integer containing the size of the specified dimension.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
int
|
|
Packit |
a4aae4 |
Array::dimension_size(Dim_iter i, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
int size = 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!_shape.empty()) {
|
|
Packit |
a4aae4 |
if (constrained)
|
|
Packit |
a4aae4 |
size = (*i).c_size;
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
size = (*i).size;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return size;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Use this function to return the start index of an array
|
|
Packit |
a4aae4 |
dimension. If the array is constrained (indicated with the
|
|
Packit |
a4aae4 |
constrained argument), the start index of the constrained
|
|
Packit |
a4aae4 |
array is returned (or zero if the dimension in question is not
|
|
Packit |
a4aae4 |
selected at all). See also <tt>dimension_stop()</tt> and
|
|
Packit |
a4aae4 |
<tt>dimension_stride()</tt>.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Return the start index of a dimension.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param i The dimension.
|
|
Packit |
a4aae4 |
@param constrained If this parameter is TRUE, the function
|
|
Packit |
a4aae4 |
returns the start index only if the dimension is constrained
|
|
Packit |
a4aae4 |
(subject to a start, stop, or stride constraint). If
|
|
Packit |
a4aae4 |
the dimension is not constrained, the function returns zero. If it
|
|
Packit |
a4aae4 |
is FALSE, the function returns the start index whether or not
|
|
Packit |
a4aae4 |
the dimension is constrained.
|
|
Packit |
a4aae4 |
@return The desired start index.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
int
|
|
Packit |
a4aae4 |
Array::dimension_start(Dim_iter i, bool /*constrained*/)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return (!_shape.empty()) ? (*i).start : 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Use this function to return the stop index of an array
|
|
Packit |
a4aae4 |
dimension. If the array is constrained (indicated with the
|
|
Packit |
a4aae4 |
constrained argument), the stop index of the constrained
|
|
Packit |
a4aae4 |
array is returned (or zero if the dimension in question is not
|
|
Packit |
a4aae4 |
selected at all). See also <tt>dimension_start()</tt> and
|
|
Packit |
a4aae4 |
<tt>dimension_stride()</tt>.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Return the stop index of the constraint.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param i The dimension.
|
|
Packit |
a4aae4 |
@param constrained If this parameter is TRUE, the function
|
|
Packit |
a4aae4 |
returns the stop index only if the dimension is constrained
|
|
Packit |
a4aae4 |
(subject to a start, stop, or stride constraint). If
|
|
Packit |
a4aae4 |
the dimension is not constrained, the function returns zero. If it
|
|
Packit |
a4aae4 |
is FALSE, the function returns the stop index whether or not
|
|
Packit |
a4aae4 |
the dimension is constrained.
|
|
Packit |
a4aae4 |
@return The desired stop index.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
int
|
|
Packit |
a4aae4 |
Array::dimension_stop(Dim_iter i, bool /*constrained*/)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return (!_shape.empty()) ? (*i).stop : 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Use this function to return the stride value of an array
|
|
Packit |
a4aae4 |
dimension. If the array is constrained (indicated with the
|
|
Packit |
a4aae4 |
constrained argument), the stride value of the constrained
|
|
Packit |
a4aae4 |
array is returned (or zero if the dimension in question is not
|
|
Packit |
a4aae4 |
selected at all). See also <tt>dimension_stop()</tt> and
|
|
Packit |
a4aae4 |
<tt>dimension_start()</tt>.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Returns the stride value of the constraint.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param i The dimension.
|
|
Packit |
a4aae4 |
@param constrained If this parameter is TRUE, the function
|
|
Packit |
a4aae4 |
returns the stride value only if the dimension is constrained
|
|
Packit |
a4aae4 |
(subject to a start, stop, or stride constraint). If
|
|
Packit |
a4aae4 |
the dimension is not constrained, the function returns zero. If it
|
|
Packit |
a4aae4 |
is FALSE, the function returns the stride value whether or not
|
|
Packit |
a4aae4 |
the dimension is constrained.
|
|
Packit |
a4aae4 |
@return The stride value requested, or zero, if constrained
|
|
Packit |
a4aae4 |
is TRUE and the dimension is not selected.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
int
|
|
Packit |
a4aae4 |
Array::dimension_stride(Dim_iter i, bool /*constrained*/)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return (!_shape.empty()) ? (*i).stride : 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** This function returns the name of the dimension indicated with
|
|
Packit |
a4aae4 |
p. Since this method is public, it is possible to call it
|
|
Packit |
a4aae4 |
before the Array object has been properly initialized. This will
|
|
Packit |
a4aae4 |
cause an exception. So don't do that.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Returns the name of the specified dimension.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param i The dimension.
|
|
Packit |
a4aae4 |
@return A pointer to a string containing the dimension name.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
string
|
|
Packit |
a4aae4 |
Array::dimension_name(Dim_iter i)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// Jose Garcia
|
|
Packit |
a4aae4 |
// Since this method is public, it is possible for a user
|
|
Packit |
a4aae4 |
// to call it before the Array object has been properly set
|
|
Packit |
a4aae4 |
// this will cause an exception which is the user's fault.
|
|
Packit |
a4aae4 |
// (User in this context is the developer of the surrogate library.)
|
|
Packit |
a4aae4 |
if (_shape.empty())
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__,
|
|
Packit |
a4aae4 |
"*This* array has no dimensions.");
|
|
Packit |
a4aae4 |
return (*i).name;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
D4Dimension *
|
|
Packit |
a4aae4 |
Array::dimension_D4dim(Dim_iter i)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return (!_shape.empty()) ? (*i).dim : 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
D4Maps *
|
|
Packit |
a4aae4 |
Array::maps()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!d_maps) d_maps = new D4Maps(this); // init with this as parent
|
|
Packit |
a4aae4 |
return d_maps;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Returns the width of the data, in bytes.
|
|
Packit |
a4aae4 |
* @param constrained if true, return the size of the array in bytes taking into
|
|
Packit |
a4aae4 |
* account the current constraints on various dimensions. False by default.
|
|
Packit |
a4aae4 |
* @return The number of bytes needed to store the array values.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
unsigned int Array::width(bool constrained) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (constrained) {
|
|
Packit |
a4aae4 |
// This preserves the original method's semantics when we ask for the
|
|
Packit |
a4aae4 |
// size of the constrained array but no constraint has been applied.
|
|
Packit |
a4aae4 |
// In this case, length will be -1. Wrong, I know...
|
|
Packit |
a4aae4 |
return length() * var()->width(constrained);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
int length = 1;
|
|
Packit |
a4aae4 |
for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
|
|
Packit |
a4aae4 |
length *= dimension_size(i, false);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
return length * var()->width(false);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
class PrintD4ArrayDimXMLWriter: public unary_function<Array::dimension&, void> {
|
|
Packit |
a4aae4 |
XMLWriter &xml;
|
|
Packit |
a4aae4 |
// Was this variable constrained using local/direct slicing? i.e., is d_local_constraint set?
|
|
Packit |
a4aae4 |
// If so, don't use shared dimensions; instead emit Dim elements that are anonymous.
|
|
Packit |
a4aae4 |
bool d_constrained;
|
|
Packit |
a4aae4 |
public:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
PrintD4ArrayDimXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) { }
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void operator()(Array::dimension &d)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// This duplicates code in D4Dimensions (where D4Dimension::print_dap4() is defined
|
|
Packit |
a4aae4 |
// because of the need to print the constrained size of a dimension. I think that
|
|
Packit |
a4aae4 |
// the constraint information has to be kept here and not in the dimension (since they
|
|
Packit |
a4aae4 |
// are shared dims). Could hack print_dap4() to take the constrained size, however.
|
|
Packit |
a4aae4 |
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dim") < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not write Dim element");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
string name = (d.dim) ? d.dim->fully_qualified_name() : d.name;
|
|
Packit |
a4aae4 |
// If there is a name, there must be a Dimension (named dimension) in scope
|
|
Packit |
a4aae4 |
// so write its name but not its size.
|
|
Packit |
a4aae4 |
if (!d_constrained && !name.empty()) {
|
|
Packit |
a4aae4 |
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name.c_str())
|
|
Packit |
a4aae4 |
< 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (d.use_sdim_for_slice) {
|
|
Packit |
a4aae4 |
assert(!name.empty());
|
|
Packit |
a4aae4 |
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name.c_str())
|
|
Packit |
a4aae4 |
< 0) throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
ostringstream size;
|
|
Packit |
a4aae4 |
size << (d_constrained ? d.c_size : d.size);
|
|
Packit |
a4aae4 |
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size",
|
|
Packit |
a4aae4 |
(const xmlChar*) size.str().c_str()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not end Dim element");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
};
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
class PrintD4ConstructorVarXMLWriter: public unary_function<BaseType*, void> {
|
|
Packit |
a4aae4 |
XMLWriter &xml;
|
|
Packit |
a4aae4 |
bool d_constrained;
|
|
Packit |
a4aae4 |
public:
|
|
Packit |
a4aae4 |
PrintD4ConstructorVarXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) { }
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void operator()(BaseType *btp)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
btp->print_dap4(xml, d_constrained);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
};
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
class PrintD4MapXMLWriter: public unary_function<D4Map*, void> {
|
|
Packit |
a4aae4 |
XMLWriter &xml;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
public:
|
|
Packit |
a4aae4 |
PrintD4MapXMLWriter(XMLWriter &xml) : xml(xml) { }
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void operator()(D4Map *m)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
m->print_dap4(xml);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
};
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Print the DAP4 representation of an array.
|
|
Packit |
a4aae4 |
* @param xml
|
|
Packit |
a4aae4 |
* @param constrained
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::print_dap4(XMLWriter &xml, bool constrained /* default: false*/)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (constrained && !send_p()) return;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) var()->type_name().c_str()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not write " + type_name() + " 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 |
// Hack job... Copied from D4Enum::print_xml_writer. jhrg 11/12/13
|
|
Packit |
a4aae4 |
if (var()->type() == dods_enum_c) {
|
|
Packit |
a4aae4 |
D4Enum *e = static_cast<D4Enum*>(var());
|
|
Packit |
a4aae4 |
string path = e->enumeration()->name();
|
|
Packit |
a4aae4 |
if (e->enumeration()->parent()) {
|
|
Packit |
a4aae4 |
// print the FQN for the enum def; D4Group::FQN() includes the trailing '/'
|
|
Packit |
a4aae4 |
path = static_cast<D4Group*>(e->enumeration()->parent()->parent())->FQN() + path;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "enum", (const xmlChar*)path.c_str()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for enum");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (prototype()->is_constructor_type()) {
|
|
Packit |
a4aae4 |
Constructor &c = static_cast<Constructor&>(*prototype());
|
|
Packit |
a4aae4 |
for_each(c.var_begin(), c.var_end(), PrintD4ConstructorVarXMLWriter(xml, constrained));
|
|
Packit |
a4aae4 |
// bind2nd(mem_fun_ref(&BaseType::print_dap4), xml));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Drop the local_constraint which is per-array and use a per-dimension on instead
|
|
Packit |
a4aae4 |
for_each(dim_begin(), dim_end(), PrintD4ArrayDimXMLWriter(xml, constrained));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
attributes()->print_dap4(xml);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for_each(maps()->map_begin(), maps()->map_end(), PrintD4MapXMLWriter(xml));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not end " + type_name() + " element");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Prints a declaration for the Array. This is what appears in a
|
|
Packit |
a4aae4 |
DDS. If the Array is constrained, the declaration will reflect
|
|
Packit |
a4aae4 |
the size of the Array once the constraint is applied.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Prints a DDS entry for the Array.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param out Write the output to this FILE *.
|
|
Packit |
a4aae4 |
@param space A string containing spaces to precede the
|
|
Packit |
a4aae4 |
declaration.
|
|
Packit |
a4aae4 |
@param print_semi A boolean indicating whether to print a
|
|
Packit |
a4aae4 |
semi-colon after the declaration. (TRUE means ``print a
|
|
Packit |
a4aae4 |
semi-colon.'')
|
|
Packit |
a4aae4 |
@param constraint_info A boolean value. See
|
|
Packit |
a4aae4 |
<tt>BaseType::print_decl()</tt>.
|
|
Packit |
a4aae4 |
@param constrained This argument should be TRUE if the Array is
|
|
Packit |
a4aae4 |
constrained, and FALSE otherwise.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::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 |
/** Prints a declaration for the Array. This is what appears in a
|
|
Packit |
a4aae4 |
DDS. If the Array is constrained, the declaration will reflect
|
|
Packit |
a4aae4 |
the size of the Array once the constraint is applied.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Prints a DDS entry for the Array.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param out Write the output to this ostream.
|
|
Packit |
a4aae4 |
@param space A string containing spaces to precede the
|
|
Packit |
a4aae4 |
declaration.
|
|
Packit |
a4aae4 |
@param print_semi A boolean indicating whether to print a
|
|
Packit |
a4aae4 |
semi-colon after the declaration. (TRUE means ``print a
|
|
Packit |
a4aae4 |
semi-colon.'')
|
|
Packit |
a4aae4 |
@param constraint_info A boolean value. See
|
|
Packit |
a4aae4 |
<tt>BaseType::print_decl()</tt>.
|
|
Packit |
a4aae4 |
@param constrained This argument should be TRUE if the Array is
|
|
Packit |
a4aae4 |
constrained, and FALSE otherwise.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void Array::print_decl(ostream &out, string space, bool print_semi, bool constraint_info, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (constrained && !send_p()) return;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// print it, but w/o semicolon
|
|
Packit |
a4aae4 |
var()->print_decl(out, space, false, constraint_info, constrained);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
|
|
Packit |
a4aae4 |
out << "[";
|
|
Packit |
a4aae4 |
if ((*i).name != "") {
|
|
Packit |
a4aae4 |
out << id2www((*i).name) << " = ";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
if (constrained) {
|
|
Packit |
a4aae4 |
out << (*i).c_size << "]";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
out << (*i).size << "]";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (print_semi) {
|
|
Packit |
a4aae4 |
out << ";\n";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @deprecated
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::print_xml(FILE *out, string space, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
XMLWriter xml(space);
|
|
Packit |
a4aae4 |
print_xml_writer_core(xml, constrained, "Array");
|
|
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 |
Array::print_xml(ostream &out, string space, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
XMLWriter xml(space);
|
|
Packit |
a4aae4 |
print_xml_writer_core(xml, constrained, "Array");
|
|
Packit |
a4aae4 |
out << xml.get_doc();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @deprecated
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::print_as_map_xml(FILE *out, string space, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
XMLWriter xml(space);
|
|
Packit |
a4aae4 |
print_xml_writer_core(xml, constrained, "Map");
|
|
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 |
Array::print_as_map_xml(ostream &out, string space, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
XMLWriter xml(space);
|
|
Packit |
a4aae4 |
print_xml_writer_core(xml, constrained, "Map");
|
|
Packit |
a4aae4 |
out << xml.get_doc();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @deprecated
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::print_xml_core(FILE *out, string space, bool constrained, string tag)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
XMLWriter xml(space);
|
|
Packit |
a4aae4 |
print_xml_writer_core(xml, constrained, tag);
|
|
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 |
Array::print_xml_core(ostream &out, string space, bool constrained, string tag)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
XMLWriter xml(space);
|
|
Packit |
a4aae4 |
print_xml_writer_core(xml, constrained, tag);
|
|
Packit |
a4aae4 |
out << xml.get_doc();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::print_xml_writer(XMLWriter &xml, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
print_xml_writer_core(xml, constrained, "Array");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::print_as_map_xml_writer(XMLWriter &xml, bool constrained)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
print_xml_writer_core(xml, constrained, "Map");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
class PrintArrayDimXMLWriter : public unary_function<Array::dimension&, void>
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
XMLWriter &xml;
|
|
Packit |
a4aae4 |
bool d_constrained;
|
|
Packit |
a4aae4 |
public:
|
|
Packit |
a4aae4 |
PrintArrayDimXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) {}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void operator()(Array::dimension &d)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"dimension") < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not write dimension element");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!d.name.empty())
|
|
Packit |
a4aae4 |
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d.name.c_str()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
ostringstream size;
|
|
Packit |
a4aae4 |
size << (d_constrained ? d.c_size : d.size);
|
|
Packit |
a4aae4 |
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size", (const xmlChar*)size.str().c_str()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not end dimension element");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
};
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::print_xml_writer_core(XMLWriter &xml, bool constrained, string tag)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (constrained && !send_p())
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)tag.c_str()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not write " + tag + " 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 |
BaseType *btp = var();
|
|
Packit |
a4aae4 |
string tmp_name = btp->name();
|
|
Packit |
a4aae4 |
btp->set_name("");
|
|
Packit |
a4aae4 |
btp->print_xml_writer(xml, constrained);
|
|
Packit |
a4aae4 |
btp->set_name(tmp_name);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for_each(dim_begin(), dim_end(), PrintArrayDimXMLWriter(xml, constrained));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Could not end " + tag + " element");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Prints the values in ASCII of the entire (constrained) array. This method
|
|
Packit |
a4aae4 |
Attempts to make an aesthetically pleasing display. However, it is
|
|
Packit |
a4aae4 |
primarily intended for debugging purposes.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param out Write the output to this FILE *.
|
|
Packit |
a4aae4 |
@param index
|
|
Packit |
a4aae4 |
@param dims
|
|
Packit |
a4aae4 |
@param shape
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Print the value given the current constraint.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
unsigned int
|
|
Packit |
a4aae4 |
Array::print_array(FILE *out, unsigned int index, unsigned int dims,
|
|
Packit |
a4aae4 |
unsigned int shape[])
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
ostringstream oss;
|
|
Packit |
a4aae4 |
unsigned int i = print_array(oss, index, dims, shape);
|
|
Packit |
a4aae4 |
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return i;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Prints the values in ASCII of the entire (constrained) array. This method
|
|
Packit |
a4aae4 |
Attempts to make an anesthetically pleasing display. However, it is
|
|
Packit |
a4aae4 |
primarily intended for debugging purposes.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param out Write the output to this ostream
|
|
Packit |
a4aae4 |
@param index
|
|
Packit |
a4aae4 |
@param dims
|
|
Packit |
a4aae4 |
@param shape
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Print the value given the current constraint.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
unsigned int Array::print_array(ostream &out, unsigned int index, unsigned int dims, unsigned int shape[])
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (dims == 1) {
|
|
Packit |
a4aae4 |
out << "{";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Added test in case this method is passed an array with no elements. jhrg 1/27/16
|
|
Packit |
a4aae4 |
if (shape[0] >= 1) {
|
|
Packit |
a4aae4 |
for (unsigned i = 0; i < shape[0] - 1; ++i) {
|
|
Packit |
a4aae4 |
var(index++)->print_val(out, "", false);
|
|
Packit |
a4aae4 |
out << ", ";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
var(index++)->print_val(out, "", false);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << "}";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return index;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
out << "{";
|
|
Packit |
a4aae4 |
// Fixed an off-by-one error in the following loop. Since the array
|
|
Packit |
a4aae4 |
// length is shape[dims-1]-1 *and* since we want one less dimension
|
|
Packit |
a4aae4 |
// than that, the correct limit on this loop is shape[dims-2]-1. From
|
|
Packit |
a4aae4 |
// Todd Karakasian.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// The saga continues; the loop test should be `i < shape[0]-1'. jhrg
|
|
Packit |
a4aae4 |
// 9/12/96.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// For arrays that hold zero values but have rank > 1, the print out
|
|
Packit |
a4aae4 |
// may look a little odd (e.g., x[4][0] will print as { {}, {}, {}, {} })
|
|
Packit |
a4aae4 |
// but it's not wrong and this is really for debugging mostly. jhrg 1/28/16
|
|
Packit |
a4aae4 |
if (shape[0] > 0) {
|
|
Packit |
a4aae4 |
for (unsigned i = 0; i < shape[0] - 1; ++i) {
|
|
Packit |
a4aae4 |
index = print_array(out, index, dims - 1, shape + 1);
|
|
Packit |
a4aae4 |
out << ",";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
index = print_array(out, index, dims - 1, shape + 1);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << "}";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return index;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Array::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
|
|
Packit |
a4aae4 |
Array::print_val(ostream &out, string space, bool print_decl_p)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// print the declaration if print decl is true.
|
|
Packit |
a4aae4 |
// for each dimension,
|
|
Packit |
a4aae4 |
// for each element,
|
|
Packit |
a4aae4 |
// print the array given its shape, number of dimensions.
|
|
Packit |
a4aae4 |
// Add the `;'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (print_decl_p) {
|
|
Packit |
a4aae4 |
print_decl(out, space, false, false, false);
|
|
Packit |
a4aae4 |
out << " = " ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
unsigned int *shape = new unsigned int[dimensions(true)];
|
|
Packit |
a4aae4 |
unsigned int index = 0;
|
|
Packit |
a4aae4 |
for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i)
|
|
Packit |
a4aae4 |
shape[index++] = dimension_size(i, true);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
print_array(out, 0, dimensions(true), shape);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
delete [] shape; shape = 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (print_decl_p) {
|
|
Packit |
a4aae4 |
out << ";\n" ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** This function checks semantic features of the Array. Currently,
|
|
Packit |
a4aae4 |
the only check specific to the Array is that there must be
|
|
Packit |
a4aae4 |
dimensions. The rest is inherited from
|
|
Packit |
a4aae4 |
<tt>BaseType::check_semantics()</tt>.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Check semantic features of the Array.
|
|
Packit |
a4aae4 |
@return A boolean value. FALSE means there was a problem.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
bool
|
|
Packit |
a4aae4 |
Array::check_semantics(string &msg, bool)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
bool sem = BaseType::check_semantics(msg) && !_shape.empty();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!sem)
|
|
Packit |
a4aae4 |
msg = "An array variable must have dimensions";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return sem;
|
|
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 |
Array::dump(ostream &strm) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "Array::dump - ("
|
|
Packit |
a4aae4 |
<< (void *)this << ")" << endl ;
|
|
Packit |
a4aae4 |
DapIndent::Indent() ;
|
|
Packit |
a4aae4 |
Vector::dump(strm) ;
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "shape:" << endl ;
|
|
Packit |
a4aae4 |
DapIndent::Indent() ;
|
|
Packit |
a4aae4 |
Dim_citer i = _shape.begin() ;
|
|
Packit |
a4aae4 |
Dim_citer ie = _shape.end() ;
|
|
Packit |
a4aae4 |
unsigned int dim_num = 0 ;
|
|
Packit |
a4aae4 |
for (; i != ie; i++) {
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "dimension " << dim_num++ << ":"
|
|
Packit |
a4aae4 |
<< endl ;
|
|
Packit |
a4aae4 |
DapIndent::Indent() ;
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "name: " << (*i).name << endl ;
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "size: " << (*i).size << endl ;
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "start: " << (*i).start << endl ;
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "stop: " << (*i).stop << endl ;
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "stride: " << (*i).stride << endl ;
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "constrained size: " << (*i).c_size
|
|
Packit |
a4aae4 |
<< endl ;
|
|
Packit |
a4aae4 |
DapIndent::UnIndent() ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
DapIndent::UnIndent() ;
|
|
Packit |
a4aae4 |
DapIndent::UnIndent() ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // namespace libdap
|
|
Packit |
a4aae4 |
|