Vector.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 1995-1999
// Please read the full copyright statement in the file COPYRIGHT_URI.
//
// Authors:
// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
// Implementation for class Vector. This class is the basis for all the
// vector-type classes in libdap's <Array, List>.
//
// 11/21/95 jhrg
#include "config.h"
#include <cassert>
#include <cstdint>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <typeinfo>
#include <vector>
#include "crc.h"
#include "Marshaller.h"
#include "UnMarshaller.h"
#include "Vector.h"
#include "D4StreamMarshaller.h"
#include "D4StreamUnMarshaller.h"
#include "D4Enum.h"
#include "DapIndent.h"
#include "InternalErr.h"
#include "Type.h"
#include "debug.h"
#include "dods-datatypes.h"
#include "dods-limits.h"
#include "escaping.h"
#undef CLEAR_LOCAL_DATA
using std::cerr;
using std::endl;
namespace libdap {
void Vector::m_duplicate(const Vector &v) {
d_length = v.d_length;
d_length_ll = v.d_length_ll;
// _var holds the type of the elements. That is, it holds a BaseType
// which acts as a template for the type of each element.
if (v.d_proto) {
// Vector manages this ptr, delete before assigning a new object. jhrg 2/19/22
if (d_proto)
delete d_proto;
d_proto = v.d_proto->ptr_duplicate(); // use ptr_duplicate()
d_proto->set_parent(this); // ptr_duplicate does not set d_parent.
} else {
d_proto = nullptr;
}
// d_compound_buf and d_buf (further down) hold the values of the Vector. The field
// d_compound_buf is used when the Vector holds non-numeric data (including strings,
// although it used to be that was not the case jhrg 2/10/05) while d_buf
// holds numeric values.
if (v.d_compound_buf.empty()) {
d_compound_buf = v.d_compound_buf;
} else {
// Failure to set the size will make the [] operator barf on the LHS
// of the assignment inside the loop.
d_compound_buf.resize(d_length);
for (int i = 0; i < d_length; ++i) {
// There's no need to call set_parent() for each element; we
// maintain the back pointer using the d_proto member. These
// instances are used to hold _values_ only while the d_proto
// field holds the type information for the elements.
d_compound_buf[i] = v.d_compound_buf[i]->ptr_duplicate();
}
}
// copy the strings. This copies the values.
d_str = v.d_str;
// copy numeric values if there are any.
d_buf = 0; // init to null
if (v.d_buf) // only copy if data present
val2buf(v.d_buf); // store v's value in this's _BUF.
d_capacity = v.d_capacity;
d_capacity_ll = v.d_capacity_ll;
}
bool Vector::m_is_cardinal_type() const {
// Not cardinal if no d_proto at all!
if (!d_proto) {
return false;
}
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_float32_c:
case dods_float64_c:
// New cardinal types for DAP4
case dods_int8_c:
case dods_uint8_c:
case dods_int64_c:
case dods_uint64_c:
case dods_enum_c:
return true;
// These must be handled differently.
case dods_str_c:
case dods_url_c:
case dods_opaque_c:
case dods_array_c:
case dods_structure_c:
case dods_sequence_c:
case dods_grid_c:
return false;
default:
assert("Vector::var: Unrecognized type");
return false;
}
}
int64_t Vector::m_create_cardinal_data_buffer_for_type(int64_t num_elements) {
// Make sure we HAVE a _var, or we cannot continue.
if (!d_proto) {
throw InternalErr(__FILE__, __LINE__, "create_cardinal_data_buffer_for_type: Logic error: _var is null!");
}
// Make sure we only do this for the correct data types.
if (!m_is_cardinal_type()) {
throw InternalErr(__FILE__, __LINE__,
"create_cardinal_data_buffer_for_type: incorrectly used on Vector whose type was not a "
"cardinal (simple data types).");
}
// Handle this special case where this is an array that holds no values
if (num_elements == 0)
return 0;
m_delete_cardinal_data_buffer();
// Actually new up the array with enough bytes to hold numEltsOfType of the actual type.
#if 0
unsigned int bytesPerElt = d_proto->width();
unsigned int bytesNeeded = bytesPerElt * numEltsOfType;
#endif
int64_t bytesNeeded = d_proto->width_ll() * num_elements;
d_buf = new char[bytesNeeded];
#if 0
d_capacity = (unsigned long long)num_elements;
#endif
set_value_capacity((uint64_t)num_elements);
return bytesNeeded;
}
void Vector::m_delete_cardinal_data_buffer() {
delete[] d_buf;
d_buf = nullptr;
d_capacity = 0;
d_capacity_ll = 0;
}
template <class CardType> void Vector::m_set_cardinal_values_internal(const CardType *fromArray, int64_t numElts) {
if (numElts < 0) {
throw InternalErr(__FILE__, __LINE__,
"Logic error: Vector::set_cardinal_values_internal() called with negative numElts!");
}
if (!fromArray) {
throw InternalErr(__FILE__, __LINE__,
"Logic error: Vector::set_cardinal_values_internal() called with null fromArray!");
}
set_length_ll(numElts);
m_create_cardinal_data_buffer_for_type(numElts);
if (d_buf)
memcpy(d_buf, fromArray, numElts * sizeof(CardType));
set_read_p(true);
}
Vector::Vector(const string &n, BaseType *v, const Type &t, bool is_dap4 /* default:false */)
: BaseType(n, t, is_dap4) {
if (v)
add_var(v);
DBG2(cerr << "Entering Vector ctor for object: " << this << endl);
if (d_proto)
d_proto->set_parent(this);
}
Vector::Vector(const string &n, const string &d, BaseType *v, const Type &t, bool is_dap4 /* default:false */)
: BaseType(n, d, t, is_dap4) {
if (v)
add_var(v);
DBG2(cerr << "Entering Vector ctor for object: " << this << endl);
if (d_proto)
d_proto->set_parent(this);
}
Vector::Vector(const Vector &rhs)
: BaseType(rhs)
{
DBG2(cerr << "Entering Vector const ctor for object: " << this << endl);
DBG2(cerr << "RHS: " << &rhs << endl);
m_duplicate(rhs);
}
Vector::~Vector() {
delete d_proto;
d_proto = nullptr;
// Clears all buffers
try {
Vector::clear_local_data();
} catch (const std::exception &) {
// It's hard to know what to do - Log it when we can, but that can fail, too.
}
}
Vector &Vector::operator=(const Vector &rhs) {
if (this == &rhs)
return *this;
BaseType::operator=(rhs);
m_duplicate(rhs);
return *this;
}
void Vector::set_name(const std::string &name) {
BaseType::set_name(name);
// We need to set the prototype name as well since
// this is what gets output in the dds! Otherwise, there's a mismatch.
if (d_proto) {
d_proto->set_name(name);
}
}
int Vector::element_count(bool leaves) {
if (!leaves)
return 1;
else
return d_proto->element_count(leaves);
// var() only works for simple types!
// jhrg 8/19/13 return var(0)->element_count(leaves);
}
// These mfuncs set the _send_p and _read_p fields of BaseType. They differ
// from BaseType's version in that they set both the Vector object's copy of
// _send_p (_read_p) but also _VAR's copy. This does not matter much when _VAR
// is a scalar, but does matter when it is an aggregate.
void Vector::set_send_p(bool state) {
if (d_proto) {
d_proto->set_send_p(state);
// because some code may depend on the BaseType*s held in d_compound_buf
// behaving as if they are 'ordinary' DAP variables, make sure their send_p
// flag is set if they exist. Because space in the vector is allocated
// before values (BaseType*s) are added, check for nulls and limit the
// iteration to only those elements actually in the object including any
// constraints that may have been applied - these are values not declarations.
// jhrg 5/13/16
switch (d_proto->type()) {
case dods_structure_c:
case dods_sequence_c:
case dods_grid_c:
if (d_compound_buf.size() > 0) {
for (unsigned long long i = 0; i < (unsigned)d_length; ++i) {
if (d_compound_buf[i])
d_compound_buf[i]->set_send_p(state);
}
}
break;
default:
break;
}
}
BaseType::set_send_p(state);
}
void Vector::set_read_p(bool state) {
if (d_proto) {
d_proto->set_read_p(state);
// See comment above.
switch (d_proto->type()) {
case dods_structure_c:
case dods_sequence_c:
case dods_grid_c:
if (d_compound_buf.size() > 0) {
for (unsigned long long i = 0; i < (unsigned)d_length; ++i) {
if (d_compound_buf[i])
d_compound_buf[i]->set_read_p(state);
}
}
break;
default:
break;
}
}
BaseType::set_read_p(state);
}
void Vector::set_length(int64_t l) { Vector::set_length_ll(l); }
void Vector::set_length_ll(int64_t l) {
d_length_ll = l;
if (l <= DODS_INT_MAX)
d_length = (int)l;
else {
d_length = -1;
d_too_big_for_dap2 = true;
}
}
void Vector::set_value_capacity(uint64_t l) {
d_capacity_ll = l;
if (l <= DODS_UINT_MAX)
d_capacity = (unsigned int)l;
else {
d_capacity = 0;
d_too_big_for_dap2 = true;
}
}
BaseType *Vector::var(const string &n, bool exact, btp_stack *s) {
string name = www2id(n);
DBG2(cerr << "Vector::var: Looking for " << name << endl);
if (name.empty() || d_proto->name() == name) {
if (s)
s->push(this);
return d_proto;
}
// If this is a Vector of constructor types, look for 'name' recursively.
// Make sure to check for the case where name is the default (the empty
// string). 9/1/98 jhrg
if (d_proto->is_constructor_type()) {
BaseType *result = d_proto->var(name, exact, s);
if (result && s)
s->push(this);
return result;
}
return NULL;
}
BaseType *Vector::var(const string &n, btp_stack &s) {
string name = www2id(n);
if (d_proto->is_constructor_type())
return d_proto->var(name, s);
else {
s.push((BaseType *)this);
return d_proto;
}
}
#if 0
BaseType *Vector::var(unsigned int i)
{
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int8_c:
case dods_uint8_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_int64_c:
case dods_uint64_c:
case dods_enum_c:
case dods_float32_c:
case dods_float64_c:
// Transfer the ith value to the BaseType *d_proto
d_proto->val2buf(d_buf + (i * (uint64_t)d_proto->width_ll()));
return d_proto;
case dods_str_c:
case dods_url_c:
d_proto->val2buf(&d_str[i]);
return d_proto;
case dods_opaque_c:
case dods_array_c:
case dods_structure_c:
case dods_sequence_c:
case dods_grid_c:
return d_compound_buf[i];
default:
throw Error ("Vector::var: Unrecognized type");
}
}
#endif
BaseType *Vector::var(unsigned int i) { return var_ll(i); }
BaseType *Vector::var_ll(uint64_t i) {
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int8_c:
case dods_uint8_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_int64_c:
case dods_uint64_c:
case dods_enum_c:
case dods_float32_c:
case dods_float64_c:
// Transfer the ith value to the BaseType *d_proto
d_proto->val2buf(d_buf + (i * (uint64_t)d_proto->width_ll()));
return d_proto;
case dods_str_c:
case dods_url_c:
d_proto->val2buf(&d_str[i]);
return d_proto;
case dods_opaque_c:
case dods_array_c:
case dods_structure_c:
case dods_sequence_c:
case dods_grid_c:
return d_compound_buf[i];
default:
throw Error("Vector::var: Unrecognized type");
}
}
void Vector::vec_resize(int l) {
// I added this check, which alters the behavior of the method. jhrg 8/14/13
if (m_is_cardinal_type())
throw InternalErr(__FILE__, __LINE__, "Vector::vec_resize() is applicable to compound types only");
// Use resize() since other parts of the code use operator[]. Note that size() should
// be used when resize() is used. Using capacity() creates problems as noted in the
// comment in set_vec_nocopy(). jhrg 5/19/17
d_compound_buf.resize(l, 0); // Fill with NULLs
#if 0
d_capacity = d_compound_buf.size(); // size in terms of number of elements.
#endif
set_value_capacity(d_compound_buf.size());
}
void Vector::vec_resize_ll(int64_t l) {
// I added this check, which alters the behavior of the method. jhrg 8/14/13
if (m_is_cardinal_type())
throw InternalErr(__FILE__, __LINE__, "Vector::vec_resize() is applicable to compound types only");
// Use resize() since other parts of the code use operator[]. Note that size() should
// be used when resize() is used. Using capacity() creates problems as noted in the
// comment in set_vec_nocopy(). jhrg 5/19/17
d_compound_buf.resize(l, nullptr); // Fill with NULLs
#if 0
d_capacity = d_compound_buf.size(); // size in terms of number of elements.
#endif
set_value_capacity(d_compound_buf.size());
}
void Vector::intern_data(ConstraintEvaluator &eval, DDS &dds) {
DBG(cerr << "Vector::intern_data: " << name() << endl);
if (is_dap4())
throw Error(string("A method usable only with DAP2 variables was called on a DAP4 variable (")
.append(name())
.append(")."),
__FILE__, __LINE__);
if (!read_p())
read(); // read() throws Error and InternalErr
// length() is not capacity; it must be set explicitly in read().
int num = length();
switch (d_proto->type()) {
case dods_byte_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_float32_c:
case dods_float64_c:
// For these cases, read() puts the data into d_buf,
// which is what we need.
break;
case dods_str_c:
case dods_url_c:
// For these cases, read() will put the data into d_str[],
// which is also what we need.
break;
case dods_array_c:
// This is an error since there can never be an Array of Array.
throw InternalErr(__FILE__, __LINE__, "Array of Array not supported.");
case dods_structure_c:
case dods_sequence_c:
case dods_grid_c:
DBG(cerr << "Vector::intern_data: found ctor" << endl);
// For these cases, we need to call read() for each of the 'num'
// elements in the 'd_compound_buf[]' array of BaseType object pointers.
//
// I changed the test here from '... = 0' to '... < num' to accommodate
// the case where the array is zero-length.
if (d_compound_buf.capacity() < (unsigned)num)
throw InternalErr(__FILE__, __LINE__, "The capacity of this Vector is less than the number of elements.");
for (int i = 0; i < num; ++i)
d_compound_buf[i]->intern_data(eval, dds);
break;
default:
throw InternalErr(__FILE__, __LINE__, "Unknown datatype.");
}
}
bool Vector::serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval) {
// Add protection against calling this with DAP4 types. Technically not needed,
// but the 'Unknown Datatype' message is not very useful. jhrg 7/28/22
if (is_dap4())
throw Error(string("A method usable only with DAP2 variables was called on a DAP4 variable (")
.append(name())
.append(")."),
__FILE__, __LINE__);
if (d_too_big_for_dap2)
throw Error("Trying to send a variable that is too large for DAP2.", __FILE__, __LINE__);
// Added to streamline zero-length arrays. Not needed for correct function,
// but explicitly handling this case here makes the code easier to follow.
// In libdap::Vector::val2buf() there is a test that will catch the zero-length
// case as well. We still need to call serialize since it will write size
// information that the client depends on. jhrg 2/17/16
if (length() == 0)
set_read_p(true);
else if (!read_p())
read(); // read() throws Error and InternalErr
if (ce_eval && !eval.eval_selection(dds, dataset()))
return true;
// length() is not capacity; it must be set explicitly in read().
int num = length();
bool status = false;
switch (d_proto->type()) {
case dods_byte_c:
m.put_vector(d_buf, num, *this);
status = true;
break;
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_float32_c:
case dods_float64_c:
assert((int)d_proto->width_ll() == d_proto->width_ll());
m.put_vector(d_buf, num, (int)d_proto->width_ll(), *this);
status = true;
break;
case dods_str_c:
case dods_url_c:
if (d_str.capacity() == 0)
throw InternalErr(__FILE__, __LINE__, "The capacity of the string vector is 0");
m.put_int(num);
for (int i = 0; i < num; ++i)
m.put_str(d_str[i]);
status = true;
break;
case dods_array_c:
case dods_structure_c:
case dods_sequence_c:
case dods_grid_c:
// Jose Garcia
// Not setting the capacity of d_compound_buf is an internal error.
if (d_compound_buf.capacity() == 0)
throw InternalErr(__FILE__, __LINE__, "The capacity of *this* vector is 0.");
m.put_int(num);
status = true;
for (int i = 0; i < num && status; ++i)
status = status && d_compound_buf[i]->serialize(eval, dds, m, false);
break;
default:
throw InternalErr(__FILE__, __LINE__, "Unknown datatype.");
}
#ifdef CLEAR_LOCAL_DATA
clear_local_data();
#endif
return status;
}
// Read an object from the network and internalize it. For a Vector this is
// handled differently for a `cardinal' type. Vectors of Cardinals are
// stored using the `C' representations because these objects often are used
// to build huge arrays (e.g., an array of 1024 by 1024 bytes). However,
// arrays of non-cardinal types are stored as Vectors of the C++ objects or
// DAP2 objects (Str and Url are vectors of the string class, Structure, ...,
// Grid are vectors of the libdap Structure, ... classes).
//
// The boolean parameter REUSE determines whether internal storage is reused
// or not. If true, the _buf member is assumed to be large enough to hold the
// incoming cardinal data and is *not* reallocated. If false, new storage is
// allocated. If the internal buffer has not yet been allocated, then this
// parameter has no effect (i.e., storage is allocated). This parameter
// effects storage for cardinal data only.
//
// Returns: True is successful, false otherwise.
bool Vector::deserialize(UnMarshaller &um, DDS *dds, bool reuse) {
unsigned int num;
unsigned i = 0;
if (is_dap4())
throw Error(string("A method usable only with DAP2 variables was called on a DAP4 variable (")
.append(name())
.append(")."),
__FILE__, __LINE__);
switch (d_proto->type()) {
case dods_byte_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_float32_c:
case dods_float64_c:
um.get_int((int &)num);
DBG(cerr << "Vector::deserialize: num = " << num << endl);
DBG(cerr << "Vector::deserialize: length = " << length() << endl);
if (length() == -1)
set_length(num);
if (num != (unsigned int)length())
throw InternalErr(__FILE__, __LINE__,
"The server sent declarations and data with mismatched sizes for the variable '" +
name() + "'.");
if (!d_buf || !reuse) {
// Make d_buf be large enough for length_ll() elements of _var->type()
// m_create...() deletes the old buffer.
m_create_cardinal_data_buffer_for_type(length_ll());
}
// Added to accommodate zero-length arrays.
// Note that the rest of the cases will just send the size without data
// but that these calls trigger error testing in the UnMarshaller code.
// jhrg 1/28/16
if (num == 0)
return true;
if (d_proto->type() == dods_byte_c)
um.get_vector((char **)&d_buf, num, *this);
else {
assert((int)d_proto->width_ll() == d_proto->width_ll());
um.get_vector((char **)&d_buf, num, d_proto->width_ll(), *this);
}
break;
case dods_str_c:
case dods_url_c:
um.get_int((int &)num);
if (length() == -1)
set_length(num);
if (num != (unsigned int)length())
throw InternalErr(__FILE__, __LINE__, "The client sent declarations and data with mismatched sizes.");
d_str.resize((num > 0) ? num : 0); // Fill with NULLs
#if 0
d_capacity = num; // capacity is number of strings we can fit.
#endif
set_value_capacity((uint64_t)num);
for (i = 0; i < num; ++i) {
string str;
um.get_str(str);
d_str[i] = str;
}
break;
case dods_array_c:
// Added jhrg 5/18/17
// This replaces a comment that was simply 'TO DO'
throw InternalErr(__FILE__, __LINE__, "Array of array!");
case dods_structure_c:
case dods_sequence_c:
case dods_grid_c:
um.get_int((int &)num);
if (length() == -1)
set_length(num);
if (num != (unsigned int)length())
throw InternalErr(__FILE__, __LINE__, "The client sent declarations and data with mismatched sizes.");
vec_resize(num);
for (i = 0; i < num; ++i) {
d_compound_buf[i] = d_proto->ptr_duplicate();
d_compound_buf[i]->deserialize(um, dds);
}
break;
default:
throw InternalErr(__FILE__, __LINE__, "Unknown type!");
}
return false;
}
void Vector::compute_checksum(Crc32 &checksum) {
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int8_c:
case dods_uint8_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_float32_c:
case dods_int64_c:
case dods_uint64_c:
case dods_float64_c:
case dods_enum_c:
checksum.AddData(reinterpret_cast<uint8_t *>(d_buf), length_ll() * d_proto->width_ll());
break;
case dods_str_c:
case dods_url_c:
for (int64_t i = 0, e = length(); i < e; ++i)
checksum.AddData(reinterpret_cast<const uint8_t *>(d_str[i].data()), d_str[i].size());
break;
case dods_opaque_c:
case dods_structure_c:
case dods_sequence_c:
d_proto->compute_checksum(checksum);
break;
case dods_array_c: // No array of array
case dods_grid_c: // No grids in DAP4
default:
throw InternalErr(__FILE__, __LINE__, "Unknown or unsupported datatype (" + d_proto->type_name() + ").");
}
}
void Vector::intern_data(/*Crc32 &checksum, DMR &dmr, ConstraintEvaluator &eval*/) {
if (!read_p())
read(); // read() throws Error and InternalErr
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int8_c:
case dods_uint8_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_int64_c:
case dods_uint64_c:
case dods_enum_c:
case dods_float32_c:
case dods_float64_c:
case dods_str_c:
case dods_url_c:
#if 0
compute_checksum(checksum);
#endif
break;
case dods_opaque_c:
case dods_structure_c:
case dods_sequence_c:
// Modified the assertion here from '... != 0' to '... >= length())
// to accommodate the case of a zero-length array. jhrg 1/28/16
assert(d_compound_buf.capacity() >= (unsigned)length());
for (int i = 0, e = length(); i < e; ++i)
d_compound_buf[i]->intern_data(/*checksum, dmr, eval*/);
break;
case dods_array_c: // No Array of Array in DAP4 either...
case dods_grid_c:
default:
throw InternalErr(__FILE__, __LINE__, "Unknown or unsupported datatype (" + d_proto->type_name() + ").");
}
}
void Vector::serialize(D4StreamMarshaller &m, DMR &dmr, bool filter /*= false*/) {
if (!read_p())
read(); // read() throws Error and InternalErr
#if 0
if (filter && !eval.eval_selection(dmr, dataset()))
return true;
#endif
int64_t num = length_ll(); // The constrained length in elements
DBG(cerr << __func__ << ", num: " << num << endl);
// Added in case we're trying to serialize a zero-length array. jhrg 1/27/16
if (num == 0)
return;
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int8_c:
case dods_uint8_c:
m.put_vector(d_buf, num);
break;
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_int64_c:
case dods_uint64_c:
m.put_vector(d_buf, num, (int)d_proto->width_ll());
break;
case dods_enum_c:
if (d_proto->width_ll() == 1)
m.put_vector(d_buf, num);
else
m.put_vector(d_buf, num, (int)d_proto->width_ll());
break;
case dods_float32_c:
m.put_vector_float32(d_buf, num);
break;
case dods_float64_c:
m.put_vector_float64(d_buf, num);
break;
case dods_str_c:
case dods_url_c:
assert((int64_t)d_str.capacity() >= num);
for (int64_t i = 0; i < num; ++i)
m.put_str(d_str[i]);
break;
case dods_array_c:
throw InternalErr(__FILE__, __LINE__, "Array of Array not allowed.");
case dods_opaque_c:
case dods_structure_c:
case dods_sequence_c:
assert(d_compound_buf.capacity() >= 0);
for (int64_t i = 0; i < num; ++i) {
DBG(cerr << __func__ << "d_compound_buf[" << i << "] " << d_compound_buf[i] << endl);
d_compound_buf[i]->serialize(m, dmr, filter);
}
break;
case dods_grid_c:
throw InternalErr(__FILE__, __LINE__, "Grid is not part of DAP4.");
default:
throw InternalErr(__FILE__, __LINE__, "Unknown datatype.");
}
#ifdef CLEAR_LOCAL_DATA
clear_local_data();
#endif
}
void Vector::deserialize(D4StreamUnMarshaller &um, DMR &dmr) {
if (m_is_cardinal_type()) {
if (d_buf)
m_delete_cardinal_data_buffer();
if (!d_buf)
m_create_cardinal_data_buffer_for_type(length());
}
DBG(cerr << __FUNCTION__ << name() << ", length(): " << length() << endl);
// Added in case we're trying to deserialize a zero-length array. jhrg 1/27/16
if (length() == 0)
return;
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int8_c:
case dods_uint8_c:
um.get_vector((char *)d_buf, length_ll());
break;
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_int64_c:
case dods_uint64_c:
um.get_vector((char *)d_buf, length_ll(), d_proto->width_ll());
break;
case dods_enum_c:
if (d_proto->width_ll() == 1)
um.get_vector((char *)d_buf, length_ll());
else
um.get_vector((char *)d_buf, length_ll(), d_proto->width_ll());
break;
case dods_float32_c:
um.get_vector_float32((char *)d_buf, length_ll());
break;
case dods_float64_c:
um.get_vector_float64((char *)d_buf, length_ll());
break;
case dods_str_c:
case dods_url_c: {
int64_t len = length_ll();
d_str.resize((len > 0) ? len : 0); // Fill with NULLs
if (len < 0)
throw InternalErr(__FILE__, __LINE__, "The number of string length is less than 0 ");
#if 0
d_capacity = len; // capacity is number of strings we can fit.
#endif
set_value_capacity(len);
for (int64_t i = 0; i < len; ++i) {
um.get_str(d_str[i]);
}
break;
}
case dods_array_c:
throw InternalErr(__FILE__, __LINE__, "Array of Array not allowed.");
case dods_opaque_c:
case dods_structure_c:
case dods_sequence_c: {
vec_resize(length());
for (int64_t i = 0, end = length(); i < end; ++i) {
d_compound_buf[i] = d_proto->ptr_duplicate();
d_compound_buf[i]->deserialize(um, dmr);
}
break;
}
case dods_grid_c:
throw InternalErr(__FILE__, __LINE__, "Grid is not part of DAP4.");
default:
throw InternalErr(__FILE__, __LINE__, "Unknown type.");
}
}
#if 0
unsigned int Vector::val2buf(void *val, bool reuse)
{
// Jose Garcia
// Added for zero-length arrays - support in the handlers. jhrg 1/29/16
if (!val && length() == 0)
return 0;
// I *think* this method has been mainly designed to be use by read which
// is implemented in the surrogate library. Passing NULL as a pointer to
// this method will be an error of the creator of the surrogate library.
// Even though I recognize the fact that some methods inside libdap++ can
// call val2buf, I think by now no coding bugs such as misusing val2buf
// will be in libdap++, so it will be an internal error from the
// surrogate library.
if (!val)
throw InternalErr(__FILE__, __LINE__, "The incoming pointer does not contain any data.");
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int8_c:
case dods_uint8_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_int64_c:
case dods_uint64_c:
case dods_enum_c:
case dods_float32_c:
case dods_float64_c:
#if 0
if (d_buf && !reuse)
m_delete_cardinal_data_buffer();
#endif
// First time or no reuse (free'd above)
if (!d_buf || !reuse)
m_create_cardinal_data_buffer_for_type(length_ll());
// width_ll(true) returns the size in bytes given the constraint
if (d_buf)
memcpy(d_buf, val, (uint64_t)width_ll(true));
break;
case dods_str_c:
case dods_url_c:
{
// Assume val points to an array of C++ string objects. Copy
// them into the vector<string> field of this object.
// Note: d_length is the number of elements in the Vector
#if 0
d_str.resize(d_length);
d_capacity = d_length;
for (int i = 0; i < d_length; ++i)
d_str[i] = *(static_cast<string *> (val) + i);
#endif
int64_t str_len = length_ll();
if (str_len <0)
throw InternalErr(__FILE__,__LINE__,"The number of string length is less than 0 ");
d_str.resize(str_len);
set_value_capacity(str_len);
for (int64_t i = 0; i < str_len; ++i)
d_str[i] = *(static_cast<string *> (val) + i);
}
break;
default:
throw InternalErr(__FILE__, __LINE__, "Vector::val2buf: bad type");
}
return (unsigned int)width_ll(true);
}
#endif
unsigned int Vector::val2buf(void *val, bool reuse) {
auto ret_value = (unsigned int)val2buf_ll(val, reuse);
return ret_value;
}
int64_t Vector::val2buf_ll(void *val, bool reuse) {
// Jose Garcia
// Added for zero-length arrays - support in the handlers. jhrg 1/29/16
if (!val && length() == 0)
return 0;
// I *think* this method has been mainly designed to be use by read which
// is implemented in the surrogate library. Passing NULL as a pointer to
// this method will be an error of the creator of the surrogate library.
// Even though I recognize the fact that some methods inside libdap++ can
// call val2buf, I think by now no coding bugs such as misusing val2buf
// will be in libdap++, so it will be an internal error from the
// surrogate library.
if (!val)
throw InternalErr(__FILE__, __LINE__, "The incoming pointer does not contain any data.");
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int8_c:
case dods_uint8_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_int64_c:
case dods_uint64_c:
case dods_enum_c:
case dods_float32_c:
case dods_float64_c:
#if 0
if (d_buf && !reuse)
m_delete_cardinal_data_buffer();
#endif
// First time or no reuse (free'd above)
if (!d_buf || !reuse)
m_create_cardinal_data_buffer_for_type(length_ll());
// width_ll(true) returns the size in bytes given the constraint
if (d_buf)
memcpy(d_buf, val, (uint64_t)width_ll(true));
break;
case dods_str_c:
case dods_url_c: {
// Assume val points to an array of C++ string objects. Copy
// them into the vector<string> field of this object.
// Note: d_length is the number of elements in the Vector
#if 0
d_str.resize(d_length);
d_capacity = d_length;
for (int i = 0; i < d_length; ++i)
d_str[i] = *(static_cast<string *> (val) + i);
#endif
int64_t str_len = length_ll();
if (str_len < 0)
throw InternalErr(__FILE__, __LINE__, "The number of string length is less than 0 ");
d_str.resize(str_len);
set_value_capacity(str_len);
for (int64_t i = 0; i < str_len; ++i)
d_str[i] = *(static_cast<string *>(val) + i);
}
break;
default:
throw InternalErr(__FILE__, __LINE__, "Vector::val2buf: bad type");
}
return width_ll(true);
}
unsigned int Vector::buf2val(void **val) {
// Jose Garcia
// The same comment in Vector::val2buf applies here!
if (!val)
throw InternalErr(__FILE__, __LINE__, "NULL pointer.");
int64_t wid = width_ll(true /* constrained */);
// This is the width computed using length(). The
// length() property is changed when a projection
// constraint is applied. Thus, this is the number of
// bytes in the buffer given the current constraint.
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int8_c:
case dods_uint8_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_int64_c:
case dods_uint64_c:
case dods_enum_c:
case dods_float32_c:
case dods_float64_c:
if (!d_buf)
throw InternalErr(__FILE__, __LINE__,
"Vector::buf2val: Logic error: called when cardinal type data buffer was empty!");
if (!*val)
*val = new char[wid];
memcpy(*val, d_buf, (uint64_t)wid);
return (unsigned int)wid;
case dods_str_c:
case dods_url_c: {
if (d_str.empty())
throw InternalErr(__FILE__, __LINE__,
"Vector::buf2val: Logic error: called when string data buffer was empty!");
if (!*val)
*val = new string[d_length];
for (int i = 0; i < d_length; ++i)
*(static_cast<string *>(*val) + i) = d_str[i];
return (unsigned int)width_ll();
}
default:
throw InternalErr(__FILE__, __LINE__, "Vector::buf2val: bad type");
}
}
int64_t Vector::buf2val_ll(void **val) {
// Jose Garcia
// The same comment in Vector::val2buf applies here!
if (!val)
throw InternalErr(__FILE__, __LINE__, "NULL pointer.");
int64_t wid = width_ll(true /* constrained */);
// This is the width computed using length(). The
// length() property is changed when a projection
// constraint is applied. Thus, this is the number of
// bytes in the buffer given the current constraint.
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int8_c:
case dods_uint8_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_int64_c:
case dods_uint64_c:
case dods_enum_c:
case dods_float32_c:
case dods_float64_c:
if (!d_buf)
throw InternalErr(__FILE__, __LINE__,
"Vector::buf2val: Logic error: called when cardinal type data buffer was empty!");
if (!*val)
*val = new char[wid];
memcpy(*val, d_buf, wid);
return wid;
case dods_str_c:
case dods_url_c: {
if (d_str.empty())
throw InternalErr(__FILE__, __LINE__,
"Vector::buf2val: Logic error: called when string data buffer was empty!");
if (!*val)
*val = new string[d_length_ll];
for (int64_t i = 0; i < d_length_ll; ++i)
*(static_cast<string *>(*val) + i) = d_str[i];
return width_ll();
}
default:
throw InternalErr(__FILE__, __LINE__, "Vector::buf2val: bad type");
}
}
void Vector::set_vec(unsigned int i, BaseType *val) { Vector::set_vec_nocopy(i, val->ptr_duplicate()); }
void Vector::set_vec_ll(uint64_t i, BaseType *val) { Vector::set_vec_nocopy_ll(i, val->ptr_duplicate()); }
void Vector::set_vec_nocopy(unsigned int i, BaseType *val) {
// Jose Garcia
// This is a public method which allows users to set the elements
// of *this* vector. Passing an invalid index, a NULL pointer or
// mismatching the vector type are internal errors.
if (i >= static_cast<unsigned int>(d_length))
throw InternalErr(__FILE__, __LINE__, "Invalid data: index too large.");
if (!val)
throw InternalErr(__FILE__, __LINE__, "Invalid data: null pointer to BaseType object.");
if (val->type() != d_proto->type())
throw InternalErr(__FILE__, __LINE__,
"invalid data: type of incoming object does not match *this* vector type.");
// This code originally used capacity() instead of size(), but that was an error.
// Use capacity() when using reserve() and size() when using resize(). Mixing
// capacity() with resize() leaves holes in the data, where (pointer) values are
// filled with nulls during successive calls to resize(). The resize() heuristic
// remembers previous calls on a given vector<> and allocates larger than requested
// blocks of memory on successive calls, which has the strange affect of erasing
// values already in the vector in the parts just added.
// jhrg 5/18/17
if (i >= d_compound_buf.size()) {
vec_resize(d_compound_buf.size() + 100);
}
d_compound_buf[i] = val;
}
void Vector::set_vec_nocopy_ll(uint64_t i, BaseType *val) {
// Jose Garcia
// This is a public method which allows users to set the elements
// of *this* vector. Passing an invalid index, a NULL pointer or
// mismatching the vector type are internal errors.
if (i >= static_cast<uint64_t>(length_ll()))
throw InternalErr(__FILE__, __LINE__, "Invalid data: index too large.");
if (!val)
throw InternalErr(__FILE__, __LINE__, "Invalid data: null pointer to BaseType object.");
if (val->type() != d_proto->type())
throw InternalErr(__FILE__, __LINE__,
"invalid data: type of incoming object does not match *this* vector type.");
// This code originally used capacity() instead of size(), but that was an error.
// Use capacity() when using reserve() and size() when using resize(). Mixing
// capacity() with resize() leaves holes in the data, where (pointer) values are
// filled with nulls during successive calls to resize(). The resize() heuristic
// remembers previous calls on a given vector<> and allocates larger than requested
// blocks of memory on successive calls, which has the strange affect of erasing
// values already in the vector in the parts just added.
// jhrg 5/18/17
if (i >= d_compound_buf.size()) {
vec_resize_ll(d_compound_buf.size() + 100);
}
d_compound_buf[i] = val;
}
void Vector::clear_local_data() {
if (d_buf) {
delete[] d_buf;
d_buf = 0;
}
for (unsigned int i = 0; i < d_compound_buf.size(); ++i) {
delete d_compound_buf[i];
d_compound_buf[i] = 0;
}
// Force memory to be reclaimed.
d_compound_buf.resize(0);
d_str.resize(0);
d_capacity = 0;
d_capacity_ll = 0;
set_read_p(false);
}
unsigned int Vector::get_value_capacity() const { return d_capacity; }
uint64_t Vector::get_value_capacity_ll() const { return d_capacity_ll; }
void Vector::reserve_value_capacity(unsigned int numElements) {
if (!d_proto) {
throw InternalErr(__FILE__, __LINE__, "reserve_value_capacity: Logic error: _var is null!");
}
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int8_c:
case dods_uint8_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_int64_c:
case dods_uint64_c:
case dods_enum_c:
case dods_float32_c:
case dods_float64_c:
// Make _buf be the right size and set _capacity
m_create_cardinal_data_buffer_for_type(numElements);
break;
case dods_str_c:
case dods_url_c:
// Make sure the d_str has enough room for all the strings.
// Technically not needed, but it will speed things up for large arrays.
d_str.reserve(numElements);
#if 0
d_capacity = numElements;
#endif
set_value_capacity(numElements);
break;
case dods_array_c:
throw InternalErr(__FILE__, __LINE__, "reserve_value_capacity: Arrays not supported!");
case dods_opaque_c:
case dods_structure_c:
case dods_sequence_c:
case dods_grid_c:
// not clear anyone will go this path, but best to be complete.
d_compound_buf.reserve(numElements);
#if 0
d_capacity = numElements;
#endif
set_value_capacity(numElements);
break;
default:
throw InternalErr(__FILE__, __LINE__, "reserve_value_capacity: Unknown type!");
} // switch
}
void Vector::reserve_value_capacity() {
// Use the current length of the vector as the reserve amount.
reserve_value_capacity(length());
}
void Vector::reserve_value_capacity_ll(uint64_t numElements) {
if (!d_proto) {
throw InternalErr(__FILE__, __LINE__, "reserve_value_capacity: Logic error: _var is null!");
}
switch (d_proto->type()) {
case dods_byte_c:
case dods_char_c:
case dods_int8_c:
case dods_uint8_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_int64_c:
case dods_uint64_c:
case dods_enum_c:
case dods_float32_c:
case dods_float64_c:
// Make _buf be the right size and set _capacity
m_create_cardinal_data_buffer_for_type(numElements);
break;
case dods_str_c:
case dods_url_c:
// Make sure the d_str has enough room for all the strings.
// Technically not needed, but it will speed things up for large arrays.
d_str.reserve(numElements);
#if 0
d_capacity = numElements;
#endif
set_value_capacity(numElements);
break;
case dods_array_c:
throw InternalErr(__FILE__, __LINE__, "reserve_value_capacity: Arrays not supported!");
case dods_opaque_c:
case dods_structure_c:
case dods_sequence_c:
case dods_grid_c:
// not clear anyone will go this path, but best to be complete.
d_compound_buf.reserve(numElements);
#if 0
d_capacity = numElements;
#endif
set_value_capacity(numElements);
break;
default:
throw InternalErr(__FILE__, __LINE__, "reserve_value_capacity: Unknown type!");
} // switch
}
void Vector::reserve_value_capacity_ll() {
// Use the current length of the vector as the reserve amount.
reserve_value_capacity_ll(length_ll());
}
void Vector::reserve_value_capacity_ll_byte(uint64_t numBytes) { d_buf = new char[numBytes]; }
uint64_t Vector::set_value_slice_from_row_major_vector(const Vector &rowMajorDataC, uint64_t startElement) {
static const string funcName = "set_value_slice_from_row_major_vector:";
// semantically const from the caller's viewpoint, but some calls are not syntactic const.
Vector &rowMajorData = const_cast<Vector &>(rowMajorDataC);
bool typesMatch = rowMajorData.var() && d_proto && (rowMajorData.var()->type() == d_proto->type());
if (!typesMatch) {
throw InternalErr(__FILE__, __LINE__, funcName + "Logic error: types do not match so cannot be copied!");
}
// Make sure the data exists
if (!rowMajorData.read_p()) {
throw InternalErr(__FILE__, __LINE__,
funcName +
"Logic error: the Vector to copy data from has !read_p() and should have been read in!");
}
// Check this otherwise the static_cast<unsigned int> below will do the wrong thing.
if (rowMajorData.length_ll() < 0) {
throw InternalErr(
__FILE__, __LINE__,
funcName +
"Logic error: the Vector to copy data from has length_ll() < 0 and was probably not initialized!");
}
// The read-in capacity had better be at least the length (the amount we will copy) or we'll memcpy into bad memory
// I imagine we could copy just the capacity rather than throw, but I really think this implies a problem to be
// addressed.
if (rowMajorData.get_value_capacity_ll() < static_cast<uint64_t>(rowMajorData.length_ll())) {
throw InternalErr(
__FILE__, __LINE__,
funcName + "Logic error: the Vector to copy from has a data capacity less than its length, can't copy!");
}
// Make sure there's enough room in this Vector to store all the elements requested. Again,
// better to throw than just copy what we can since it implies a logic error that needs to be solved.
if (d_capacity_ll < (startElement + rowMajorData.length_ll())) {
throw InternalErr(__FILE__, __LINE__,
funcName +
"Logic error: the capacity of this Vector cannot hold all the data in the from Vector!");
}
// OK, at this point we're pretty sure we can copy the data, but we have to do it differently depending on type.
switch (d_proto->type()) {
case dods_int8_c:
case dods_uint8_c:
case dods_byte_c:
case dods_char_c:
case dods_int16_c:
case dods_uint16_c:
case dods_int32_c:
case dods_uint32_c:
case dods_int64_c:
case dods_uint64_c:
case dods_enum_c:
case dods_float32_c:
case dods_float64_c: {
if (!d_buf) {
throw InternalErr(__FILE__, __LINE__, funcName + "Logic error: this->_buf was unexpectedly null!");
}
if (!rowMajorData.d_buf) {
throw InternalErr(__FILE__, __LINE__, funcName + "Logic error: rowMajorData._buf was unexpectedly null!");
}
// memcpy the data into this, taking care to do ptr arithmetic on bytes and not sizeof(element)
int64_t varWidth = d_proto->width_ll();
char *pFromBuf = rowMajorData.d_buf;
int64_t numBytesToCopy = rowMajorData.width_ll(true);
char *pIntoBuf = d_buf + (startElement * varWidth);
memcpy(pIntoBuf, pFromBuf, numBytesToCopy);
break;
}
case dods_str_c:
case dods_url_c:
// Strings need to be copied directly
for (uint64_t i = 0; i < static_cast<uint64_t>(rowMajorData.length_ll()); ++i) {
d_str[startElement + i] = rowMajorData.d_str[i];
}
break;
case dods_array_c:
case dods_opaque_c:
case dods_structure_c:
case dods_sequence_c:
case dods_grid_c:
// Not sure that this function will be used for these type of nested objects, so I will throw here.
throw InternalErr(__FILE__, __LINE__,
funcName +
"Unimplemented method for Vectors of type: array, opaque, structure, sequence or grid.");
default:
throw InternalErr(__FILE__, __LINE__, funcName + ": Unknown type!");
} // switch (_var->type())
// This is how many elements we copied.
return (uint64_t)rowMajorData.length_ll();
}
template <typename T> static bool types_match(Type t, T *cpp_var) {
switch (t) {
case dods_byte_c:
case dods_char_c:
case dods_uint8_c:
return typeid(cpp_var) == typeid(dods_byte *);
case dods_int8_c:
return typeid(cpp_var) == typeid(dods_int8 *);
case dods_int16_c:
return typeid(cpp_var) == typeid(dods_int16 *);
case dods_uint16_c:
return typeid(cpp_var) == typeid(dods_uint16 *);
case dods_int32_c:
return typeid(cpp_var) == typeid(dods_int32 *);
case dods_uint32_c:
return typeid(cpp_var) == typeid(dods_uint32 *);
case dods_int64_c:
return typeid(cpp_var) == typeid(dods_int64 *);
case dods_uint64_c:
return typeid(cpp_var) == typeid(dods_uint64 *);
case dods_float32_c:
return typeid(cpp_var) == typeid(dods_float32 *);
case dods_float64_c:
return typeid(cpp_var) == typeid(dods_float64 *);
case dods_null_c:
case dods_enum_c:
case dods_str_c:
case dods_url_c:
case dods_opaque_c:
case dods_array_c:
case dods_structure_c:
case dods_sequence_c:
case dods_group_c:
default:
return false;
}
}
template <typename T> bool Vector::set_value_worker(T *v, int sz) {
if (!v || !types_match(
d_proto->type() == dods_enum_c ? static_cast<D4Enum *>(d_proto)->element_type() : d_proto->type(), v))
return false;
m_set_cardinal_values_internal(v, (int64_t)sz);
return true;
}
template <typename T> bool Vector::set_value_ll_worker(T *v, int64_t sz) {
if (!v || !types_match(
d_proto->type() == dods_enum_c ? static_cast<D4Enum *>(d_proto)->element_type() : d_proto->type(), v))
return false;
m_set_cardinal_values_internal(v, sz);
return true;
}
bool Vector::set_value(dods_byte *val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(dods_int8 *val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(dods_int16 *val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(dods_uint16 *val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(dods_int32 *val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(dods_uint32 *val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(dods_int64 *val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(dods_uint64 *val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(dods_float32 *val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(dods_float64 *val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value_ll(dods_byte *val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(dods_int8 *val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(dods_int16 *val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(dods_uint16 *val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(dods_int32 *val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(dods_uint32 *val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(dods_int64 *val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(dods_uint64 *val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(dods_float32 *val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(dods_float64 *val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value(string *val, int sz) {
if ((var()->type() == dods_str_c || var()->type() == dods_url_c) && val) {
d_str.resize(sz);
#if 0
d_capacity = sz;
#endif
set_value_capacity(sz);
for (int t = 0; t < sz; t++) {
d_str[t] = val[t];
}
set_length(sz);
set_read_p(true);
return true;
} else {
return false;
}
}
bool Vector::set_value_ll(string *val, int64_t sz) {
if ((var()->type() == dods_str_c || var()->type() == dods_url_c) && val) {
d_str.resize(sz);
#if 0
d_capacity_ll = sz;
#endif
set_value_capacity(sz);
for (int64_t t = 0; t < sz; t++) {
d_str[t] = val[t];
}
set_length_ll(sz);
set_read_p(true);
return true;
} else {
return false;
}
}
template <typename T> bool Vector::set_value_worker(vector<T> &v, int sz) { return set_value(v.data(), sz); }
template <typename T> bool Vector::set_value_ll_worker(vector<T> &v, int64_t sz) { return set_value_ll(v.data(), sz); }
bool Vector::set_value(vector<dods_byte> &val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(vector<dods_int8> &val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(vector<dods_int16> &val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(vector<dods_uint16> &val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(vector<dods_int32> &val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(vector<dods_uint32> &val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(vector<dods_int64> &val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(vector<dods_uint64> &val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(vector<dods_float32> &val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value(vector<dods_float64> &val, int sz) { return set_value_worker(val, sz); }
bool Vector::set_value_ll(vector<dods_byte> &val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(vector<dods_int8> &val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(vector<dods_int16> &val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(vector<dods_uint16> &val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(vector<dods_int32> &val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(vector<dods_uint32> &val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(vector<dods_int64> &val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(vector<dods_uint64> &val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(vector<dods_float32> &val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value_ll(vector<dods_float64> &val, int64_t sz) { return set_value_ll_worker(val, sz); }
bool Vector::set_value(vector<string> &val, int sz) {
if (var()->type() == dods_str_c || var()->type() == dods_url_c) {
d_str.resize(sz);
d_capacity = sz;
for (int t = 0; t < sz; t++) {
d_str[t] = val[t];
}
set_length(sz);
set_read_p(true);
return true;
} else {
return false;
}
}
bool Vector::set_value_ll(vector<string> &val, int64_t sz) {
if (var()->type() == dods_str_c || var()->type() == dods_url_c) {
d_str.resize(sz);
d_capacity_ll = sz;
for (int64_t t = 0; t < sz; t++) {
d_str[t] = val[t];
}
set_length_ll(sz);
set_read_p(true);
return true;
} else {
return false;
}
}
template <typename T> void Vector::value_worker(vector<unsigned int> *indices, T *b) const {
#if 0
// Iterator version. Not tested, jhrg 8/14/13
for (vector<unsigned int>::iterator i = indices->begin(), e = indices->end(); i != e; ++i) {
unsigned long currentIndex = *i;
if(currentIndex > (unsigned int)length()){
stringstream s;
s << "Vector::value() - Subset index[" << i - subsetIndex->begin() << "] = " << currentIndex << " references a value that is " <<
"outside the bounds of the internal storage [ length()= " << length() << " ] name: '" << name() << "'. ";
throw Error(s.str());
}
b[i - indices->begin()] = reinterpret_cast<T*>(d_buf )[currentIndex];
}
#endif
for (unsigned long i = 0, e = indices->size(); i < e; ++i) {
unsigned long currentIndex = (*indices)[i];
if (currentIndex > (unsigned int)length()) {
stringstream s;
s << "Vector::value() - Subset index[" << i << "] = " << currentIndex << " references a value that is "
<< "outside the bounds of the internal storage [ length()= " << length() << " ] name: '" << name()
<< "'. ";
throw Error(s.str());
}
b[i] = reinterpret_cast<T *>(d_buf)[currentIndex]; // I like this version - and it works!
}
}
template <typename T> void Vector::value_ll_worker(vector<uint64_t> *indices, T *b) const {
#if 0
// Iterator version. Not tested, jhrg 8/14/13
for (vector<unsigned int>::iterator i = indices->begin(), e = indices->end(); i != e; ++i) {
unsigned long currentIndex = *i;
if(currentIndex > (unsigned int)length()){
stringstream s;
s << "Vector::value() - Subset index[" << i - subsetIndex->begin() << "] = " << currentIndex << " references a value that is " <<
"outside the bounds of the internal storage [ length()= " << length() << " ] name: '" << name() << "'. ";
throw Error(s.str());
}
b[i - indices->begin()] = reinterpret_cast<T*>(d_buf )[currentIndex];
}
#endif
for (uint64_t i = 0, e = indices->size(); i < e; ++i) {
uint64_t currentIndex = (*indices)[i];
if (currentIndex > (uint64_t)length_ll()) {
stringstream s;
s << "Vector::value() - Subset index[" << i << "] = " << currentIndex << " references a value that is "
<< "outside the bounds of the internal storage [ length_ll()= " << length_ll() << " ] name: '" << name()
<< "'. ";
throw Error(s.str());
}
b[i] = reinterpret_cast<T *>(d_buf)[currentIndex]; // I like this version - and it works!
}
}
void Vector::value(vector<unsigned int> *indices, dods_byte *b) const { value_worker(indices, b); }
void Vector::value(vector<unsigned int> *indices, dods_int8 *b) const { value_worker(indices, b); }
void Vector::value(vector<unsigned int> *indices, dods_int16 *b) const { value_worker(indices, b); }
void Vector::value(vector<unsigned int> *indices, dods_uint16 *b) const { value_worker(indices, b); }
void Vector::value(vector<unsigned int> *indices, dods_int32 *b) const { value_worker(indices, b); }
void Vector::value(vector<unsigned int> *indices, dods_uint32 *b) const { value_worker(indices, b); }
void Vector::value(vector<unsigned int> *indices, dods_int64 *b) const { value_worker(indices, b); }
void Vector::value(vector<unsigned int> *indices, dods_uint64 *b) const { value_worker(indices, b); }
void Vector::value(vector<unsigned int> *indices, dods_float32 *b) const { value_worker(indices, b); }
void Vector::value(vector<unsigned int> *indices, dods_float64 *b) const { value_worker(indices, b); }
void Vector::value_ll(vector<uint64_t> *indices, dods_byte *b) const { value_ll_worker(indices, b); }
void Vector::value_ll(vector<uint64_t> *indices, dods_int8 *b) const { value_ll_worker(indices, b); }
void Vector::value_ll(vector<uint64_t> *indices, dods_int16 *b) const { value_ll_worker(indices, b); }
void Vector::value_ll(vector<uint64_t> *indices, dods_uint16 *b) const { value_ll_worker(indices, b); }
void Vector::value_ll(vector<uint64_t> *indices, dods_int32 *b) const { value_ll_worker(indices, b); }
void Vector::value_ll(vector<uint64_t> *indices, dods_uint32 *b) const { value_ll_worker(indices, b); }
void Vector::value_ll(vector<uint64_t> *indices, dods_int64 *b) const { value_ll_worker(indices, b); }
void Vector::value_ll(vector<uint64_t> *indices, dods_uint64 *b) const { value_ll_worker(indices, b); }
void Vector::value_ll(vector<uint64_t> *indices, dods_float32 *b) const { value_ll_worker(indices, b); }
void Vector::value_ll(vector<uint64_t> *indices, dods_float64 *b) const { value_ll_worker(indices, b); }
#if 0
template void Vector::value(vector<unsigned int> *indices, dods_byte *b) const;
template void Vector::value(vector<unsigned int> *indices, dods_int8 *b) const;
template void Vector::value(vector<unsigned int> *indices, dods_int16 *b) const;
template void Vector::value(vector<unsigned int> *indices, dods_uint16 *b) const;
template void Vector::value(vector<unsigned int> *indices, dods_int32 *b) const;
template void Vector::value(vector<unsigned int> *indices, dods_uint32 *b) const;
template void Vector::value(vector<unsigned int> *indices, dods_int64 *b) const;
template void Vector::value(vector<unsigned int> *indices, dods_uint64 *b) const;
template void Vector::value(vector<unsigned int> *indices, dods_float32 *b) const;
template void Vector::value(vector<unsigned int> *indices, dods_float64 *b) const;
#endif
void Vector::value(vector<unsigned int> *subsetIndex, vector<string> &b) const {
unsigned long currentIndex;
if (d_proto->type() == dods_str_c || d_proto->type() == dods_url_c) {
for (unsigned long i = 0; i < subsetIndex->size(); ++i) {
currentIndex = (*subsetIndex)[i];
if (currentIndex > (unsigned int)length()) {
stringstream s;
s << "Vector::value() - Subset index[" << i << "] = " << currentIndex << " references a value that is "
<< "outside the bounds of the internal storage [ length()= " << length() << " ] name: '" << name()
<< "'. ";
throw Error(s.str());
}
b[i] = d_str[currentIndex];
}
}
}
void Vector::value_ll(vector<uint64_t> *subsetIndex, vector<string> &b) const {
uint64_t currentIndex;
if (d_proto->type() == dods_str_c || d_proto->type() == dods_url_c) {
for (uint64_t i = 0; i < subsetIndex->size(); ++i) {
currentIndex = (*subsetIndex)[i];
if (currentIndex > (uint64_t)length_ll()) {
stringstream s;
s << "Vector::value() - Subset index[" << i << "] = " << currentIndex << " references a value that is "
<< "outside the bounds of the internal storage [ length_ll()= " << length_ll() << " ] name: '"
<< name() << "'. ";
throw Error(s.str());
}
b[i] = d_str[currentIndex];
}
}
}
template <typename T> void Vector::value_worker(T *v) const {
// Only copy if v is not null and the proto's type matches.
// For Enums, use the element type since type == dods_enum_c.
if (v && types_match(
d_proto->type() == dods_enum_c ? static_cast<D4Enum *>(d_proto)->element_type() : d_proto->type(), v))
memcpy(v, d_buf, length_ll() * sizeof(T));
}
void Vector::value(dods_byte *b) const { value_worker(b); }
void Vector::value(dods_int8 *b) const { value_worker(b); }
void Vector::value(dods_int16 *b) const { value_worker(b); }
void Vector::value(dods_uint16 *b) const { value_worker(b); }
void Vector::value(dods_int32 *b) const { value_worker(b); }
void Vector::value(dods_uint32 *b) const { value_worker(b); }
void Vector::value(dods_int64 *b) const { value_worker(b); }
void Vector::value(dods_uint64 *b) const { value_worker(b); }
void Vector::value(dods_float32 *b) const { value_worker(b); }
void Vector::value(dods_float64 *b) const { value_worker(b); }
#if 0
template void Vector::value(dods_byte *v) const;
template void Vector::value(dods_int8 *v) const;
template void Vector::value(dods_int16 *v) const;
template void Vector::value(dods_uint16 *v) const;
template void Vector::value(dods_int32 *v) const;
template void Vector::value(dods_uint32 *v) const;
template void Vector::value(dods_int64 *v) const;
template void Vector::value(dods_uint64 *v) const;
template void Vector::value(dods_float32 *v) const;
template void Vector::value(dods_float64 *v) const;
#endif
void Vector::value(vector<string> &b) const {
if (d_proto->type() == dods_str_c || d_proto->type() == dods_url_c)
b = d_str;
}
void *Vector::value() {
void *buffer = new char[width_ll(true)];
memcpy(buffer, d_buf, width_ll(true));
return buffer;
}
void Vector::add_var(BaseType *v, Part /*p*/) {
#if 1
if (v)
Vector::add_var_nocopy(v->ptr_duplicate());
else {
delete d_proto;
d_proto = nullptr;
}
#else
// Delete the current template variable
if (d_proto) {
delete d_proto;
d_proto = 0;
}
// if 'v' is null, just set _var to null and exit.
if (!v) {
d_proto = 0;
} else {
// Jose Garcia
// By getting a copy of this object to be assigned to _var
// we let the owner of 'v' to deallocate it as necessary.
d_proto = v->ptr_duplicate();
// If 'v' has a name, use it as the name of the array. If v doesn't have
// a name, then make sure to copy the array's name to it
// so that software which uses the template's name will still work.
if (!v->name().empty())
set_name(v->name());
else
d_proto->set_name(name());
d_proto->set_parent(this); // Vector --> child
DBG(cerr << "Vector::add_var: Added variable " << v << " (" << v->name() << " " << v->type_name() << ")"
<< endl);
}
#endif
}
void Vector::add_var_nocopy(BaseType *v, Part) {
// Delete the current template variable, if it exists
delete d_proto;
d_proto = nullptr;
// if 'v' is null, just set _var to null and exit.
if (v) {
d_proto = v;
// If 'v' has a name, use it as the name of the array. If it *is*
// empty, then make sure to copy the array's name to the template
// so that software which uses the template's name will still work.
if (!v->name().empty())
set_name(v->name());
else
d_proto->set_name(name());
d_proto->set_parent(this); // Vector is the parent; proto is the child
DBG(cerr << "Vector::add_var_no_copy: Added variable " << v << " (" << v->name() << " " << v->type_name() << ")"
<< endl);
}
}
bool Vector::check_semantics(string &msg, bool) { return BaseType::check_semantics(msg); }
bool Vector::is_dap4_projected(std::vector<std::string> &inventory) {
bool has_projected_dap4 = false;
if (send_p()) {
if (d_proto->is_constructor_type()) {
has_projected_dap4 =
d_proto->is_dap4_projected(inventory) || attributes()->has_dap4_types(FQN(), inventory);
} else {
has_projected_dap4 = prototype()->is_dap4();
if (has_projected_dap4) {
inventory.emplace_back(prototype()->type_name() + " " + FQN());
}
has_projected_dap4 |= attributes()->has_dap4_types(FQN(), inventory);
}
if (has_projected_dap4) {
inventory.emplace_back(type_name() + " " + FQN());
}
}
return has_projected_dap4;
}
void Vector::dump(ostream &strm) const {
strm << DapIndent::LMarg << "Vector::dump - (" << (void *)this << ")" << endl;
DapIndent::Indent();
BaseType::dump(strm);
strm << DapIndent::LMarg << "# elements in vector: " << d_length << endl;
if (d_proto) {
strm << DapIndent::LMarg << "base type:" << endl;
DapIndent::Indent();
d_proto->dump(strm);
DapIndent::UnIndent();
} else {
strm << DapIndent::LMarg << "base type: not set" << endl;
}
strm << DapIndent::LMarg << "vector contents:" << endl;
DapIndent::Indent();
for (unsigned i = 0; i < d_compound_buf.size(); ++i) {
if (d_compound_buf[i])
d_compound_buf[i]->dump(strm);
else
strm << DapIndent::LMarg << "vec[" << i << "] is null" << endl;
}
DapIndent::UnIndent();
strm << DapIndent::LMarg << "strings:" << endl;
DapIndent::Indent();
for (unsigned i = 0; i < d_str.size(); i++) {
strm << DapIndent::LMarg << d_str[i] << endl;
}
DapIndent::UnIndent();
if (d_buf) {
switch (d_proto != 0 ? d_proto->type() : 0) {
case dods_byte_c:
case dods_char_c:
strm << DapIndent::LMarg << "_buf: ";
strm.write(d_buf, d_length);
strm << endl;
break;
case 0:
default:
strm << DapIndent::LMarg << "_buf: " << (void *)d_buf << endl;
break;
}
} else {
strm << DapIndent::LMarg << "_buf: EMPTY" << endl;
}
DapIndent::UnIndent();
}
} // namespace libdap
BaseType
Crc32
Definition crc.h:45
Crc32::AddData
void AddData(const uint8_t *pData, const uint32_t length)
Definition crc.h:66
Vector
libdap::D4Attributes::has_dap4_types
bool has_dap4_types(const std::string &path, std::vector< std::string > &inventory) const
Definition D4Attributes.cc:656
libdap::InternalErr
A class for software fault reporting.
Definition InternalErr.h:61
libdap
top level DAP object to house generic methods
Definition AlarmHandler.h:35
libdap::set_length
virtual void set_length(int64_t)
Set the number of elements for this variable. use -1 to indicate nothing set.
Definition BaseType.h:224
libdap::Type
Type
Identifies the data type.
Definition Type.h:94
libdap::length_ll
virtual int64_t length_ll() const
Get the number of elements in this variable This version of the function deprecates length() which is...
Definition BaseType.h:216
libdap::reserve_value_capacity_ll
virtual void reserve_value_capacity_ll(uint64_t numElements)
Definition Vector.cc:1748
libdap::read_p
virtual bool read_p()
Has this variable been read?
Definition BaseType.cc:410
libdap::type_name
virtual string type_name() const
Returns the type of the class instance as a string.
Definition BaseType.cc:335
libdap::var
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=nullptr)
Returns a pointer to a member of a constructor class.
libdap::www2id
string www2id(const string &in, const string &escape, const string &except)
Definition escaping.cc:202
libdap::serialize
virtual bool serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval=true)
Move data to the net, then remove them from the object.
Definition D4Sequence.h:203
libdap::length
virtual int length() const
How many elements are in this variable? Uses -1 in places.
Definition BaseType.h:207
libdap::intern_data
virtual void intern_data(ConstraintEvaluator &eval, DDS &dds)
Definition D4Sequence.h:200
libdap::width_ll
virtual int64_t width_ll(bool constrained=false) const
Return the number of bytes needed to hold the array data.
Definition Vector.h:203
libdap::reserve_value_capacity
virtual void reserve_value_capacity(unsigned int numElements)
Definition Vector.cc:1675
libdap::send_p
virtual bool send_p()
Should this variable be sent?
Definition BaseType.cc:478
libdap::set_value
virtual void set_value(D4SeqValues &values)
Set the internal value. The 'values' of a D4Sequence is a vector of vectors of BaseType* objects....
Definition D4Sequence.h:268
libdap::set_length_ll
virtual void set_length_ll(int64_t)
Set the number of elements in this variable This version of the function deprecates set_length() whic...
Definition BaseType.h:232
libdap::vec_resize
void vec_resize(int l)
Definition Vector.cc:613
libdap::compute_checksum
virtual void compute_checksum(Crc32 &checksum)=0
include the data for this variable in the checksum DAP4 includes a checksum with every data response....
libdap::dataset
virtual string dataset() const
Returns the name of the dataset used to create this instance.
Definition BaseType.cc:326
libdap::clear_local_data
virtual void clear_local_data()
The basic data type for the DODS DAP types. */.
Definition BaseType.h:179
libdap::val2buf
virtual unsigned int val2buf(void *val, bool reuse=false)=0
Loads class data.