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