bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
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 <libdap/Type.h>
34#include <libdap/BaseType.h>
35#include <libdap/Byte.h>
36#include <libdap/Int16.h>
37#include <libdap/UInt16.h>
38#include <libdap/Int32.h>
39#include <libdap/UInt32.h>
40#include <libdap/Float32.h>
41#include <libdap/Float64.h>
42#include <libdap/Str.h>
43#include <libdap/Url.h>
44#include <libdap/Array.h>
45#include <libdap/Error.h>
46#include <libdap/DDS.h>
47
48#include <libdap/DMR.h>
49#include <libdap/D4Group.h>
50#include <libdap/D4RValue.h>
51
52#include <libdap/debug.h>
53#include <libdap/util.h>
54
55#include <libdap/BaseTypeFactory.h>
56
57#include <BESDebug.h>
58
59#include "MakeArrayFunction.h"
60#include "functions_util.h"
61
62using namespace libdap;
63
64namespace functions {
65
66string 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
71bool 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
130template<class DAP_Primitive, class DAP_BaseType>
131static 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
158template<class DAP_Primitive, class DAP_BaseType>
159static 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
202void 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
309BaseType *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 of JSON value.
Definition rapidjson.h:664