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