bes  Updated for version 3.20.6
TabularSequence.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) 2015 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@opendap.org>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public 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 #include "config.h"
26 
27 #include <algorithm>
28 #include <string>
29 #include <sstream>
30 
31 //#define DODS_DEBUG
32 
33 #include <BaseType.h>
34 #include <Byte.h>
35 #include <Int16.h>
36 #include <Int32.h>
37 #include <UInt16.h>
38 #include <UInt32.h>
39 #include <Float32.h>
40 #include <Float64.h>
41 #include <Str.h>
42 #include <Url.h>
43 
44 #include <DDS.h>
45 #include <ConstraintEvaluator.h>
46 #include <Marshaller.h>
47 #include <UnMarshaller.h>
48 #include <debug.h>
49 
50 #include "BESIndent.h"
51 #include "TabularSequence.h"
52 
53 using namespace std;
54 using namespace libdap;
55 
56 namespace functions {
57 
58 // static constants and functions copied from the parent class. These
59 // should never have been static... hindsight
60 
61 static const unsigned char end_of_sequence = 0xA5; // binary pattern 1010 0101
62 static const unsigned char start_of_instance = 0x5A; // binary pattern 0101 1010
63 
64 static void
65 write_end_of_sequence(Marshaller &m)
66 {
67  m.put_opaque( (char *)&end_of_sequence, 1 ) ;
68 }
69 
70 static void
71 write_start_of_instance(Marshaller &m)
72 {
73  m.put_opaque( (char *)&start_of_instance, 1 ) ;
74 }
75 
76 void TabularSequence::load_prototypes_with_values(BaseTypeRow &btr, bool safe)
77 {
78  // For each of the prototype variables in the Sequence, load it
79  // with a values from the BaseType* vector. The order should match.
80  // Test the type, but assume if that matches, the value is correct
81  // for the variable.
82  Vars_iter i = d_vars.begin(), e = d_vars.end();
83  for (BaseTypeRow::iterator vi = btr.begin(), ve = btr.end(); vi != ve; ++vi) {
84 
85  if (safe && (i == e || ((*i)->type() != (*vi)->var()->type())))
86  throw InternalErr(__FILE__, __LINE__, "Expected number and types to match when loading values for selection expression evaluation.");
87 
88  // Ugly... but faster than the generic code that allocates storage for each scalar?
89  switch ((*i)->type()) {
90  case dods_byte_c:
91  static_cast<Byte*>(*i++)->set_value(static_cast<Byte*>(*vi)->value());
92  break;
93  case dods_int16_c:
94  static_cast<Int16*>(*i++)->set_value(static_cast<Int16*>((*vi))->value());
95  break;
96  case dods_int32_c:
97  static_cast<Int32*>(*i++)->set_value(static_cast<Int32*>((*vi))->value());
98  break;
99  case dods_uint16_c:
100  static_cast<UInt16*>(*i++)->set_value(static_cast<UInt16*>((*vi))->value());
101  break;
102  case dods_uint32_c:
103  static_cast<UInt32*>(*i++)->set_value(static_cast<UInt32*>((*vi))->value());
104  break;
105  case dods_float32_c:
106  static_cast<Float32*>(*i++)->set_value(static_cast<Float32*>((*vi))->value());
107  break;
108  case dods_float64_c:
109  static_cast<Float64*>(*i++)->set_value(static_cast<Float64*>((*vi))->value());
110  break;
111  case dods_str_c:
112  static_cast<Str*>(*i++)->set_value(static_cast<Str*>((*vi))->value());
113  break;
114  case dods_url_c:
115  static_cast<Url*>(*i++)->set_value(static_cast<Url*>((*vi))->value());
116  break;
117  default:
118  throw InternalErr(__FILE__, __LINE__, "Expected a scalar type when loading values for selection expression evaluation.");
119  }
120  }
121 }
122 
123 // Public member functions
124 
141 bool
142 TabularSequence::serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval /* true */)
143 {
144  DBG(cerr << "Entering TabularSequence::serialize for " << name() << endl);
145 
146  SequenceValues &values = value_ref();
147  //ce_eval = true; Commented out here and changed in BESDapResponseBuilder. jhrg 3/10/15
148 
149  for (SequenceValues::iterator i = values.begin(), e = values.end(); i != e; ++i) {
150 
151  BaseTypeRow &btr = **i;
152 
153  // Transfer values of the current row into the Seq's prototypes so the CE
154  // evaluator will find the values.
155 #if 1
156  load_prototypes_with_values(btr, false);
157 #else
158  int j = 0;
159  for (BaseTypeRow::iterator vi = btr.begin(), ve = btr.end(); vi != ve; ++vi) {
160  void *val = 0;
161  (*vi)->buf2val(&val);
162  d_vars.at(j++)->val2buf(val);
163  }
164 #endif
165  DBG(cerr << __func__ << ": Sequence element: " << hex << *btr.begin() << dec << endl);
166  // Evaluate the CE against this row; continue (skipping this row) if it fails
167  if (ce_eval && !eval.eval_selection(dds, dataset()))
168  continue;
169 
170  // Write out this row of values
171  write_start_of_instance(m);
172 
173  // In this loop serialize will signal an error with an exception.
174  for (BaseTypeRow::iterator vi = btr.begin(), ve = btr.end(); vi != ve; ++vi) {
175  if ((*vi)->send_p()) {
176  (*vi)->serialize(eval, dds, m, false);
177  }
178  }
179  }
180 
181  write_end_of_sequence(m);
182 
183  return true; // Signal errors with exceptions.
184 }
185 
195 void TabularSequence::intern_data(ConstraintEvaluator &eval, DDS &dds)
196 {
197  DBG(cerr << "Entering TabularSequence::intern_data" << endl);
198 
199  // TODO Special case when there are no selection clauses
200  // TODO Use a destructive copy to move values from 'values' to
201  // result? Or pop values - find a way to not copy all the values
202  // after doing some profiling to see if this code can be meaningfully
203  // optimized
204  SequenceValues result; // These values satisfy the CE
205  SequenceValues &values = value_ref();
206 
207  for (SequenceValues::iterator i = values.begin(), e = values.end(); i != e; ++i) {
208 
209  BaseTypeRow &btr = **i;
210 
211  // Transfer values of the current row into the Seq's prototypes so the CE
212  // evaluator will find the values.
213  load_prototypes_with_values(btr, false /* safe */);
214 #if 0
215  int j = 0;
216  for (BaseTypeRow::iterator vi = btr.begin(), ve = btr.end(); vi != ve; ++vi) {
217  // TODO check this for efficiency - is the switch-based version (load_prototypes_with_values) faster?
218  void *val = 0;
219  (*vi)->buf2val(&val);
220  d_vars.at(j++)->val2buf(val);
221  }
222 #endif
223  // Evaluate the CE against this row; continue (skipping this row) if it fails
224  if (!eval.eval_selection(dds, dataset()))
225  continue;
226 
227  BaseTypeRow *result_row = new BaseTypeRow();
228  for (BaseTypeRow::iterator vi = btr.begin(), ve = btr.end(); vi != ve; ++vi) {
229  if ((*vi)->send_p()) {
230  result_row->push_back(*vi);
231  }
232  }
233 
234  result.push_back(result_row);
235  }
236 
237  set_value(result);
238 
239  DBG(cerr << "Leaving TabularSequence::intern_data" << endl);
240 }
241 
250 void
251 TabularSequence::dump(ostream &strm) const
252 {
253  strm << BESIndent::LMarg << "TabularSequence::dump - (" << (void *)this << ")" << endl ;
254  BESIndent::Indent() ;
255  Sequence::dump(strm) ;
256  BESIndent::UnIndent() ;
257 }
258 
259 } // namespace functions
260 
libdap
Definition: BESDapFunctionResponseCache.h:35