libdap++  Updated for version 3.12.0
ConstraintEvaluator.cc
Go to the documentation of this file.
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) 2002,2003 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 //#define DODS_DEBUG
28 
29 #include "ServerFunctionsList.h"
30 #include "ConstraintEvaluator.h"
31 
32 #include "ce_parser.h"
33 #include "debug.h"
34 #include "parser.h"
35 #include "expr.h"
36 //#include "ce_expr.tab.hh"
37 
38 struct yy_buffer_state;
39 
41 
42 // Glue routines declared in expr.lex
43 void ce_expr_switch_to_buffer(void *new_buffer);
44 void ce_expr_delete_buffer(void * buffer);
45 void *ce_expr_string(const char *yy_str);
46 
47 extern int ce_exprdebug;
48 
49 namespace libdap {
50 
52 {
53  // Functions are now held in BES modules. jhrg 1/30/13
54 
55  // modules load functions to this list; this class searches the list
56  // instead of having it's own copy. This is very similar to the BES'
57  // various List classes, but this one is part of libdap and not the
58  // BES. The List class is a singleton, so each function module can
59  // register it's functions to the list object.
60  d_functions_list = ServerFunctionsList::TheList();
61 }
62 
64 {
65  // delete all the constants created by the parser for CE evaluation
66  for (Constants_iter j = constants.begin(); j != constants.end(); j++) {
67  BaseType *btp = *j;
68  delete btp;
69  btp = 0;
70  }
71 
72  for (Clause_iter k = expr.begin(); k != expr.end(); k++) {
73  Clause *cp = *k;
74  delete cp;
75  cp = 0;
76  }
77 }
78 
81 {
82  return expr.begin();
83 }
84 
88 {
89  return expr.end();
90 }
91 
94 bool ConstraintEvaluator::clause_value(Clause_iter &iter, DDS &dds/*, const string &***/)
95 {
96  if (expr.empty())
97  throw InternalErr(__FILE__, __LINE__, "There are no CE clauses for *this* DDS object.");
98 
99  return (*iter)->value(dds);
100 }
101 
115 {
116  Clause *clause = new Clause(op, arg1, arg2);
117 
118  expr.push_back(clause);
119 }
120 
131 {
132  Clause *clause = new Clause(func, args);
133 
134  expr.push_back(clause);
135 }
136 
147 {
148  Clause *clause = new Clause(func, args);
149 
150  expr.push_back(clause);
151 }
152 
161 {
162  constants.push_back(btp);
163 }
164 
165 // This code was removed when I switched from CE having it's own internal
166 // list of functions to using an external list.
167 #if 0
168 class func_name_is {
169 private:
170  const string d_name;
171 
172 public:
173  func_name_is(const string &name) :
174  d_name(name)
175  {
176  }
177  bool operator()(const ConstraintEvaluator::function f)
178  {
179  return f.name == d_name;
180  }
181 };
182 
203 void ConstraintEvaluator::add_function(const string &name, bool_func f)
204 {
205  functions.remove_if(func_name_is(name));
206  function func(name, f);
207  functions.push_back(func);
208 }
209 
211 void ConstraintEvaluator::add_function(const string &name, btp_func f)
212 {
213  functions.remove_if(func_name_is(name));
214  function func(name, f);
215  functions.push_back(func);
216 }
217 
219 void ConstraintEvaluator::add_function(const string &name, proj_func f)
220 {
221  functions.remove_if(func_name_is(name));
222  function func(name, f);
223  functions.push_back(func);
224 }
225 #endif
226 
228 bool ConstraintEvaluator::find_function(const string &name, bool_func *f) const
229 {
230  return d_functions_list->find_function(name, f);
231 #if 0
232  if (functions.empty())
233  return false;
234 
235  for (Functions_citer i = functions.begin(); i != functions.end(); i++) {
236  if (name == (*i).name && (*f = (*i).b_func)) {
237  return true;
238  }
239  }
240 
241  return false;
242 #endif
243 }
244 
246 bool ConstraintEvaluator::find_function(const string &name, btp_func *f) const
247 {
248  return d_functions_list->find_function(name, f);
249 #if 0
250  if (functions.empty())
251  return false;
252 
253  for (Functions_citer i = functions.begin(); i != functions.end(); i++) {
254  if (name == (*i).name && (*f = (*i).bt_func)) {
255  return true;
256  }
257  }
258 
259  return false;
260 #endif
261 }
262 
264 bool ConstraintEvaluator::find_function(const string &name, proj_func *f) const
265 {
266  return d_functions_list->find_function(name, f);
267 #if 0
268  if (functions.empty())
269  return false;
270 
271  for (Functions_citer i = functions.begin(); i != functions.end(); i++)
272  if (name == (*i).name && (*f = (*i).p_func)) {
273  return true;
274  }
275 
276  return false;
277 #endif
278 }
280 
290 {
291  if (expr.empty())
292  return false;
293 
294  Clause *cp = expr[0];
295  return cp->value_clause();
296 }
297 
301 BaseType *
303 {
304  if (expr.size() != 1)
305  throw InternalErr(__FILE__, __LINE__, "The length of the list of CE clauses is not 1.");
306 
307  Clause *cp = expr[0];
308  BaseType *result;
309  if (cp->value(dds, &result))
310  return result;
311  else
312  return NULL;
313 }
314 
325 {
326  if (expr.empty())
327  return false;
328 
329  for (unsigned int i = 0; i < expr.size(); ++i) {
330  Clause *cp = expr[i];
331  if (!cp->value_clause())
332  return false;
333  }
334 
335  return true;
336 }
337 
353 DDS *
355 {
356  if (expr.empty())
357  throw InternalErr(__FILE__, __LINE__, "The constraint expression is empty.");
358 
359  DDS *fdds = new DDS(dds.get_factory(), "function_result_" + dds.get_dataset_name());
360  for (unsigned int i = 0; i < expr.size(); ++i) {
361  Clause *cp = expr[i];
362  BaseType *result;
363  if (cp->value(dds, &result)) {
364  // This is correct: The function must allocate the memory for the result
365  // variable. 11/30/12 jhrg
366  fdds->add_var_nocopy(result);
367  }
368  else {
369  delete fdds;
370  throw Error("A function was called but failed to return a value.");
371  }
372  }
373 
374  return fdds;
375 }
376 
391 DataDDS *
393 {
394  if (expr.empty())
395  throw InternalErr(__FILE__, __LINE__, "The constraint expression is empty.");
396 
397  DataDDS *fdds = new DataDDS(dds.get_factory(), "function_result_" + dds.get_dataset_name(), dds.get_version(),
398  dds.get_protocol());
399 
400  for (unsigned int i = 0; i < expr.size(); ++i) {
401  Clause *cp = expr[i];
402  BaseType *result;
403  if (cp->value(dds, &result)) {
404  fdds->add_var_nocopy(result);
405  }
406  else {
407  delete fdds;
408  throw Error("A function was called but failed to return a value.");
409  }
410  }
411 
412  return fdds;
413 }
414 
417 {
418  if (expr.empty())
419  return false;
420 
421  bool boolean = true;
422  for (Clause_iter i = expr.begin(); i != expr.end(); i++) {
423  boolean = boolean && (*i)->boolean_clause();
424  }
425 
426  return boolean;
427 }
428 
436 bool ConstraintEvaluator::eval_selection(DDS &dds, const string &)
437 {
438  if (expr.empty()) {
439  DBG(cerr << "No selection recorded" << endl);
440  return true;
441  }
442 
443  DBG(cerr << "Eval selection" << endl);
444 
445  // A CE is made up of zero or more clauses, each of which has a boolean
446  // value. The value of the CE is the logical AND of the clause
447  // values. See ConstraintEvaluator::clause::value(...) for information on logical ORs in
448  // CEs.
449  bool result = true;
450  for (Clause_iter i = expr.begin(); i != expr.end() && result; i++) {
451  // A selection expression *must* contain only boolean clauses!
452  if (!((*i)->boolean_clause()))
453  throw InternalErr(__FILE__, __LINE__, "A selection expression must contain only boolean clauses.");
454  result = result && (*i)->value(dds);
455  }
456 
457  return result;
458 }
459 
470 void ConstraintEvaluator::parse_constraint(const string &constraint, DDS &dds)
471 {
472  void *buffer = ce_expr_string(constraint.c_str());
473 
474  // Toggle this to debug the parser. A last resort...
475  ce_exprdebug = false;
476 
477  ce_expr_switch_to_buffer(buffer);
478 
479  ce_parser_arg arg(this, &dds);
480 
481  // For all errors, exprparse will throw Error.
482  try {
483  ce_exprparse(&arg);
484  ce_expr_delete_buffer(buffer);
485  }
486  catch (...) {
487  // Make sure to remove the buffer when there's an error
488  ce_expr_delete_buffer(buffer);
489  throw;
490  }
491 }
492 
493 } // namespace libdap