34#include <libdap/BaseType.h>
35#include <libdap/UInt32.h>
36#include <libdap/Array.h>
37#include <libdap/Sequence.h>
38#include <libdap/D4Sequence.h>
39#include <libdap/D4RValue.h>
40#include <libdap/Error.h>
41#include <libdap/debug.h>
42#include <libdap/util.h>
43#include <libdap/ServerFunctionsList.h>
45#include "TabularSequence.h"
46#include "TabularFunction.h"
59static void read_array_values(Array *a)
74TabularFunction::Shape TabularFunction::array_shape(Array *a)
78 for (Array::Dim_iter i = a->dim_begin(), e = a->dim_end(); i != e; ++i) {
79 shape.push_back(a->dimension_size(i));
93bool TabularFunction::shape_matches(Array *a,
const Shape &shape)
96 if (shape.size() != a->dimensions())
return false;
99 Array::Dim_iter i = a->dim_begin(), e = a->dim_end();
100 Shape::const_iterator si = shape.begin(), se = shape.end();
101 while (i != e && si != se) {
102 assert(a->dimension_size(i) >= 0);
103 if (*si != (
unsigned long) a->dimension_size(i))
return false;
124bool TabularFunction::dep_indep_match(
const Shape &dep_shape,
const Shape &indep_shape)
128 Shape::const_reverse_iterator di = dep_shape.rbegin();
129 for (Shape::const_reverse_iterator i = indep_shape.rbegin(), e = indep_shape.rend(); i != e; ++i) {
130 if (di == dep_shape.rend())
return false;
131 if (*i != *di++)
return false;
144unsigned long TabularFunction::number_of_values(
const Shape &shape)
146 unsigned long size = 1;
147 Shape::const_iterator si = shape.begin(), se = shape.end();
174void TabularFunction::build_columns(
unsigned long n, BaseType* btp, vector<Array*>& the_arrays,
177 if (btp->type() != dods_array_c)
178 throw Error(
"In tabular(): Expected argument '" + btp->name() +
"' to be an Array.");
181 Array *a =
static_cast<Array*
>(btp);
185 shape = array_shape(a);
186 else if (!shape_matches(a, shape))
187 throw Error(
"In tabular: Array '" + a->name() +
"' does not match the shape of the initial Array.");
189 read_array_values(a);
191 the_arrays.at(n) = a;
202void TabularFunction::read_values(
const vector<Array*> &arrays)
205 for_each(arrays.begin(), arrays.end(), read_array_values);
224void TabularFunction::build_sequence_values(
const vector<Array*> &the_arrays, SequenceValues &sv)
231 for (SequenceValues::size_type i = 0; i < sv.size(); ++i) {
233 BaseTypeRow *row =
new BaseTypeRow(the_arrays.size());
235 for (BaseTypeRow::size_type j = 0; j < the_arrays.size(); ++j) {
236 DBG(cerr <<
"the_arrays.at(" << j <<
") " << the_arrays.at(j) << endl);
238 (*row)[j]= the_arrays[j]->var(i)->ptr_duplicate();
240 (*row)[j]->set_send_p(
true);
241 (*row)[j]->set_read_p(
true);
267void TabularFunction::combine_sequence_values(SequenceValues &dep,
const SequenceValues &indep)
269 SequenceValues::const_iterator ii = indep.begin(), ie = indep.end();
270 for (SequenceValues::iterator i = dep.begin(), e = dep.end(); i != e; ++i) {
273 if (ii == ie) ii = indep.begin();
278 for (BaseTypeRow::iterator btr_i = (*ii)->begin(), btr_e = (*ii)->end(); btr_i != btr_e; ++btr_i) {
279 (*i)->push_back((*btr_i)->ptr_duplicate());
312void TabularFunction::add_index_column(
const Shape &indep_shape,
const Shape &dep_shape,
313 vector<Array*> &dep_vars)
315 assert(dep_vars.size() > 0);
316 assert(dep_shape.size() == indep_shape.size() + 1);
319 unsigned long num_indep_values = number_of_values(indep_shape);
320 unsigned long num_dep_values = number_of_values(dep_shape);
321 vector<dods_uint32> index_vals(num_dep_values);
323 assert(num_dep_values == num_indep_values * dep_shape.at(0));
326 vector<dods_uint32>::iterator iv = index_vals.begin();
327 for (Shape::size_type i = 0; i < dep_shape.at(0); ++i) {
328 assert(iv != index_vals.end());
329 fill(iv, iv + num_indep_values, i);
330 iv += num_indep_values;
334 string new_column_name = dep_vars.at(0)->dimension_name(dep_vars.at(0)->dim_begin());
335 if (new_column_name.empty())
336 new_column_name =
"index";
339 Array *a =
new Array(new_column_name,
new UInt32(new_column_name));
340 a->append_dim(num_dep_values, new_column_name);
341 a->set_value(index_vals, (
int)index_vals.size());
344 dep_vars.insert(dep_vars.begin(), a);
373void TabularFunction::function_dap2_tabular(
int argc, BaseType *argv[], DDS &, BaseType **btpp)
375 vector<Array*> the_arrays;
377 for (
int n = 0; n < argc; ++n) {
378 if (argv[n]->type() != dods_array_c)
379 throw Error(
"In function tabular(): Expected an array, but argument " + argv[n]->name()
380 +
" is a " + argv[n]->type_name() +
".");
381 the_arrays.push_back(
static_cast<Array*
>(argv[n]));
384 if (the_arrays.size() < 1)
385 throw Error(
"In function tabular(): Expected at least one Array variable.");
388 unsigned long min_dim_size = ULONG_MAX;
389 for (vector<Array*>::iterator i = the_arrays.begin(), e = the_arrays.end(); i != e; ++i) {
390 min_dim_size = min((
unsigned long) (*i)->dimensions(), min_dim_size);
394 vector<Array*> indep_vars, dep_vars;
395 for (vector<Array*>::iterator i = the_arrays.begin(), e = the_arrays.end(); i != e; ++i) {
396 if ((*i)->dimensions() == min_dim_size) {
397 indep_vars.push_back(*i);
400 dep_vars.push_back(*i);
404 Shape indep_shape = array_shape(indep_vars.at(0));
406 for (vector<Array*>::iterator i = indep_vars.begin()+1, e = indep_vars.end(); i != e; ++i) {
407 if (!shape_matches(*i, indep_shape))
408 throw Error(
"In function tabular(): Expected all of the 'independent' variables to have the same shape.");
412 read_values(indep_vars);
413 unsigned long num_indep_values = number_of_values(indep_shape);
414 SequenceValues indep_sv(num_indep_values);
415 build_sequence_values(indep_vars, indep_sv);
420 SequenceValues &result = indep_sv;
423 if (dep_vars.size() > 0) {
424 Shape dep_shape = array_shape(dep_vars.at(0));
426 for (vector<Array*>::iterator i = dep_vars.begin()+1, e = dep_vars.end(); i != e; ++i) {
427 if (!shape_matches(*i, dep_shape))
428 throw Error(
"In function tabular(): Expected all of the 'dependent' variables to have the same shape.");
434 if (dep_shape.size() > indep_shape.size() + 1)
435 throw Error(
"In function tabular(): The rank of the dependent variables may be at most one more than the rank of the independent variables");
436 if (dep_shape.size() < indep_shape.size())
437 throw Error(
"In function tabular(): The rank of the dependent variables cannot be less than the rank of the independent variables");
439 if (!dep_indep_match(dep_shape, indep_shape))
440 throw Error(
"In function tabular(): The 'independent' array shapes must match the right-most dimensions of the 'dependent' variables.");
442 read_values(dep_vars);
443 unsigned long num_dep_values = number_of_values(dep_shape);
444 SequenceValues dep_sv(num_dep_values);
447 add_index_column(indep_shape, dep_shape, dep_vars);
449 build_sequence_values(dep_vars, dep_sv);
454 combine_sequence_values(dep_sv, indep_sv);
458 unique_ptr<TabularSequence> response(
new TabularSequence(
"table"));
460 if (!dep_vars.empty()) {
462 for (
auto variable: dep_vars) {
463 response->add_var(variable->var());
467 for (
auto variable: indep_vars) {
468 response->add_var(variable->var());
472 response->set_value(result);
473 response->set_read_p(
true);
475 *btpp = response.release();
493BaseType *TabularFunction::function_dap4_tabular(D4RValueList *args, DMR &dmr)
497 unique_ptr<D4Sequence> response(
new D4Sequence(
"table"));
499 int num_arrays = args->size();
500 vector<unsigned long> shape;
501 vector<Array*> the_arrays(num_arrays);
503 for (
int n = 0; n < num_arrays; ++n) {
504 TabularFunction::build_columns(n, args->get_rvalue(n)->value(dmr), the_arrays, shape);
507 DBG(cerr <<
"the_arrays.size(): " << the_arrays.size() << endl);
509 for (
unsigned long n = 0; n < the_arrays.size(); ++n) {
510 response->add_var(the_arrays[n]->var());
513 unsigned long num_values = TabularFunction::number_of_values(shape);
514 D4SeqValues sv(num_values);
516 TabularFunction::build_sequence_values(the_arrays, sv);
518 response->set_value(sv);
519 response->set_read_p(
true);
521 return response.release();