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 <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 
45 #include <Array.h>
46 
47 #include <Error.h>
48 #include <DDS.h>
49 
50 #include <debug.h>
51 #include <util.h>
52 
53 #include <BaseTypeFactory.h>
54 
55 #include <BESDebug.h>
56 
57 #include "MakeArrayFunction.h"
58 
59 namespace libdap {
60 
65 vector<int>
66 parse_dims(const string &shape)
67 {
68  vector<int> dims;
69  istringstream iss(shape);
70  string::size_type pos = 0;
71  do {
72  char brace;
73  iss >> brace;
74  ++pos;
75  // EOF is only found by reading past the last character
76  if (iss.eof())
77  return dims;
78 
79  if (brace != '[' || iss.fail())
80  throw Error(malformed_expr, "make_array(): Expected a left brace at position " + long_to_string(pos) + " in shape expression: " + shape);
81 
82  int size = 0;
83  iss >> size;
84  ++pos;
85  if (size == 0 || iss.fail())
86  throw Error(malformed_expr, "make_array(): Expected an integer at position " + long_to_string(pos) + " in shape expression: " + shape);
87  dims.push_back(size);
88 
89  iss >> brace;
90  ++pos;
91  if (brace != ']' || iss.fail())
92  throw Error(malformed_expr, "make_array(): Expected a right brace at position " + long_to_string(pos) + " in shape expression: " + shape);
93  } while (!iss.eof());
94 
95  return dims;
96 }
97 
98 template<class DAP_Primitive, class DAP_BaseType>
99 static void
100 read_values(int argc, BaseType *argv[], Array *dest)
101 {
102  vector<DAP_Primitive> values;
103  values.reserve(argc-2); // The number of values/elements to read
104 
105  // read argv[2]...argv[2+N-1] elements, convert them to type an load them in the Array.
106  for (int i = 2; i < argc; ++i) {
107  BESDEBUG("functions", "Adding value: " << static_cast<DAP_BaseType*>(argv[i])->value() <<endl);
108  values.push_back(static_cast<DAP_BaseType*>(argv[i])->value());
109  }
110 
111  BESDEBUG("functions", "values size: " << values.size() << endl);
112 
113  // copy the values to the DAP Array
114  dest->set_value(values, values.size());
115 }
116 
129 void
130 function_make_array(int argc, BaseType * argv[], DDS &dds, BaseType **btpp)
131 {
132  string info =
133  string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") +
134  "<function name=\"make_array\" version=\"1.0\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#make_array\">\n" +
135  "</function>";
136 
137  if (argc == 0) {
138  Str *response = new Str("info");
139  response->set_value(info);
140  *btpp = response;
141  return;
142  }
143 
144  // Check for two args or more. The first two must be strings.
145  if (argc < 2)
146  throw Error(malformed_expr, "make_array(type,shape,[value0,...]) requires at least two arguments.");
147 
148  string type_name = extract_string_argument(argv[0]);
149  string shape = extract_string_argument(argv[1]);
150 
151  BESDEBUG("functions", "type: " << type_name << endl);
152  BESDEBUG("functions", "shape: " << shape << endl);
153 
154  // get the DAP type; NB: In DAP4 this will include Url4 and Enum
155  Type type = libdap::get_type(type_name.c_str());
156  if (!is_simple_type(type))
157  throw Error(malformed_expr, "make_array() can only build arrays of simple types (integers, floats and strings).");
158 
159  // parse the shape information. The shape expression form is [size0][size1]...[sizeN]
160  // count [ and ] and the numbers should match (low budget invariant) and that's N
161  // use an istringstream to read the integer sizes and build an Array
162  vector<int> dims = parse_dims(shape); // throws on parse error
163 
164  static unsigned long counter = 1;
165  string name;
166  do {
167  name = "g" + long_to_string(counter++);
168  } while (dds.var(name));
169 
170  Array *dest = new Array(name, 0); // The ctor for Array copies the prototype pointer...
171  BaseTypeFactory btf;
172  dest->add_var_nocopy(btf.NewVariable(type)); // ... so use add_var_nocopy() to add it instead
173 
174  unsigned long number_of_elements = 1;
175  vector<int>::iterator i = dims.begin();
176  while (i != dims.end()) {
177  number_of_elements *= *i;
178  dest->append_dim(*i++);
179  }
180 
181  // Get the total element number
182  // check that argc + 2 is N
183  if (number_of_elements + 2 != (unsigned long)argc)
184  throw Error(malformed_expr, "make_array(): Expected " + long_to_string(number_of_elements) + " but found " + long_to_string(argc-2) + " instead.");
185 
186  switch (type) {
187  // All integer values are stored in Int32 DAP variables by the stock argument parser
188  // except values too large; those are stored in a UInt32
189  case dods_byte_c:
190  read_values<dods_byte, Int32>(argc, argv, dest);
191  break;
192 
193  case dods_int16_c:
194  read_values<dods_int16, Int32>(argc, argv, dest);
195  break;
196 
197  case dods_uint16_c:
198  read_values<dods_uint16, Int32>(argc, argv, dest);
199  break;
200 
201  case dods_int32_c:
202  read_values<dods_int32, Int32>(argc, argv, dest);
203  break;
204 
205  case dods_uint32_c:
206  // FIXME Should be UInt32 but the parser uses Int32 unless a value is too big.
207  read_values<dods_uint32, Int32>(argc, argv, dest);
208  break;
209 
210  case dods_float32_c:
211  read_values<dods_float32, Float64>(argc, argv, dest);
212  break;
213 
214  case dods_float64_c:
215  read_values<dods_float64, Float64>(argc, argv, dest);
216  break;
217 
218  case dods_str_c:
219  read_values<string, Str>(argc, argv, dest);
220  break;
221 
222  case dods_url_c:
223  read_values<string, Url>(argc, argv, dest);
224  break;
225 
226  default:
227  throw InternalErr(__FILE__, __LINE__, "Unknown type error");
228  }
229 
230  dest->set_send_p(true);
231  dest->set_read_p(true);
232 
233  // return the array
234  *btpp = dest;
235  return;
236 }
237 
238 } // namesspace libdap
vector< int > parse_dims(const string &shape)
Parse the shape 'expression'.
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
void function_make_array(int argc, BaseType *argv[], DDS &dds, BaseType **btpp)
Build a new DAP Array variable.