bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
FFArray.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of ff_handler a FreeForm API handler for the OPeNDAP
4// DAP2 data server.
5
6// Copyright (c) 2005 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This is free software; you can redistribute it and/or modify it under the
10// terms of the GNU Lesser General Public License as published by the Free
11// Software Foundation; either version 2.1 of the License, or (at your
12// option) any later version.
13//
14// This software is distributed in the hope that it will be useful, but
15// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17// License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25// (c) COPYRIGHT URI/MIT 1997-99
26// Please read the full copyright statement in the file COPYRIGHT.
27//
28// Authors: reza (Reza Nekovei)
29
30// FreeFrom sub-class implementation for FFByte,...FFGrid.
31// The files are patterned after the subcalssing examples
32// Test<type>.c,h files.
33//
34// ReZa 6/18/97
35
36#include "config_ff.h"
37
38static char rcsid[] not_used = { "$Id$" };
39
40#include <cstring>
41#include <iostream>
42#include <string>
43
44#include <BESDebug.h>
45
46#include <libdap/dods-datatypes.h>
47#include <libdap/D4Attributes.h>
48#include <libdap/D4Group.h>
49#include <libdap/Error.h>
50#include <libdap/InternalErr.h>
51
52#include "FFArray.h"
53#include "util_ff.h"
54#include <libdap/util.h>
55
56BaseType *
57FFArray::ptr_duplicate()
58{
59 return new FFArray(*this);
60}
61
62FFArray::FFArray(const string &n, const string &d, BaseType *v, const string &iff) :
63 Array(n, d, v), d_input_format_file(iff)
64{
65}
66
67FFArray::~FFArray()
68{
69}
70
71// parse constraint expr. and make coordinate point location for an array.
72// return number of elements to read.
73
74long FFArray::Arr_constraint(long *cor, long *step, long *edg, string *dim_nms, bool *has_stride)
75{
76 long start, stride, stop;
77
78 int id = 0;
79 long nels = 1;
80 *has_stride = false;
81
82 Array::Dim_iter i = dim_begin();
83 while (i != dim_end()) {
84 start = (long) dimension_start(i, true);
85 stride = (long) dimension_stride(i, true);
86 stop = (long) dimension_stop(i, true);
87 string dimname = dimension_name(i);
88#if 0
89 // Check for empty constraint
90 if (start + stop + stride == 0)
91 return -1;
92#endif
93 // This code is a correct version of the above, but it _should_ never be called
94 // since libdap::Vector::serialize() will never call Array::read() when length is
95 // zero. Still, a server function might... jhrg 2/17/16
96 if (length() == 0)
97 return -1;
98
99 dim_nms[id] = dimname;
100 // (void) strcpy(dim_nms[id], dimname.c_str());
101
102 cor[id] = start;
103 step[id] = stride;
104 edg[id] = ((stop - start) / stride) + 1; // count of elements
105
106 nels *= edg[id]; // total number of values for variable
107
108 if (stride != 1)
109 *has_stride = true;
110
111 ++id;
112 ++i;
113 }
114 return nels;
115}
116
117#if 0
118// parse constraint expr. and make coordinate point location.
119// return number of elements to read.
120
121long FFArray::Seq_constraint(long *cor, long *step, long *edg, bool *has_stride)
122{
123 int start, stride, stop;
124 int id = 0;
125 long nels = 1;
126 *has_stride = false;
127
128 Array::Dim_iter i = dim_begin();
129 while (i != dim_end()) {
130 start = (long) dimension_start(i, true);
131 stride = (long) dimension_stride(i, true);
132 stop = (long) dimension_stop(i, true);
133#if 0
134 // Check for empty constraint
135 if (start + stop + stride == 0)
136 return -1;
137#endif
138 if (length() == 0)
139 return -1;
140
141 cor[id] = start;
142 step[id] = stride;
143 edg[id] = ((stop - start) / stride) + 1; // count of elements
144 nels *= edg[id]; // total number of values for variable
145 if (stride != 1)
146 *has_stride = true;
147
148 ++id;
149 ++i;
150 }
151 return nels;
152}
153#endif
154
155#if 0
156static int hyper_get(void *dest, void *src, unsigned szof, const int dim_num, int index, const int dimsz[],
157 const long start[], const long edge[])
158{
159 long jump = 1;
160
161 // The THEN part of this IF handles the cases where we are hyper-slabbing
162 // any dimension *other* than the rightmost dimension. E.G. Suppose
163 // a[10][10][10] is in SRC, for INDEX == 0 and 1 we do the code in the
164 // THEN clause and for INDEX == 2 the ELSE clause is executed.
165
166 // NOTE: I have added casts for src and dest from void * to char * since
167 // ANSI C++ won't allow pointer arithmetic on void * variables. 4/17/98
168 // jhrg
169
170 if (dim_num != (index + 1)) {
171 // number of lines, pages, etc to skip
172 for (int i = dim_num - 1; i > index; i--)
173 jump *= dimsz[i];
174
175 for (int edge_tmp = 0; edge_tmp < edge[index]; edge_tmp++) {
176 void *srctmp = ((char *) src + (start[index] + edge_tmp) * jump * szof);
177 dest = (char *) dest + hyper_get(dest, srctmp, szof, dim_num, index + 1, dimsz, start, edge);
178 }
179 return (0);
180 }
181 else {
182 // number of bytes to jump
183 void *srctmp = (char *) src + start[index] * szof;
184 memcpy(dest, srctmp, (size_t) edge[index] * szof);
185 return (edge[index] * szof);
186 }
187}
188#endif
189
190#if 0
191template<class T>
192static void seq2vects(T * t, FFArray & array)
193{
194 bool has_stride;
195 int ndim = array.dimensions();
196 long *start = new long[ndim];
197 long *stride = new long[ndim];
198 long *edge = new long[ndim];
199
200 long count = array.Seq_constraint(start, stride, edge, &has_stride);
201
202 if (count != -1) { // non-null hyperslab
203 T *t_hs = new T[count];
204 int *dimsz = new int[array.dimensions()];
205
206 int i = 0;
207 Array::Dim_iter p = array.dim_begin();
208 while (p != array.dim_end()) {
209 dimsz[i] = array.dimension_length(p);
210 ++i;
211 ++p;
212 }
213
214 hyper_get(t_hs, t, array.var()->width(), ndim, 0, dimsz, start, edge);
215
216 array.set_read_p(true); // reading is done
217 array.val2buf((void *) t_hs); // put values in the buffer
218
219 delete[] t_hs;
220 delete[] dimsz;
221 }
222 else {
223 array.set_read_p(true);
224 array.val2buf((void *) t);
225 }
226
227 delete[] start;
228 delete[] stride;
229 delete[] edge;
230}
231#endif
232
233// Read cardinal types and ctor types separately. Cardinal types are
234// stored in arrays of the C++ data type while ctor types are stored
235// in arrays of the DODS classes used to store those types.
236//
237// NB: Currently this code only reads arrays of Byte, Int32 and
238// Float64. Str and Url as well as all the ctor types are not
239// supported.
240//
241// Throws an Error object if an error was detected.
242// Returns true if more data still needs to be read, otherwise returns false.
243
244bool FFArray::read()
245{
246 if (read_p()) // Nothing to do
247 return true;
248
249 bool has_stride;
250 int ndims = dimensions();
251 vector<string> dname(ndims);
252 vector<long> start(ndims);
253 vector<long> stride(ndims);
254 vector<long> edge(ndims);
255 long count = Arr_constraint(start.data(), stride.data(), edge.data(), dname.data(), &has_stride);
256
257 if (!count) {
258 throw Error(unknown_error, "Constraint returned an empty dataset.");
259 }
260
261 string output_format = makeND_output_format(name(), var()->type(), var()->width(),
262 ndims, start.data(), edge.data(), stride.data(), dname.data());
263
264 // For each cardinal-type variable, do the following:
265 // Use ff to read the data
266 // Store the (possibly constrained) data
267 // NB: extract_array throws an Error object to signal problems.
268
269 switch (var()->type()) {
270 case dods_byte_c:
271 extract_array<dods_byte>(dataset(), d_input_format_file, output_format);
272 break;
273
274 case dods_int16_c:
275 extract_array<dods_int16>(dataset(), d_input_format_file, output_format);
276 break;
277
278 case dods_uint16_c:
279 extract_array<dods_uint16>(dataset(), d_input_format_file, output_format);
280 break;
281
282 case dods_int32_c:
283 extract_array<dods_int32>(dataset(), d_input_format_file, output_format);
284 break;
285
286 case dods_uint32_c:
287 extract_array<dods_uint32>(dataset(), d_input_format_file, output_format);
288 break;
289
290 case dods_float32_c:
291 extract_array<dods_float32>(dataset(), d_input_format_file, output_format);
292 break;
293
294 case dods_float64_c:
295 extract_array<dods_float64>(dataset(), d_input_format_file, output_format);
296 break;
297
298 default:
299 throw InternalErr(__FILE__, __LINE__,
300 (string) "FFArray::read: Unsupported array type " + var()->type_name() + ".");
301 }
302
303 return true;
304}
305
306// This template reads arrays of simple types into the Array object's _buf
307// member. It returns true if successful, false otherwise.
308
309template<class T>
310bool FFArray::extract_array(const string &ds, const string &if_fmt, const string &o_fmt)
311{
312 vector<T> d(length());
313 long bytes = read_ff(ds.c_str(), if_fmt.c_str(), o_fmt.c_str(), (char *) d.data(), width());
314
315 BESDEBUG("ff", "FFArray::extract_array: Read " << bytes << " bytes." << endl);
316
317 if (bytes == -1) {
318 throw Error(unknown_error, "Could not read values from the dataset.");
319 }
320 else {
321 set_read_p(true);
322 set_value(d, d.size());
323 }
324
325 return true;
326}