souffle  2.0.2-371-g6315b36
Visitor.h
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 /************************************************************************
10  *
11  * @file Visitor.h
12  *
13  * Provides some infrastructure for the implementation of operations
14  * on top of RAM structures.
15  *
16  ***********************************************************************/
17 
18 #pragma once
19 
22 #include "ram/AbstractOperator.h"
23 #include "ram/Aggregate.h"
24 #include "ram/AutoIncrement.h"
26 #include "ram/Break.h"
27 #include "ram/Call.h"
28 #include "ram/Choice.h"
29 #include "ram/Clear.h"
30 #include "ram/Condition.h"
31 #include "ram/Conjunction.h"
32 #include "ram/Constant.h"
33 #include "ram/Constraint.h"
34 #include "ram/DebugInfo.h"
35 #include "ram/EmptinessCheck.h"
36 #include "ram/ExistenceCheck.h"
37 #include "ram/Exit.h"
38 #include "ram/Expression.h"
39 #include "ram/Extend.h"
40 #include "ram/False.h"
41 #include "ram/Filter.h"
42 #include "ram/FloatConstant.h"
43 #include "ram/IO.h"
44 #include "ram/IndexAggregate.h"
45 #include "ram/IndexChoice.h"
46 #include "ram/IndexOperation.h"
47 #include "ram/IndexScan.h"
48 #include "ram/IntrinsicOperator.h"
49 #include "ram/ListStatement.h"
50 #include "ram/LogRelationTimer.h"
51 #include "ram/LogSize.h"
52 #include "ram/LogTimer.h"
53 #include "ram/Loop.h"
54 #include "ram/Negation.h"
56 #include "ram/NestedOperation.h"
57 #include "ram/Node.h"
58 #include "ram/Operation.h"
59 #include "ram/PackRecord.h"
60 #include "ram/Parallel.h"
61 #include "ram/ParallelAggregate.h"
62 #include "ram/ParallelChoice.h"
65 #include "ram/ParallelIndexScan.h"
66 #include "ram/ParallelScan.h"
67 #include "ram/Program.h"
68 #include "ram/Project.h"
70 #include "ram/Query.h"
71 #include "ram/Relation.h"
72 #include "ram/RelationOperation.h"
73 #include "ram/RelationSize.h"
74 #include "ram/RelationStatement.h"
75 #include "ram/Scan.h"
76 #include "ram/Sequence.h"
77 #include "ram/SignedConstant.h"
78 #include "ram/Statement.h"
79 #include "ram/SubroutineArgument.h"
80 #include "ram/SubroutineReturn.h"
81 #include "ram/Swap.h"
82 #include "ram/True.h"
83 #include "ram/TupleElement.h"
84 #include "ram/TupleOperation.h"
85 #include "ram/UndefValue.h"
86 #include "ram/UnpackRecord.h"
87 #include "ram/UnsignedConstant.h"
91 #include <cstddef>
92 #include <functional>
93 #include <type_traits>
94 #include <typeinfo>
95 #include <vector>
96 
97 namespace souffle::ram {
98 
99 /** A tag type required for the is_ram_visitor type trait to identify RamVisitors */
100 struct ram_visitor_tag {};
101 
102 /**
103  * The generic base type of all RamVisitors realizing the dispatching of
104  * visitor calls. Each visitor may define a return type R and a list of
105  * extra parameters to be passed along with the visited Nodes to the
106  * corresponding visitor function.
107  *
108  * @tparam R the result type produced by a visit call
109  * @tparam Params extra parameters to be passed to the visit call
110  */
111 template <typename R = void, typename... Params>
112 struct Visitor : public ram_visitor_tag {
113  /** A virtual destructor */
114  virtual ~Visitor() = default;
115 
116  /** The main entry for the user allowing visitors to be utilized as functions */
117  R operator()(const Node& node, Params... args) {
118  return visit(node, args...);
119  }
120 
121  /** The main entry for the user allowing visitors to be utilized as functions */
122  R operator()(const Node* node, Params... args) {
123  return visit(*node, args...);
124  }
125 
126  /**
127  * The main entry for a visit process conducting the dispatching of
128  * a visit to the various sub-types of Nodes. Sub-classes may override
129  * this implementation to conduct pre-visit operations.
130  *
131  * Note that the order of this list is important. Sub-classes must be listed
132  * before their super-classes; otherwise sub-classes cannot be visited.
133  *
134  * @param node the node to be visited
135  * @param args a list of extra parameters to be forwarded
136  */
137  virtual R visit(const Node& node, Params... args) {
138  // dispatch node processing based on dynamic type
139 
140 #define FORWARD(Kind) \
141  if (const auto* n = dynamic_cast<const Kind*>(&node)) return visit##Kind(*n, args...);
142 
143  // Relation
145 
146  // Expressions
151  FORWARD(Constant);
159 
160  // Conditions
161  FORWARD(True);
162  FORWARD(False);
167  FORWARD(Negation);
169 
170  // Operations
171  FORWARD(Filter);
172  FORWARD(Break);
173  FORWARD(Project);
178  FORWARD(Scan);
182  FORWARD(Choice);
189 
190  // Statements
191  FORWARD(IO);
192  FORWARD(Query);
193  FORWARD(Clear);
194  FORWARD(LogSize);
195 
196  FORWARD(Swap);
197  FORWARD(Extend);
198 
199  // Control-flow
200  FORWARD(Program);
201  FORWARD(Sequence);
202  FORWARD(Loop);
203  FORWARD(Parallel);
204  FORWARD(Exit);
205  FORWARD(LogTimer);
208  FORWARD(Call);
209 
210 #undef FORWARD
211 
212  // did not work ...
213  fatal("unsupported type: %s", typeid(node).name());
214  }
215 
216  virtual R visit(const Node* node, Params... args) {
217  return visit(*node, args...);
218  }
219 
220 protected:
221 #define LINK(Node, Parent) \
222  virtual R visit##Node(const Node& n, Params... args) { \
223  return visit##Parent(n, args...); \
224  }
225 
226  // -- statements --
228  LINK(Query, Statement);
229  LINK(Clear, RelationStatement);
230  LINK(LogSize, RelationStatement);
231 
232  LINK(RelationStatement, Statement);
233 
234  LINK(Swap, BinRelationStatement);
235  LINK(Extend, BinRelationStatement);
236  LINK(BinRelationStatement, Statement);
237 
238  LINK(Sequence, ListStatement);
239  LINK(Loop, Statement);
240  LINK(Parallel, ListStatement);
241  LINK(ListStatement, Statement);
242  LINK(Exit, Statement);
243  LINK(LogTimer, Statement);
244  LINK(LogRelationTimer, Statement);
245  LINK(DebugInfo, Statement);
246  LINK(Call, Statement);
247 
248  LINK(Statement, Node);
249 
250  // -- operations --
251  LINK(Project, Operation);
252  LINK(SubroutineReturn, Operation);
253  LINK(UnpackRecord, TupleOperation);
254  LINK(NestedIntrinsicOperator, TupleOperation)
255  LINK(Scan, RelationOperation);
256  LINK(ParallelScan, Scan);
257  LINK(IndexScan, IndexOperation);
258  LINK(ParallelIndexScan, IndexScan);
259  LINK(Choice, RelationOperation);
260  LINK(ParallelChoice, Choice);
261  LINK(IndexChoice, IndexOperation);
262  LINK(ParallelIndexChoice, IndexChoice);
263  LINK(RelationOperation, TupleOperation);
264  LINK(Aggregate, RelationOperation);
265  LINK(ParallelAggregate, Aggregate);
266  LINK(IndexAggregate, IndexOperation);
267  LINK(ParallelIndexAggregate, IndexAggregate);
268  LINK(IndexOperation, RelationOperation);
269  LINK(TupleOperation, NestedOperation);
270  LINK(Filter, AbstractConditional);
271  LINK(Break, AbstractConditional);
272  LINK(AbstractConditional, NestedOperation);
273  LINK(NestedOperation, Operation);
274 
275  LINK(Operation, Node);
276 
277  // -- conditions --
278  LINK(True, Condition);
279  LINK(False, Condition);
280  LINK(Conjunction, Condition);
281  LINK(Negation, Condition);
282  LINK(Constraint, Condition);
283  LINK(ProvenanceExistenceCheck, AbstractExistenceCheck);
284  LINK(ExistenceCheck, AbstractExistenceCheck);
285  LINK(EmptinessCheck, Condition);
286  LINK(AbstractExistenceCheck, Condition);
287 
288  LINK(Condition, Node);
289 
290  // -- values --
291  LINK(SignedConstant, Constant);
292  LINK(UnsignedConstant, Constant);
293  LINK(FloatConstant, Constant);
294  LINK(Constant, Expression);
295  LINK(UndefValue, Expression);
296  LINK(TupleElement, Expression);
297  LINK(IntrinsicOperator, AbstractOperator);
298  LINK(UserDefinedOperator, AbstractOperator);
299  LINK(AbstractOperator, Expression);
300  LINK(AutoIncrement, Expression);
301  LINK(PackRecord, Expression);
302  LINK(SubroutineArgument, Expression);
303  LINK(RelationSize, Expression);
304 
305  LINK(Expression, Node);
306 
307  // -- program --
308  LINK(Program, Node);
309 
310  // -- relation
311  LINK(Relation, Node);
312 
313 #undef LINK
314 
315  /** The base case for all visitors -- if no more specific overload was defined */
316  virtual R visitNode(const Node& /*node*/, Params... /*args*/) {
317  return R();
318  }
319 };
320 
321 /**
322  * A utility function visiting all nodes within the RAM fragment rooted by the given node
323  * recursively in a depth-first pre-order fashion applying the given visitor to each
324  * encountered node.
325  *
326  * @param root the root of the RAM fragment to be visited
327  * @param visitor the visitor to be applied on each node
328  * @param args a list of extra parameters to be forwarded to the visitor
329  */
330 template <typename R, typename... Ps, typename... Args>
331 void visitDepthFirstPreOrder(const Node& root, Visitor<R, Ps...>& visitor, Args&... args) {
332  visitor(root, args...);
333  for (const Node* cur : root.getChildNodes()) {
334  if (cur != nullptr) {
335  visitDepthFirstPreOrder(*cur, visitor, args...);
336  }
337  }
338 }
339 
340 /**
341  * A utility function visiting all nodes within the RAM fragments rooted by the given node
342  * recursively in a depth-first pre-order fashion applying the given visitor to each
343  * encountered node.
344  *
345  * @param root the root of the RAM fragments to be visited
346  * @param visitor the visitor to be applied on each node
347  * @param args a list of extra parameters to be forwarded to the visitor
348  */
349 template <typename R, typename... Ps, typename... Args>
350 void visitDepthFirst(const Node& root, Visitor<R, Ps...>& visitor, Args&... args) {
351  visitDepthFirstPreOrder(root, visitor, args...);
352 }
353 
354 namespace detail {
355 
356 /**
357  * A specialized visitor wrapping a lambda function -- an auxiliary type required
358  * for visitor convenience functions.
359  */
360 template <typename R, typename N>
361 struct LambdaVisitor : public Visitor<void> {
362  std::function<R(const N&)> lambda;
363  LambdaVisitor(std::function<R(const N&)> lambda) : lambda(std::move(lambda)) {}
364  void visit(const Node& node) override {
365  if (const auto* n = dynamic_cast<const N*>(&node)) {
366  lambda(*n);
367  }
368  }
369 };
370 
371 /**
372  * A factory function for creating LambdaVisitor instances.
373  */
374 template <typename R, typename N>
375 LambdaVisitor<R, N> makeLambdaVisitor(const std::function<R(const N&)>& fun) {
376  return LambdaVisitor<R, N>(fun);
377 }
378 
379 /**
380  * A type trait determining whether a given type is a visitor or not.
381  */
382 template <typename T>
383 struct is_ram_visitor {
384  static constexpr size_t value = std::is_base_of<ram_visitor_tag, T>::value;
385 };
386 
387 template <typename T>
388 struct is_ram_visitor<const T> : public is_ram_visitor<T> {};
389 
390 template <typename T>
391 struct is_ram_visitor<T&> : public is_ram_visitor<T> {};
392 } // namespace detail
393 
394 /**
395  * A utility function visiting all nodes within the RAM fragment rooted by the given node
396  * recursively in a depth-first pre-order fashion applying the given function to each
397  * encountered node.
398  *
399  * @param root the root of the RAM fragment to be visited
400  * @param fun the function to be applied
401  * @param args a list of extra parameters to be forwarded to the visitor
402  */
403 template <typename R, typename N>
404 void visitDepthFirst(const Node& root, const std::function<R(const N&)>& fun) {
405  auto visitor = detail::makeLambdaVisitor(fun);
406  visitDepthFirst<void>(root, visitor);
407 }
408 
409 /**
410  * A utility function visiting all nodes within the RAM fragment rooted by the given node
411  * recursively in a depth-first pre-order fashion applying the given function to each
412  * encountered node.
413  *
414  * @param root the root of the RAM fragment to be visited
415  * @param fun the function to be applied
416  * @param args a list of extra parameters to be forwarded to the visitor
417  */
418 template <typename Lambda, typename R = typename lambda_traits<Lambda>::result_type,
419  typename N = typename lambda_traits<Lambda>::arg0_type>
420 typename std::enable_if<!detail::is_ram_visitor<Lambda>::value, void>::type visitDepthFirst(
421  const Node& root, const Lambda& fun) {
422  visitDepthFirst(root, std::function<R(const N&)>(fun));
423 }
424 
425 } // namespace souffle::ram
Aggregate.h
souffle::ram::Break
Breaks out of the loop if a condition holds.
Definition: Break.h:49
UserDefinedOperator.h
Constant.h
souffle::ram::AutoIncrement
Increment a counter and return its value.
Definition: AutoIncrement.h:36
AbstractExistenceCheck.h
souffle::ram::Visitor::visit
virtual R visit(const Node &node, Params... args)
The main entry for a visit process conducting the dispatching of a visit to the various sub-types of ...
Definition: Visitor.h:144
RelationStatement.h
souffle::ram::UserDefinedOperator
Operator that represents an extrinsic (user-defined) functor.
Definition: UserDefinedOperator.h:43
souffle::ram::Program
RAM program relation declaration and functions.
Definition: Program.h:58
PackRecord.h
souffle::ram::ParallelIndexScan
Search for tuples of a relation matching a criteria.
Definition: ParallelIndexScan.h:58
NestedOperation.h
UnsignedConstant.h
Constraint.h
Call.h
souffle::ram::UnpackRecord
Record lookup.
Definition: UnpackRecord.h:51
souffle::ram::Swap
Swap operation with respect to two relations.
Definition: Swap.h:43
souffle::ram::Query
A relational algebra query.
Definition: Query.h:50
Scan.h
Exit.h
Negation.h
souffle::ram::PackRecord
Packs a record's arguments into a reference.
Definition: PackRecord.h:42
Project.h
souffle::ram::detail::LambdaVisitor::visit
void visit(const Node &node) override
Definition: Visitor.h:371
Clear.h
LogTimer.h
souffle::ram::Loop
Execute statement until statement terminates loop via an exit statement.
Definition: Loop.h:48
souffle::ram::Exit
Exit statement for a loop.
Definition: Exit.h:48
souffle::lambda_traits
A type trait enabling the deduction of type properties of lambdas.
Definition: FunctionalUtil.h:94
souffle::ram::ParallelIndexChoice
Use an index to find a tuple in a relation such that a given condition holds in parallel.
Definition: ParallelIndexChoice.h:59
souffle::ram::Parallel
Parallel block of statements.
Definition: Parallel.h:49
souffle::ram::Extend
Extend equivalence relation.
Definition: Extend.h:41
souffle::ram::Call
Call a subroutine.
Definition: Call.h:42
False.h
ParallelChoice.h
ListStatement.h
LogRelationTimer.h
MiscUtil.h
souffle::ram::SignedConstant
Represents a signed constant.
Definition: SignedConstant.h:40
souffle::ram::detail::is_ram_visitor
A type trait determining whether a given type is a visitor or not.
Definition: Visitor.h:390
Filter.h
souffle::ram::LogTimer
Execution time logger for a statement.
Definition: LogTimer.h:55
SubroutineArgument.h
DebugInfo.h
EmptinessCheck.h
Swap.h
souffle::ram::ExistenceCheck
Existence check for a tuple(-pattern) in a relation.
Definition: ExistenceCheck.h:49
True.h
RelationOperation.h
souffle::ram::TupleElement
Access element from the current tuple in a tuple environment.
Definition: TupleElement.h:42
souffle::ram::FloatConstant
Represents a float constant.
Definition: FloatConstant.h:40
TupleOperation.h
souffle::ram::Visitor::~Visitor
virtual ~Visitor()=default
A virtual destructor.
ParallelIndexScan.h
n
var n
Definition: htmlJsChartistMin.h:15
souffle::ram::detail::LambdaVisitor
A specialized visitor wrapping a lambda function – an auxiliary type required for visitor convenience...
Definition: Visitor.h:368
souffle::ram::Node::getChildNodes
virtual std::vector< const Node * > getChildNodes() const
Obtain list of all embedded child nodes.
Definition: Node.h:93
souffle::ram::False
Definition: False.h:38
Program.h
souffle::ram
Definition: AstToRamTranslator.h:54
IndexAggregate.h
souffle::ram::Filter
Checks whether a given condition holds.
Definition: Filter.h:49
souffle::ram::Conjunction
A conjunction of conditions.
Definition: Conjunction.h:54
souffle::ram::ProvenanceExistenceCheck
Provenance Existence check for a relation.
Definition: ProvenanceExistenceCheck.h:42
souffle::ram::UnsignedConstant
Represents a unsigned constant.
Definition: UnsignedConstant.h:40
souffle::ram::Visitor::visitNode
virtual R visitNode(const Node &, Params...)
The base case for all visitors – if no more specific overload was defined.
Definition: Visitor.h:323
souffle::ram::Node
Node is a superclass for all RAM IR classes.
Definition: Node.h:42
ProvenanceExistenceCheck.h
IndexScan.h
IndexChoice.h
souffle::ram::Project
Project a result into the target relation.
Definition: Project.h:50
souffle::ram::ram_visitor_tag
A tag type required for the is_ram_visitor type trait to identify RamVisitors.
Definition: Visitor.h:107
souffle::ram::detail::is_ram_visitor::value
static constexpr size_t value
Definition: Visitor.h:391
Choice.h
souffle::ram::Clear
Delete tuples of a relation.
Definition: Clear.h:50
souffle::ram::ParallelIndexAggregate
Aggregate over values of a relation using an index in parallel.
Definition: ParallelIndexAggregate.h:52
souffle::ram::Relation
An abstract class for performing indexed operations.
Definition: Relation.h:40
Relation.h
NestedIntrinsicOperator.h
souffle::ram::Aggregate
Aggregation function applied on some relation.
Definition: Aggregate.h:53
ParallelIndexChoice.h
Condition.h
souffle::ram::ParallelAggregate
Parallel Aggregation function applied on some relation.
Definition: ParallelAggregate.h:53
souffle::ram::Visitor::operator()
R operator()(const Node &node, Params... args)
The main entry for the user allowing visitors to be utilized as functions.
Definition: Visitor.h:124
ParallelIndexAggregate.h
souffle::ram::IndexChoice
Use an index to find a tuple in a relation such that a given condition holds.
Definition: IndexChoice.h:58
souffle::ram::IndexAggregate
Indexed aggregation on a relation. The index allows us to iterate over a restricted range.
Definition: IndexAggregate.h:51
souffle::ram::Visitor
The generic base type of all RamVisitors realizing the dispatching of visitor calls.
Definition: Visitor.h:119
ExistenceCheck.h
UnpackRecord.h
AutoIncrement.h
souffle::ram::ParallelScan
Iterate all tuples of a relation in parallel.
Definition: ParallelScan.h:52
souffle::ram::detail::LambdaVisitor::lambda
std::function< R(const N &)> lambda
Definition: Visitor.h:369
souffle::ram::Constant
Represents a Ram Constant.
Definition: Constant.h:36
souffle::ram::EmptinessCheck
Emptiness check for a relation.
Definition: EmptinessCheck.h:53
souffle::ram::IO
I/O statement for a relation.
Definition: IO.h:42
IO.h
RelationSize.h
ParallelScan.h
FORWARD
#define FORWARD(Kind)
Break.h
ParallelAggregate.h
souffle::ram::DebugInfo
Debug statement.
Definition: DebugInfo.h:47
souffle::ram::Choice
Find a tuple in a relation such that a given condition holds.
Definition: Choice.h:59
souffle::ram::Scan
Iterate all tuples of a relation.
Definition: Scan.h:47
souffle::ram::IndexScan
Search for tuples of a relation matching a criteria.
Definition: IndexScan.h:52
souffle::ram::IntrinsicOperator
Operator that represents an intrinsic (built-in) functor.
Definition: IntrinsicOperator.h:42
BinRelationStatement.h
IndexOperation.h
souffle::ram::Constraint
Evaluates a binary constraint with respect to two Expressions.
Definition: Constraint.h:55
TupleElement.h
souffle::ram::Negation
Negates a given condition.
Definition: Negation.h:49
Node.h
Operation.h
Query.h
Sequence.h
Statement.h
souffle::fatal
void fatal(const char *format, const Args &... args)
Definition: MiscUtil.h:198
SignedConstant.h
souffle::ram::UndefValue
An undefined expression.
Definition: UndefValue.h:36
AbstractConditional.h
souffle::ram::NestedIntrinsicOperator
Effectively identical to IntrinsicOperator, except it can produce multiple results.
Definition: NestedIntrinsicOperator.h:62
SubroutineReturn.h
souffle::ram::detail::makeLambdaVisitor
LambdaVisitor< R, N > makeLambdaVisitor(const std::function< R(const N &)> &fun)
A factory function for creating LambdaVisitor instances.
Definition: Visitor.h:382
Expression.h
UndefValue.h
Loop.h
souffle::ram::RelationStatement
RAM Statements with a single relation.
Definition: RelationStatement.h:37
souffle::ram::True
False value condition.
Definition: True.h:38
FunctionalUtil.h
souffle::ram::SubroutineArgument
Access argument of a subroutine.
Definition: SubroutineArgument.h:40
souffle::ram::SubroutineReturn
A statement for returning from a ram subroutine.
Definition: SubroutineReturn.h:46
souffle::ram::RelationSize
Returns the numbers of tuples in a relation.
Definition: RelationSize.h:49
souffle::ram::LogSize
Log relation size and a logging message.
Definition: LogSize.h:38
souffle::ram::visitDepthFirst
void visitDepthFirst(const Node &root, Visitor< R, Ps... > &visitor, Args &... args)
A utility function visiting all nodes within the RAM fragments rooted by the given node recursively i...
Definition: Visitor.h:357
souffle::ram::visitDepthFirstPreOrder
void visitDepthFirstPreOrder(const Node &root, Visitor< R, Ps... > &visitor, Args &... args)
A utility function visiting all nodes within the RAM fragment rooted by the given node recursively in...
Definition: Visitor.h:338
souffle::ram::Visitor::LINK
LINK(IO, RelationStatement)
souffle::ram::Sequence
Sequence of RAM statements.
Definition: Sequence.h:37
LogSize.h
IntrinsicOperator.h
souffle::ram::LogRelationTimer
Execution time logger for a statement.
Definition: LogRelationTimer.h:55
FloatConstant.h
std::type
ElementType type
Definition: span.h:640
souffle::ram::ParallelChoice
Find a tuple in a relation such that a given condition holds in parallel.
Definition: ParallelChoice.h:51
souffle::ram::detail::LambdaVisitor::LambdaVisitor
LambdaVisitor(std::function< R(const N &)> lambda)
Definition: Visitor.h:370
AbstractOperator.h
Parallel.h
Conjunction.h
Extend.h