libdap Updated for version 3.20.5
libdap4 is an implementation of OPeNDAP's DAP protocol.
ConstraintEvaluator.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) 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#include "Clause.h"
32#include "DataDDS.h"
33
34#include "ce_parser.h"
35#include "debug.h"
36#include "parser.h"
37#include "expr.h"
38
39struct yy_buffer_state;
40
41int ce_exprparse(libdap::ce_parser_arg *arg);
42
43// Glue routines declared in expr.lex
44void ce_expr_switch_to_buffer(void *new_buffer);
45void ce_expr_delete_buffer(void * buffer);
46void *ce_expr_string(const char *yy_str);
47
48extern int ce_exprdebug;
49
50namespace libdap {
51
52ConstraintEvaluator::ConstraintEvaluator()
53{
54 // Functions are now held in BES modules. jhrg 1/30/13
55
56 // modules load functions to this list; this class searches the list
57 // instead of having it's own copy. This is very similar to the BES'
58 // various List classes, but this one is part of libdap and not the
59 // BES. The List class is a singleton, so each function module can
60 // register it's functions to the list object.
61 d_functions_list = ServerFunctionsList::TheList();
62}
63
64ConstraintEvaluator::~ConstraintEvaluator()
65{
66 // delete all the constants created by the parser for CE evaluation
67 for (Constants_iter j = constants.begin(); j != constants.end(); j++) {
68 BaseType *btp = *j;
69 delete btp;
70 btp = 0;
71 }
72
73 for (Clause_iter k = expr.begin(); k != expr.end(); k++) {
74 Clause *cp = *k;
75 delete cp;
76 cp = 0;
77 }
78}
79
81ConstraintEvaluator::Clause_iter ConstraintEvaluator::clause_begin()
82{
83 return expr.begin();
84}
85
88ConstraintEvaluator::Clause_iter ConstraintEvaluator::clause_end()
89{
90 return expr.end();
91}
92
95bool ConstraintEvaluator::clause_value(Clause_iter &iter, DDS &dds/*, const string &***/)
96{
97 if (expr.empty())
98 throw InternalErr(__FILE__, __LINE__, "There are no CE clauses for *this* DDS object.");
99
100 return (*iter)->value(dds);
101}
102
115void ConstraintEvaluator::append_clause(int op, rvalue *arg1, rvalue_list *arg2)
116{
117 Clause *clause = new Clause(op, arg1, arg2);
118
119 expr.push_back(clause);
120}
121
131void ConstraintEvaluator::append_clause(bool_func func, rvalue_list *args)
132{
133 Clause *clause = new Clause(func, args);
134
135 expr.push_back(clause);
136}
137
147void ConstraintEvaluator::append_clause(btp_func func, rvalue_list *args)
148{
149 Clause *clause = new Clause(func, args);
150
151 expr.push_back(clause);
152}
153
162{
163 constants.push_back(btp);
164}
165
167bool ConstraintEvaluator::find_function(const string &name, bool_func *f) const
168{
169 return d_functions_list->find_function(name, f);
170}
171
173bool ConstraintEvaluator::find_function(const string &name, btp_func *f) const
174{
175 return d_functions_list->find_function(name, f);
176}
177
179bool ConstraintEvaluator::find_function(const string &name, proj_func *f) const
180{
181 return d_functions_list->find_function(name, f);
182}
184
194{
195 if (expr.empty())
196 return false;
197
198 Clause *cp = expr[0];
199 return cp->value_clause();
200}
201
205BaseType *
207{
208 if (expr.size() != 1)
209 throw InternalErr(__FILE__, __LINE__, "The length of the list of CE clauses is not 1.");
210
211 Clause *cp = expr[0];
212 BaseType *result;
213 if (cp->value(dds, &result))
214 return result;
215 else
216 return NULL;
217}
218
229{
230 if (expr.empty())
231 return false;
232
233 for (unsigned int i = 0; i < expr.size(); ++i) {
234 Clause *cp = expr[i];
235 if (!cp->value_clause())
236 return false;
237 }
238
239 return true;
240}
241
257DDS *
259{
260 if (expr.empty())
261 throw InternalErr(__FILE__, __LINE__, "The constraint expression is empty.");
262
263 DDS *fdds = new DDS(dds.get_factory(), "function_result_" + dds.get_dataset_name());
264 for (unsigned int i = 0; i < expr.size(); ++i) {
265 Clause *cp = expr[i];
266 BaseType *result;
267 if (cp->value(dds, &result)) {
268 // This is correct: The function must allocate the memory for the result
269 // variable. 11/30/12 jhrg
270 fdds->add_var_nocopy(result);
271 }
272 else {
273 delete fdds;
274 throw Error(internal_error, "A function was called but failed to return a value.");
275 }
276 }
277
278 return fdds;
279}
280
286DataDDS *
288{
289 if (expr.empty())
290 throw InternalErr(__FILE__, __LINE__, "The constraint expression is empty.");
291
292 DataDDS *fdds = new DataDDS(dds.get_factory(), "function_result_" + dds.get_dataset_name(), dds.get_version(),
293 dds.get_protocol());
294
295 for (unsigned int i = 0; i < expr.size(); ++i) {
296 Clause *cp = expr[i];
297 BaseType *result;
298 if (cp->value(dds, &result)) {
299 fdds->add_var_nocopy(result);
300 }
301 else {
302 delete fdds;
303 throw Error(internal_error, "A function was called but failed to return a value.");
304 }
305 }
306
307 return fdds;
308}
309
312{
313 if (expr.empty())
314 return false;
315
316 bool boolean = true;
317 for (Clause_iter i = expr.begin(); i != expr.end(); i++) {
318 boolean = boolean && (*i)->boolean_clause();
319 }
320
321 return boolean;
322}
323
331bool ConstraintEvaluator::eval_selection(DDS &dds, const string &)
332{
333 if (expr.empty()) {
334 DBG(cerr << "No selection recorded" << endl);
335 return true;
336 }
337
338 DBG(cerr << "Eval selection" << endl);
339
340 // A CE is made up of zero or more clauses, each of which has a boolean
341 // value. The value of the CE is the logical AND of the clause
342 // values. See ConstraintEvaluator::clause::value(...) for information on logical ORs in
343 // CEs.
344 bool result = true;
345 for (Clause_iter i = expr.begin(); i != expr.end() && result; i++) {
346 // A selection expression *must* contain only boolean clauses!
347 if (!((*i)->boolean_clause()))
348 throw InternalErr(__FILE__, __LINE__, "A selection expression must contain only boolean clauses.");
349 result = result && (*i)->value(dds);
350 }
351
352 return result;
353}
354
365void ConstraintEvaluator::parse_constraint(const string &constraint, DDS &dds)
366{
367 void *buffer = ce_expr_string(constraint.c_str());
368
369 // Toggle this to debug the parser. A last resort...
370 ce_exprdebug = false;
371
372 ce_expr_switch_to_buffer(buffer);
373
374 ce_parser_arg arg(this, &dds);
375
376 // For all errors, exprparse will throw Error.
377 try {
378 ce_exprparse(&arg);
379 ce_expr_delete_buffer(buffer);
380 }
381 catch (...) {
382 // Make sure to remove the buffer when there's an error
383 ce_expr_delete_buffer(buffer);
384 throw;
385 }
386}
387
388} // namespace libdap
The basic data type for the DODS DAP types.
Definition BaseType.h:118
bool boolean_expression()
Does the current constraint expression return a boolean value?
bool eval_selection(DDS &dds, const std::string &dataset)
Evaluate a boolean-valued constraint expression. This is main method for the evaluator and is called ...
bool find_function(const std::string &name, bool_func *f) const
Find a Boolean function with a given name in the function list.
bool clause_value(Clause_iter &i, DDS &dds)
void parse_constraint(const std::string &constraint, DDS &dds)
Parse the constraint expression given the current DDS.
void append_clause(int op, rvalue *arg1, rvalue_list *arg2)
Add a clause to a constraint expression.
BaseType * eval_function(DDS &dds, const std::string &dataset)
Evaluate a function-valued constraint expression.
bool function_clauses()
Does the current constraint expression contain function clauses.
DDS * eval_function_clauses(DDS &dds)
Evaluate a function-valued constraint expression that contains several function calls.
bool functional_expression()
Does the current constraint expression return a BaseType pointer? This method does not evaluate the c...
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition DDS.cc:613
string get_dataset_name() const
Definition DDS.cc:356
BaseTypeFactory * get_factory() const
Definition DDS.h:242
Holds a DAP2 DDS.
Definition DataDDS.h:78
string get_version() const
Get the server version string, unparsed.
Definition DataDDS.h:109
A class for error processing.
Definition Error.h:93
A class for software fault reporting.
Definition InternalErr.h:65
virtual bool find_function(const std::string &name, bool_func *f) const
Find a boolean function with a given name in the function list.
top level DAP object to house generic methods
Holds a fragment of a constraint expression.
Definition Clause.h:91
bool value_clause()
Return true if the clause returns a value in a BaseType pointer.
Definition Clause.cc:139
bool value(DDS &dds)
Evaluate a clause which returns a boolean value This method must only be evaluated for clauses with r...
Definition Clause.cc:157