OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
MakeArrayFunction.cc
Go to the documentation of this file.
1 
2 // -*- mode: c++; c-basic-offset:4 -*-
3 
4 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
5 // Access Protocol.
6 
7 // Copyright (c) 2013 OPeNDAP, Inc.
8 // Authors: Nathan Potter <npotter@opendap.org>
9 // James Gallagher <jgallagher@opendap.org>
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
26 
27 #include "config.h"
28 
29 #include <cassert>
30 
31 #include <sstream>
32 #include <vector>
33 
34 #include <Type.h>
35 #include <BaseType.h>
36 #include <Byte.h>
37 #include <Int16.h>
38 #include <UInt16.h>
39 #include <Int32.h>
40 #include <UInt32.h>
41 #include <Float32.h>
42 #include <Float64.h>
43 #include <Str.h>
44 #include <Url.h>
45 #include <Array.h>
46 #include <Error.h>
47 #include <DDS.h>
48 
49 #include <DMR.h>
50 #include <D4Group.h>
51 #include <D4RValue.h>
52 
53 #include <debug.h>
54 #include <util.h>
55 
56 #include <BaseTypeFactory.h>
57 
58 #include <BESDebug.h>
59 
60 #include "MakeArrayFunction.h"
61 
62 namespace libdap {
63 
65 string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") +
66 "<function name=\"make_array\" version=\"1.0\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#make_array\">\n" +
67 "</function>";
68 
73 vector<int>
74 parse_dims(const string &shape)
75 {
76  vector<int> dims;
77  istringstream iss(shape);
78  string::size_type pos = 0;
79  do {
80  char brace;
81  iss >> brace;
82  ++pos;
83  // EOF is only found by reading past the last character
84  if (iss.eof())
85  return dims;
86 
87  if (brace != '[' || iss.fail())
88  throw Error(malformed_expr, "make_array(): Expected a left brace at position " + long_to_string(pos) + " in shape expression: " + shape);
89 
90  int size = 0;
91  iss >> size;
92  ++pos;
93  if (size == 0 || iss.fail())
94  throw Error(malformed_expr, "make_array(): Expected an integer at position " + long_to_string(pos) + " in shape expression: " + shape);
95  dims.push_back(size);
96 
97  iss >> brace;
98  ++pos;
99  if (brace != ']' || iss.fail())
100  throw Error(malformed_expr, "make_array(): Expected a right brace at position " + long_to_string(pos) + " in shape expression: " + shape);
101  } while (!iss.eof());
102 
103  return dims;
104 }
105 
106 
107 
108 bool isValidTypeMatch(Type requestedType, Type argType){
109  bool typematch_status = false;
110  switch (requestedType) {
111  case dods_byte_c:
112  case dods_int16_c:
113  case dods_uint16_c:
114  case dods_int32_c:
115  case dods_uint32_c:
116  {
117  // All integer values are stored in Int32 DAP variables by the stock argument parser
118  // except values too large; those are stored in a UInt32 these return the same size value
119  // (i.e. casting one to the other is fine, at least I think)
120  // FIXME - Verify this assumption
121  switch(argType){
122  case dods_int32_c:
123  case dods_uint32_c:
124  {
125  typematch_status=true;
126  }
127  break;
128  default:
129  break;
130  }
131  }
132  break;
133 
134 
135  case dods_float32_c:
136  case dods_float64_c:
137  {
138  // All floating point values are stored as Float64 by the stock argument parser
139  // FIXME - Verify this assumption
140  switch(argType){
141  case dods_float64_c:
142  {
143  typematch_status=true;
144  }
145  break;
146  default:
147  break;
148  }
149  }
150  break;
151 
152  case dods_str_c:
153  case dods_url_c:
154  {
155  // Strings and Urls, like Int32 and UInt32 are pretty much the same
156  // FIXME - Verify this assumption
157  switch(argType){
158  case dods_str_c:
159  case dods_url_c:
160  {
161  typematch_status=true;
162  }
163  break;
164  default:
165  break;
166  }
167  }
168  break;
169 
170  default:
171  throw InternalErr(__FILE__, __LINE__, "Unknown type error");
172  }
173 
174  return typematch_status;
175 
176 }
177 
178 template<class DAP_Primitive, class DAP_BaseType>
179 static void
180 read_values(int argc, BaseType *argv[], Array *dest)
181 {
182  vector<DAP_Primitive> values;
183  values.reserve(argc-2); // The number of values/elements to read
184 
185  string requestedTypeName = extract_string_argument(argv[0]);
186  Type requestedType = libdap::get_type(requestedTypeName.c_str());
187  BESDEBUG("functions", "Requested array type: " << requestedTypeName<< endl);
188 
189  // read argv[2]...argv[2+N-1] elements, convert them to type an load them in the Array.
190  for (int i = 2; i < argc; ++i) {
191  BESDEBUG("functions", "Adding value of type " << argv[i]->type_name() << endl);
192  if(!isValidTypeMatch(requestedType,argv[i]->type())){
193  throw Error(malformed_expr, "make_array(): Expected values to be of type " + requestedTypeName +
194  " but argument " + long_to_string(i) +
195  " evaluated into a type " + argv[i]->type_name() + " instead.");
196  }
197  BESDEBUG("functions", "Adding value: " << static_cast<DAP_BaseType*>(argv[i])->value() << endl);
198  values.push_back(static_cast<DAP_BaseType*>(argv[i])->value());
199  }
200 
201  BESDEBUG("functions", "values size: " << values.size() << endl);
202 
203  // copy the values to the DAP Array
204  dest->set_value(values, values.size());
205 }
206 
207 template<class DAP_Primitive, class DAP_BaseType>
208 static void
209 read_values(D4RValueList *args, DMR &dmr, Array *dest)
210 {
211  vector<DAP_Primitive> values;
212  values.reserve(args->size()-2); // The number of values/elements to read
213 
214  string requestedTypeName = extract_string_argument(args->get_rvalue(0)->value(dmr));
215  Type requestedType = libdap::get_type(requestedTypeName.c_str());
216  BESDEBUG("functions", "Requested array type: " << requestedTypeName<< endl);
217 
218  // read argv[2]...argv[2+N-1] elements, convert them to type an load them in the Array.
219  for (unsigned int i = 2; i < args->size(); ++i) {
220 
221  BESDEBUG("functions", "Adding value of type " << args->get_rvalue(i)->value(dmr)->type_name() << endl);
222  if(!isValidTypeMatch(requestedType,args->get_rvalue(i)->value(dmr)->type())){
223  throw Error(malformed_expr, "make_array(): Expected values to be of type " + requestedTypeName +
224  " but argument " + long_to_string(i) +
225  " evaluated into a type " + args->get_rvalue(i)->value(dmr)->type_name() + " instead.");
226  }
227 
228  BESDEBUG("functions", "Adding value: " << static_cast<DAP_BaseType*>(args->get_rvalue(i)->value(dmr))->value() <<endl);
229  values.push_back(static_cast<DAP_BaseType*>(args->get_rvalue(i)->value(dmr))->value());
230  }
231 
232  BESDEBUG("functions", "values size: " << values.size() << endl);
233 
234  // copy the values to the DAP Array
235  dest->set_value(values, values.size());
236 }
237 
238 
239 
240 
241 
254 void
255 function_make_dap2_array(int argc, BaseType * argv[], DDS &dds, BaseType **btpp)
256 {
257 
258  if (argc == 0) {
259  Str *response = new Str("info");
260  response->set_value(make_array_info);
261  *btpp = response;
262  return;
263  }
264 
265  BESDEBUG("functions", "function_make_dap2_array() - argc: " << long_to_string(argc) << endl);
266 
267  // Check for two args or more. The first two must be strings.
268  if (argc < 2)
269  throw Error(malformed_expr, "make_array(type,shape,[value0,...]) requires at least two arguments.");
270 
271  string requested_type_name = extract_string_argument(argv[0]);
272  string shape = extract_string_argument(argv[1]);
273 
274  BESDEBUG("functions", "function_make_dap2_array() - type: " << requested_type_name << endl);
275  BESDEBUG("functions", "function_make_dap2_array() - shape: " << shape << endl);
276 
277  // get the DAP type; NB: In DAP4 this will include Url4 and Enum
278  Type requested_type = libdap::get_type(requested_type_name.c_str());
279  if (!is_simple_type(requested_type))
280  throw Error(malformed_expr, "make_array() can only build arrays of simple types (integers, floats and strings).");
281 
282  // parse the shape information. The shape expression form is [size0][size1]...[sizeN]
283  // count [ and ] and the numbers should match (low budget invariant) and that's N
284  // use an istringstream to read the integer sizes and build an Array
285  vector<int> dims = parse_dims(shape); // throws on parse error
286 
287  static unsigned long counter = 1;
288  string name;
289  do {
290  name = "g" + long_to_string(counter++);
291  } while (dds.var(name));
292 
293  Array *dest = new Array(name, 0); // The ctor for Array copies the prototype pointer...
294  BaseTypeFactory btf;
295  dest->add_var_nocopy(btf.NewVariable(requested_type)); // ... so use add_var_nocopy() to add it instead
296 
297  unsigned long number_of_elements = 1;
298  vector<int>::iterator i = dims.begin();
299  while (i != dims.end()) {
300  number_of_elements *= *i;
301  dest->append_dim(*i++);
302  }
303 
304  // Get the total element number
305  // check that argc + 2 is N
306  if (number_of_elements + 2 != (unsigned long)argc)
307  throw Error(malformed_expr, "make_array(): Expected " + long_to_string(number_of_elements) + " parameters but found " + long_to_string(argc-2) + " instead.");
308 
309  switch (requested_type) {
310  // All integer values are stored in Int32 DAP variables by the stock argument parser
311  // except values too large; those are stored in a UInt32
312  case dods_byte_c:
313  read_values<dods_byte, Int32>(argc, argv, dest);
314  break;
315 
316  case dods_int16_c:
317  read_values<dods_int16, Int32>(argc, argv, dest);
318  break;
319 
320  case dods_uint16_c:
321  read_values<dods_uint16, Int32>(argc, argv, dest);
322  break;
323 
324  case dods_int32_c:
325  read_values<dods_int32, Int32>(argc, argv, dest);
326  break;
327 
328  case dods_uint32_c:
329  // FIXME Should be UInt32 but the parser uses Int32 unless a value is too big.
330  read_values<dods_uint32, Int32>(argc, argv, dest);
331  break;
332 
333  case dods_float32_c:
334  read_values<dods_float32, Float64>(argc, argv, dest);
335  break;
336 
337  case dods_float64_c:
338  read_values<dods_float64, Float64>(argc, argv, dest);
339  break;
340 
341  case dods_str_c:
342  read_values<string, Str>(argc, argv, dest);
343  break;
344 
345  case dods_url_c:
346  read_values<string, Url>(argc, argv, dest);
347  break;
348 
349  default:
350  throw InternalErr(__FILE__, __LINE__, "Unknown type error");
351  }
352 
353  dest->set_send_p(true);
354  dest->set_read_p(true);
355 
356  // return the array
357  *btpp = dest;
358  return;
359 }
360 
361 BaseType *function_make_dap4_array(D4RValueList *args, DMR &dmr){
362  // DAP4 function porting information: in place of 'argc' use 'args.size()'
363  if (args == 0 || args->size() == 0) {
364  Str *response = new Str("info");
365  response->set_value(make_array_info);
366  // DAP4 function porting: return a BaseType* instead of using the value-result parameter
367  return response;
368  }
369 
370  // Check for 2 arguments
371  DBG(cerr << "args.size() = " << args.size() << endl);
372  if (args->size() < 2)
373  throw Error(malformed_expr,"Wrong number of arguments to make_array(). See make_array() for more information");
374 
375  string requested_type_name = extract_string_argument(args->get_rvalue(0)->value(dmr));
376  string shape = extract_string_argument(args->get_rvalue(1)->value(dmr));
377 
378 
379  BESDEBUG("functions", "type: " << requested_type_name << endl);
380  BESDEBUG("functions", "shape: " << shape << endl);
381 
382 
383  // get the DAP type; NB: In DAP4 this will include Url4 and Enum
384  Type requested_type = libdap::get_type(requested_type_name.c_str());
385  if (!is_simple_type(requested_type))
386  throw Error(malformed_expr, "make_array() can only build arrays of simple types (integers, floats and strings).");
387 
388  // parse the shape information. The shape expression form is [size0][size1]...[sizeN]
389  // count [ and ] and the numbers should match (low budget invariant) and that's N
390  // use an istringstream to read the integer sizes and build an Array
391  vector<int> dims = parse_dims(shape); // throws on parse error
392 
393  static unsigned long counter = 1;
394  string name;
395  do {
396  name = "g" + long_to_string(counter++);
397  } while (dmr.root()->var(name));
398 
399  Array *dest = new Array(name, 0); // The ctor for Array copies the prototype pointer...
400  BaseTypeFactory btf;
401  dest->add_var_nocopy(btf.NewVariable(requested_type)); // ... so use add_var_nocopy() to add it instead
402 
403  unsigned long number_of_elements = 1;
404  vector<int>::iterator i = dims.begin();
405  while (i != dims.end()) {
406  number_of_elements *= *i;
407  dest->append_dim(*i++);
408  }
409 
410  // Get the total element number
411  // check that args.size() + 2 is N
412  if (number_of_elements + 2 != args->size())
413  throw Error(malformed_expr, "make_array(): Expected " + long_to_string(number_of_elements) + " parameters but found " + long_to_string(args->size()-2) + " instead.");
414 
415  switch (requested_type) {
416  // All integer values are stored in Int32 DAP variables by the stock argument parser
417  // except values too large; those are stored in a UInt32
418  case dods_byte_c:
419  read_values<dods_byte, Int32>(args, dmr, dest);
420  break;
421 
422  case dods_int16_c:
423  read_values<dods_int16, Int32>(args, dmr, dest);
424  break;
425 
426  case dods_uint16_c:
427  read_values<dods_uint16, Int32>(args, dmr, dest);
428  break;
429 
430  case dods_int32_c:
431  read_values<dods_int32, Int32>(args, dmr, dest);
432  break;
433 
434  case dods_uint32_c:
435  // FIXME Should be UInt32 but the parser uses Int32 unless a value is too big.
436  read_values<dods_uint32, Int32>(args, dmr, dest);
437  break;
438 
439  case dods_float32_c:
440  read_values<dods_float32, Float64>(args, dmr, dest);
441  break;
442 
443  case dods_float64_c:
444  read_values<dods_float64, Float64>(args, dmr, dest);
445  break;
446 
447  case dods_str_c:
448  read_values<string, Str>(args, dmr, dest);
449  break;
450 
451  case dods_url_c:
452  read_values<string, Url>(args, dmr, dest);
453  break;
454 
455  default:
456  throw InternalErr(__FILE__, __LINE__, "Unknown type error");
457  }
458  dest->set_send_p(true);
459  dest->set_read_p(true);
460 
461  return dest;
462 
463 }
464 
465 
466 
467 } // namesspace libdap
BaseType * function_make_dap4_array(D4RValueList *args, DMR &dmr)
The linear_scale() function applies the familiar y = mx + b equation to data.
void function_make_dap2_array(int argc, BaseType *argv[], DDS &dds, BaseType **btpp)
Build a new DAP Array variable.
vector< int > parse_dims(const string &shape)
Parse the shape 'expression'.
static class NCMLUtil overview
bool isValidTypeMatch(Type requestedType, Type argType)
string make_array_info
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64