souffle  2.0.2-371-g6315b36
Generator.cpp
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2020, The Souffle Developers. 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 Generator.cpp
12  *
13  * Define the Interpreter Generator class.
14  ***********************************************************************/
15 
16 #include "interpreter/Generator.h"
17 #include "interpreter/Engine.h"
18 
19 namespace souffle::interpreter {
20 
21 using NodePtr = Own<Node>;
22 using NodePtrVec = std::vector<NodePtr>;
23 using RelationHandle = Own<RelationWrapper>;
24 
25 NodeGenerator::NodeGenerator(Engine& engine) : engine(engine) {
26  visitDepthFirst(engine.tUnit.getProgram(), [&](const ram::Relation& relation) {
27  assert(relationMap.find(relation.getName()) == relationMap.end() && "double-naming of relations");
28  relationMap[relation.getName()] = &relation;
29  });
30 }
31 
32 NodePtr NodeGenerator::generateTree(const ram::Node& root) {
33  // Encode all relation, indexPos and viewId.
34  visitDepthFirst(root, [&](const ram::Node& node) {
35  if (isA<ram::Query>(&node)) {
36  newQueryBlock();
37  }
38  if (const auto* indexSearch = dynamic_cast<const ram::IndexOperation*>(&node)) {
39  encodeIndexPos(*indexSearch);
40  encodeView(indexSearch);
41  } else if (const auto* exists = dynamic_cast<const ram::ExistenceCheck*>(&node)) {
42  encodeIndexPos(*exists);
43  encodeView(exists);
44  } else if (const auto* provExists = dynamic_cast<const ram::ProvenanceExistenceCheck*>(&node)) {
45  encodeIndexPos(*provExists);
46  encodeView(provExists);
47  }
48  });
49  // Parse program
50  return visit(root);
51 }
52 
53 NodePtr NodeGenerator::visitConstant(const ram::Constant& num) {
54  return mk<Constant>(I_Constant, &num);
55 }
56 
57 NodePtr NodeGenerator::visitTupleElement(const ram::TupleElement& access) {
58  auto tupleId = access.getTupleId();
59  auto elementId = access.getElement();
60  auto newElementId = orderingContext.mapOrder(tupleId, elementId);
61  return mk<TupleElement>(I_TupleElement, &access, tupleId, newElementId);
62 }
63 
64 NodePtr NodeGenerator::visitAutoIncrement(const ram::AutoIncrement& inc) {
65  return mk<AutoIncrement>(I_AutoIncrement, &inc);
66 }
67 
68 NodePtr NodeGenerator::visitIntrinsicOperator(const ram::IntrinsicOperator& op) {
69  NodePtrVec children;
70  for (const auto& arg : op.getArguments()) {
71  children.push_back(visit(arg));
72  }
73  return mk<IntrinsicOperator>(I_IntrinsicOperator, &op, std::move(children));
74 }
75 
76 NodePtr NodeGenerator::visitUserDefinedOperator(const ram::UserDefinedOperator& op) {
77  NodePtrVec children;
78  for (const auto& arg : op.getArguments()) {
79  children.push_back(visit(arg));
80  }
81  return mk<UserDefinedOperator>(I_UserDefinedOperator, &op, std::move(children));
82 }
83 
84 NodePtr NodeGenerator::visitNestedIntrinsicOperator(const ram::NestedIntrinsicOperator& op) {
85  auto arity = op.getArguments().size();
86  orderingContext.addNewTuple(op.getTupleId(), arity);
87  NodePtrVec children;
88  for (auto&& arg : op.getArguments()) {
89  children.push_back(visit(arg));
90  }
91  children.push_back(visitTupleOperation(op));
92  return mk<NestedIntrinsicOperator>(I_NestedIntrinsicOperator, &op, std::move(children));
93 }
94 
95 NodePtr NodeGenerator::visitPackRecord(const ram::PackRecord& pr) {
96  NodePtrVec children;
97  for (const auto& arg : pr.getArguments()) {
98  children.push_back(visit(arg));
99  }
100  return mk<PackRecord>(I_PackRecord, &pr, std::move(children));
101 }
102 
103 NodePtr NodeGenerator::visitSubroutineArgument(const ram::SubroutineArgument& arg) {
104  return mk<SubroutineArgument>(I_SubroutineArgument, &arg);
105 }
106 
107 // -- connectors operators --
108 NodePtr NodeGenerator::visitTrue(const ram::True& ltrue) {
109  return mk<True>(I_True, &ltrue);
110 }
111 
112 NodePtr NodeGenerator::visitFalse(const ram::False& lfalse) {
113  return mk<False>(I_False, &lfalse);
114 }
115 
116 NodePtr NodeGenerator::visitConjunction(const ram::Conjunction& conj) {
117  return mk<Conjunction>(I_Conjunction, &conj, visit(conj.getLHS()), visit(conj.getRHS()));
118 }
119 
120 NodePtr NodeGenerator::visitNegation(const ram::Negation& neg) {
121  return mk<Negation>(I_Negation, &neg, visit(neg.getOperand()));
122 }
123 
124 NodePtr NodeGenerator::visitEmptinessCheck(const ram::EmptinessCheck& emptiness) {
125  size_t relId = encodeRelation(emptiness.getRelation());
126  auto rel = getRelationHandle(relId);
127  NodeType type = constructNodeType("EmptinessCheck", lookup(emptiness.getRelation()));
128  return mk<EmptinessCheck>(type, &emptiness, rel);
129 }
130 
131 NodePtr NodeGenerator::visitRelationSize(const ram::RelationSize& size) {
132  size_t relId = encodeRelation(size.getRelation());
133  auto rel = getRelationHandle(relId);
134  NodeType type = constructNodeType("RelationSize", lookup(size.getRelation()));
135  return mk<RelationSize>(type, &size, rel);
136 }
137 
138 NodePtr NodeGenerator::visitExistenceCheck(const ram::ExistenceCheck& exists) {
139  SuperInstruction superOp = getExistenceSuperInstInfo(exists);
140  // Check if the search signature is a total signature
141  bool isTotal = true;
142  for (const auto& cur : exists.getValues()) {
143  if (isUndefValue(cur)) {
144  isTotal = false;
145  }
146  }
147  auto ramRelation = lookup(exists.getRelation());
148  NodeType type = constructNodeType("ExistenceCheck", ramRelation);
149  return mk<ExistenceCheck>(type, &exists, isTotal, encodeView(&exists), std::move(superOp),
150  ramRelation.isTemp(), ramRelation.getName());
151 }
152 
153 NodePtr NodeGenerator::visitProvenanceExistenceCheck(const ram::ProvenanceExistenceCheck& provExists) {
154  SuperInstruction superOp = getExistenceSuperInstInfo(provExists);
155  NodeType type = constructNodeType("ProvenanceExistenceCheck", lookup(provExists.getRelation()));
156  return mk<ProvenanceExistenceCheck>(type, &provExists, visit(provExists.getChildNodes().back()),
157  encodeView(&provExists), std::move(superOp));
158 }
159 
160 NodePtr NodeGenerator::visitConstraint(const ram::Constraint& relOp) {
161  return mk<Constraint>(I_Constraint, &relOp, visit(relOp.getLHS()), visit(relOp.getRHS()));
162 }
163 
164 NodePtr NodeGenerator::visitNestedOperation(const ram::NestedOperation& nested) {
165  return visit(nested.getOperation());
166 }
167 
168 NodePtr NodeGenerator::visitTupleOperation(const ram::TupleOperation& search) {
169  if (engine.profileEnabled) {
170  return mk<TupleOperation>(I_TupleOperation, &search, visit(search.getOperation()));
171  }
172  return visit(search.getOperation());
173 }
174 
175 NodePtr NodeGenerator::visitScan(const ram::Scan& scan) {
176  orderingContext.addTupleWithDefaultOrder(scan.getTupleId(), scan);
177  size_t relId = encodeRelation(scan.getRelation());
178  auto rel = getRelationHandle(relId);
179  NodeType type = constructNodeType("Scan", lookup(scan.getRelation()));
180  return mk<Scan>(type, &scan, rel, visitTupleOperation(scan));
181 }
182 
183 NodePtr NodeGenerator::visitParallelScan(const ram::ParallelScan& pScan) {
184  orderingContext.addTupleWithDefaultOrder(pScan.getTupleId(), pScan);
185  size_t relId = encodeRelation(pScan.getRelation());
186  auto rel = getRelationHandle(relId);
187  NodeType type = constructNodeType("ParallelScan", lookup(pScan.getRelation()));
188  auto res = mk<ParallelScan>(type, &pScan, rel, visitTupleOperation(pScan));
189  res->setViewContext(parentQueryViewContext);
190  return res;
191 }
192 
193 NodePtr NodeGenerator::visitIndexScan(const ram::IndexScan& iScan) {
194  orderingContext.addTupleWithIndexOrder(iScan.getTupleId(), iScan);
195  SuperInstruction indexOperation = getIndexSuperInstInfo(iScan);
196  NodeType type = constructNodeType("IndexScan", lookup(iScan.getRelation()));
197  return mk<IndexScan>(
198  type, &iScan, nullptr, visitTupleOperation(iScan), encodeView(&iScan), std::move(indexOperation));
199 }
200 
201 NodePtr NodeGenerator::visitParallelIndexScan(const ram::ParallelIndexScan& piscan) {
202  orderingContext.addTupleWithIndexOrder(piscan.getTupleId(), piscan);
203  SuperInstruction indexOperation = getIndexSuperInstInfo(piscan);
204  size_t relId = encodeRelation(piscan.getRelation());
205  auto rel = getRelationHandle(relId);
206  NodeType type = constructNodeType("ParallelIndexScan", lookup(piscan.getRelation()));
207  auto res = mk<ParallelIndexScan>(type, &piscan, rel, visitTupleOperation(piscan), encodeIndexPos(piscan),
208  std::move(indexOperation));
209  res->setViewContext(parentQueryViewContext);
210  return res;
211 }
212 
213 NodePtr NodeGenerator::visitChoice(const ram::Choice& choice) {
214  orderingContext.addTupleWithDefaultOrder(choice.getTupleId(), choice);
215  size_t relId = encodeRelation(choice.getRelation());
216  auto rel = getRelationHandle(relId);
217  NodeType type = constructNodeType("Choice", lookup(choice.getRelation()));
218  return mk<Choice>(type, &choice, rel, visit(choice.getCondition()), visitTupleOperation(choice));
219 }
220 
221 NodePtr NodeGenerator::visitParallelChoice(const ram::ParallelChoice& pChoice) {
222  orderingContext.addTupleWithDefaultOrder(pChoice.getTupleId(), pChoice);
223  size_t relId = encodeRelation(pChoice.getRelation());
224  auto rel = getRelationHandle(relId);
225  NodeType type = constructNodeType("ParallelChoice", lookup(pChoice.getRelation()));
226  auto res = mk<ParallelChoice>(
227  type, &pChoice, rel, visit(pChoice.getCondition()), visitTupleOperation(pChoice));
228  res->setViewContext(parentQueryViewContext);
229  return res;
230 }
231 
232 NodePtr NodeGenerator::visitIndexChoice(const ram::IndexChoice& iChoice) {
233  orderingContext.addTupleWithIndexOrder(iChoice.getTupleId(), iChoice);
234  SuperInstruction indexOperation = getIndexSuperInstInfo(iChoice);
235  NodeType type = constructNodeType("IndexChoice", lookup(iChoice.getRelation()));
236  return mk<IndexChoice>(type, &iChoice, nullptr, visit(iChoice.getCondition()),
237  visitTupleOperation(iChoice), encodeView(&iChoice), std::move(indexOperation));
238 }
239 
240 NodePtr NodeGenerator::visitParallelIndexChoice(const ram::ParallelIndexChoice& piChoice) {
241  orderingContext.addTupleWithIndexOrder(piChoice.getTupleId(), piChoice);
242  SuperInstruction indexOperation = getIndexSuperInstInfo(piChoice);
243  size_t relId = encodeRelation(piChoice.getRelation());
244  auto rel = getRelationHandle(relId);
245  NodeType type = constructNodeType("ParallelIndexChoice", lookup(piChoice.getRelation()));
246  auto res = mk<ParallelIndexChoice>(type, &piChoice, rel, visit(piChoice.getCondition()),
247  visit(piChoice.getOperation()), encodeIndexPos(piChoice), std::move(indexOperation));
248  res->setViewContext(parentQueryViewContext);
249  return res;
250 }
251 
252 NodePtr NodeGenerator::visitUnpackRecord(const ram::UnpackRecord& unpack) { // get reference
253  orderingContext.addNewTuple(unpack.getTupleId(), unpack.getArity());
254  return mk<UnpackRecord>(
255  I_UnpackRecord, &unpack, visit(unpack.getExpression()), visitTupleOperation(unpack));
256 }
257 
258 NodePtr NodeGenerator::visitAggregate(const ram::Aggregate& aggregate) {
259  // Notice: Aggregate is sensitive to the visiting order of the subexprs in order to make
260  // orderCtxt consistent. The order of visiting should be the same as the order of execution during
261  // runtime.
262  orderingContext.addTupleWithDefaultOrder(aggregate.getTupleId(), aggregate);
263  NodePtr expr = visit(aggregate.getExpression());
264  NodePtr cond = visit(aggregate.getCondition());
265  orderingContext.addNewTuple(aggregate.getTupleId(), 1);
266  NodePtr nested = visitTupleOperation(aggregate);
267  size_t relId = encodeRelation(aggregate.getRelation());
268  auto rel = getRelationHandle(relId);
269  NodeType type = constructNodeType("Aggregate", lookup(aggregate.getRelation()));
270  return mk<Aggregate>(type, &aggregate, rel, std::move(expr), std::move(cond), std::move(nested));
271 }
272 
273 NodePtr NodeGenerator::visitParallelAggregate(const ram::ParallelAggregate& pAggregate) {
274  orderingContext.addTupleWithDefaultOrder(pAggregate.getTupleId(), pAggregate);
275  NodePtr expr = visit(pAggregate.getExpression());
276  NodePtr cond = visit(pAggregate.getCondition());
277  orderingContext.addNewTuple(pAggregate.getTupleId(), 1);
278  NodePtr nested = visitTupleOperation(pAggregate);
279  size_t relId = encodeRelation(pAggregate.getRelation());
280  auto rel = getRelationHandle(relId);
281  NodeType type = constructNodeType("ParallelAggregate", lookup(pAggregate.getRelation()));
282  auto res = mk<ParallelAggregate>(
283  type, &pAggregate, rel, std::move(expr), std::move(cond), std::move(nested));
284  res->setViewContext(parentQueryViewContext);
285 
286  return res;
287 }
288 
289 NodePtr NodeGenerator::visitIndexAggregate(const ram::IndexAggregate& iAggregate) {
290  orderingContext.addTupleWithIndexOrder(iAggregate.getTupleId(), iAggregate);
291  SuperInstruction indexOperation = getIndexSuperInstInfo(iAggregate);
292  NodePtr expr = visit(iAggregate.getExpression());
293  NodePtr cond = visit(iAggregate.getCondition());
294  orderingContext.addNewTuple(iAggregate.getTupleId(), 1);
295  NodePtr nested = visitTupleOperation(iAggregate);
296  size_t relId = encodeRelation(iAggregate.getRelation());
297  auto rel = getRelationHandle(relId);
298  NodeType type = constructNodeType("IndexAggregate", lookup(iAggregate.getRelation()));
299  return mk<IndexAggregate>(type, &iAggregate, rel, std::move(expr), std::move(cond), std::move(nested),
300  encodeView(&iAggregate), std::move(indexOperation));
301 }
302 
303 NodePtr NodeGenerator::visitParallelIndexAggregate(const ram::ParallelIndexAggregate& piAggregate) {
304  orderingContext.addTupleWithIndexOrder(piAggregate.getTupleId(), piAggregate);
305  SuperInstruction indexOperation = getIndexSuperInstInfo(piAggregate);
306  NodePtr expr = visit(piAggregate.getExpression());
307  NodePtr cond = visit(piAggregate.getCondition());
308  orderingContext.addNewTuple(piAggregate.getTupleId(), 1);
309  NodePtr nested = visitTupleOperation(piAggregate);
310  size_t relId = encodeRelation(piAggregate.getRelation());
311  auto rel = getRelationHandle(relId);
312  NodeType type = constructNodeType("ParallelIndexAggregate", lookup(piAggregate.getRelation()));
313  auto res = mk<ParallelIndexAggregate>(type, &piAggregate, rel, std::move(expr), std::move(cond),
314  std::move(nested), encodeView(&piAggregate), std::move(indexOperation));
315  res->setViewContext(parentQueryViewContext);
316  return res;
317 }
318 
319 NodePtr NodeGenerator::visitBreak(const ram::Break& breakOp) {
320  return mk<Break>(I_Break, &breakOp, visit(breakOp.getCondition()), visit(breakOp.getOperation()));
321 }
322 
323 NodePtr NodeGenerator::visitFilter(const ram::Filter& filter) {
324  return mk<Filter>(I_Filter, &filter, visit(filter.getCondition()), visit(filter.getOperation()));
325 }
326 
327 NodePtr NodeGenerator::visitProject(const ram::Project& project) {
328  SuperInstruction superOp = getProjectSuperInstInfo(project);
329  size_t relId = encodeRelation(project.getRelation());
330  auto rel = getRelationHandle(relId);
331  NodeType type = constructNodeType("Project", lookup(project.getRelation()));
332  return mk<Project>(type, &project, rel, std::move(superOp));
333 }
334 
335 NodePtr NodeGenerator::visitSubroutineReturn(const ram::SubroutineReturn& ret) {
336  NodePtrVec children;
337  for (const auto& value : ret.getValues()) {
338  children.push_back(visit(value));
339  }
340  return mk<SubroutineReturn>(I_SubroutineReturn, &ret, std::move(children));
341 }
342 
343 NodePtr NodeGenerator::visitSequence(const ram::Sequence& seq) {
344  NodePtrVec children;
345  for (const auto& value : seq.getStatements()) {
346  children.push_back(visit(value));
347  }
348  return mk<Sequence>(I_Sequence, &seq, std::move(children));
349 }
350 
351 NodePtr NodeGenerator::visitParallel(const ram::Parallel& parallel) {
352  // Parallel statements are executed in sequence for now.
353  NodePtrVec children;
354  for (const auto& value : parallel.getStatements()) {
355  children.push_back(visit(value));
356  }
357  return mk<Parallel>(I_Parallel, &parallel, std::move(children));
358 }
359 
360 NodePtr NodeGenerator::visitLoop(const ram::Loop& loop) {
361  return mk<Loop>(I_Loop, &loop, visit(loop.getBody()));
362 }
363 
364 NodePtr NodeGenerator::visitExit(const ram::Exit& exit) {
365  return mk<Exit>(I_Exit, &exit, visit(exit.getCondition()));
366 }
367 
368 NodePtr NodeGenerator::visitCall(const ram::Call& call) {
369  // translate a subroutine name to an index
370  // the index is used to identify the subroutine
371  // in the interpreter. The index is stored in the
372  // data array of the Node as the first
373  // entry.
374  auto subs = engine.tUnit.getProgram().getSubroutines();
375  size_t subroutineId = distance(subs.begin(), subs.find(call.getName()));
376  return mk<Call>(I_Call, &call, subroutineId);
377 }
378 
379 NodePtr NodeGenerator::visitLogRelationTimer(const ram::LogRelationTimer& timer) {
380  size_t relId = encodeRelation(timer.getRelation());
381  auto rel = getRelationHandle(relId);
382  return mk<LogRelationTimer>(I_LogRelationTimer, &timer, visit(timer.getStatement()), rel);
383 }
384 
385 NodePtr NodeGenerator::visitLogTimer(const ram::LogTimer& timer) {
386  return mk<LogTimer>(I_LogTimer, &timer, visit(timer.getStatement()));
387 }
388 
389 NodePtr NodeGenerator::visitDebugInfo(const ram::DebugInfo& dbg) {
390  return mk<DebugInfo>(I_DebugInfo, &dbg, visit(dbg.getStatement()));
391 }
392 
393 NodePtr NodeGenerator::visitClear(const ram::Clear& clear) {
394  size_t relId = encodeRelation(clear.getRelation());
395  auto rel = getRelationHandle(relId);
396  NodeType type = constructNodeType("Clear", lookup(clear.getRelation()));
397  return mk<Clear>(type, &clear, rel);
398 }
399 
400 NodePtr NodeGenerator::visitLogSize(const ram::LogSize& size) {
401  size_t relId = encodeRelation(size.getRelation());
402  auto rel = getRelationHandle(relId);
403  return mk<LogSize>(I_LogSize, &size, rel);
404 }
405 
406 NodePtr NodeGenerator::visitIO(const ram::IO& io) {
407  size_t relId = encodeRelation(io.getRelation());
408  auto rel = getRelationHandle(relId);
409  return mk<IO>(I_IO, &io, rel);
410 }
411 
412 NodePtr NodeGenerator::visitQuery(const ram::Query& query) {
413  std::shared_ptr<ViewContext> viewContext = std::make_shared<ViewContext>();
414  parentQueryViewContext = viewContext;
415  // split terms of conditions of outer-most filter operation
416  // into terms that require a context and terms that
417  // do not require a view
418  const ram::Operation* next = &query.getOperation();
419  std::vector<const ram::Condition*> freeOfView;
420  if (const auto* filter = dynamic_cast<const ram::Filter*>(&query.getOperation())) {
421  next = &filter->getOperation();
422  // Check terms of outer filter operation whether they can be pushed before
423  // the view-generation for speed improvements
424  auto conditions = findConjunctiveTerms(&filter->getCondition());
425  for (auto const& cur : conditions) {
426  bool needView = false;
427  visitDepthFirst(*cur, [&](const ram::Node& node) {
428  if (requireView(&node)) {
429  needView = true;
430  const auto& rel = getViewRelation(&node);
431  viewContext->addViewInfoForFilter(
432  encodeRelation(rel), indexTable[&node], encodeView(&node));
433  }
434  });
435 
436  if (needView) {
437  viewContext->addViewOperationForFilter(visit(*cur));
438  } else {
439  viewContext->addViewFreeOperationForFilter(visit(*cur));
440  }
441  }
442  }
443 
444  visitDepthFirst(*next, [&](const ram::Node& node) {
445  if (requireView(&node)) {
446  const auto& rel = getViewRelation(&node);
447  viewContext->addViewInfoForNested(encodeRelation(rel), indexTable[&node], encodeView(&node));
448  };
449  });
450 
451  visitDepthFirst(*next, [&](const ram::AbstractParallel&) { viewContext->isParallel = true; });
452 
453  auto res = mk<Query>(I_Query, &query, visit(*next));
454  res->setViewContext(parentQueryViewContext);
455  return res;
456 }
457 
458 NodePtr NodeGenerator::visitExtend(const ram::Extend& extend) {
459  size_t src = encodeRelation(extend.getFirstRelation());
460  size_t target = encodeRelation(extend.getSecondRelation());
461  return mk<Extend>(I_Extend, &extend, src, target);
462 }
463 
464 NodePtr NodeGenerator::visitSwap(const ram::Swap& swap) {
465  size_t src = encodeRelation(swap.getFirstRelation());
466  size_t target = encodeRelation(swap.getSecondRelation());
467  return mk<Swap>(I_Swap, &swap, src, target);
468 }
469 
470 NodePtr NodeGenerator::visitUndefValue(const ram::UndefValue&) {
471  return nullptr;
472 }
473 
474 NodePtr NodeGenerator::visitNode(const ram::Node& node) {
475  fatal("unsupported node type: %s", typeid(node).name());
476 }
477 
478 void NodeGenerator::newQueryBlock() {
479  viewTable.clear();
480  viewId = 0;
481 }
482 
483 size_t NodeGenerator::getNewRelId() {
484  return relId++;
485 }
486 
487 size_t NodeGenerator::getNextViewId() {
488  return viewId++;
489 }
490 
491 template <class RamNode>
492 size_t NodeGenerator::encodeIndexPos(RamNode& node) {
493  const std::string& name = node.getRelation();
494  auto& orderSet = engine.isa->getIndexes(name);
495  ram::analysis::SearchSignature signature = engine.isa->getSearchSignature(&node);
496  // A zero signature is equivalent as a full order signature.
497  if (signature.empty()) {
499  }
500  auto i = orderSet.getLexOrderNum(signature);
501  indexTable[&node] = i;
502  return i;
503 };
504 
505 size_t NodeGenerator::encodeView(const ram::Node* node) {
506  auto pos = viewTable.find(node);
507  if (pos != viewTable.end()) {
508  return pos->second;
509  }
510  size_t id = getNextViewId();
511  viewTable[node] = id;
512  return id;
513 }
514 
515 const ram::Relation& NodeGenerator::lookup(const std::string& relName) {
516  auto it = relationMap.find(relName);
517  assert(it != relationMap.end() && "relation not found");
518  return *it->second;
519 }
520 
521 size_t NodeGenerator::getArity(const std::string& relName) {
522  auto rel = lookup(relName);
523  return rel.getArity();
524 }
525 
526 size_t NodeGenerator::encodeRelation(const std::string& relName) {
527  auto pos = relTable.find(relName);
528  if (pos != relTable.end()) {
529  return pos->second;
530  }
531  size_t id = getNewRelId();
532  relTable[relName] = id;
533  engine.createRelation(lookup(relName), id);
534  return id;
535 }
536 
537 RelationHandle* NodeGenerator::getRelationHandle(const size_t idx) {
538  return engine.relations[idx].get();
539 }
540 
541 bool NodeGenerator::requireView(const ram::Node* node) {
542  if (isA<ram::AbstractExistenceCheck>(node)) {
543  return true;
544  } else if (isA<ram::IndexOperation>(node)) {
545  return true;
546  }
547  return false;
548 }
549 
550 const std::string& NodeGenerator::getViewRelation(const ram::Node* node) {
551  if (const auto* exist = dynamic_cast<const ram::AbstractExistenceCheck*>(node)) {
552  return exist->getRelation();
553  } else if (const auto* index = dynamic_cast<const ram::IndexOperation*>(node)) {
554  return index->getRelation();
555  }
556 
557  fatal("The ram::Node does not require a view.");
558 }
559 
560 SuperInstruction NodeGenerator::getIndexSuperInstInfo(const ram::IndexOperation& ramIndex) {
561  size_t arity = getArity(ramIndex.getRelation());
562  auto interpreterRel = encodeRelation(ramIndex.getRelation());
563  auto indexId = encodeIndexPos(ramIndex);
564  auto order = (*getRelationHandle(interpreterRel))->getIndexOrder(indexId);
565  SuperInstruction indexOperation(arity);
566  const auto& first = ramIndex.getRangePattern().first;
567  for (size_t i = 0; i < arity; ++i) {
568  // Note: unlike orderingContext::mapOrder, where we try to decode the order,
569  // here we have to encode the order.
570  auto& low = first[order[i]];
571 
572  // Unbounded
573  if (isUndefValue(low)) {
574  indexOperation.first[i] = MIN_RAM_SIGNED;
575  continue;
576  }
577 
578  // Constant
579  if (isA<ram::Constant>(low)) {
580  indexOperation.first[i] = dynamic_cast<ram::Constant*>(low)->getConstant();
581  continue;
582  }
583 
584  // TupleElement
585  if (isA<ram::TupleElement>(low)) {
586  auto lowTuple = dynamic_cast<ram::TupleElement*>(low);
587  size_t tupleId = lowTuple->getTupleId();
588  size_t elementId = lowTuple->getElement();
589  size_t newElementId = orderingContext.mapOrder(tupleId, elementId);
590  indexOperation.tupleFirst.push_back({i, tupleId, newElementId});
591  continue;
592  }
593 
594  // Generic expression
595  indexOperation.exprFirst.push_back(std::pair<size_t, Own<Node>>(i, visit(low)));
596  }
597  const auto& second = ramIndex.getRangePattern().second;
598  for (size_t i = 0; i < arity; ++i) {
599  auto& hig = second[order[i]];
600 
601  // Unbounded
602  if (isUndefValue(hig)) {
603  indexOperation.second[i] = MAX_RAM_SIGNED;
604  continue;
605  }
606 
607  // Constant
608  if (isA<ram::Constant>(hig)) {
609  indexOperation.second[i] = dynamic_cast<ram::Constant*>(hig)->getConstant();
610  continue;
611  }
612 
613  // TupleElement
614  if (isA<ram::TupleElement>(hig)) {
615  auto highTuple = dynamic_cast<ram::TupleElement*>(hig);
616  size_t tupleId = highTuple->getTupleId();
617  size_t elementId = highTuple->getElement();
618  size_t newElementId = orderingContext.mapOrder(tupleId, elementId);
619  indexOperation.tupleSecond.push_back({i, tupleId, newElementId});
620  continue;
621  }
622 
623  // Generic expression
624  indexOperation.exprSecond.push_back(std::pair<size_t, Own<Node>>(i, visit(hig)));
625  }
626  return indexOperation;
627 }
628 
629 SuperInstruction NodeGenerator::getExistenceSuperInstInfo(const ram::AbstractExistenceCheck& abstractExist) {
630  auto interpreterRel = encodeRelation(abstractExist.getRelation());
631  size_t indexId = 0;
632  if (isA<ram::ExistenceCheck>(&abstractExist)) {
633  indexId = encodeIndexPos(*dynamic_cast<const ram::ExistenceCheck*>(&abstractExist));
634  } else if (isA<ram::ProvenanceExistenceCheck>(&abstractExist)) {
635  indexId = encodeIndexPos(*dynamic_cast<const ram::ProvenanceExistenceCheck*>(&abstractExist));
636  } else {
637  fatal("Unrecognized ram::AbstractExistenceCheck.");
638  }
639  auto order = (*getRelationHandle(interpreterRel))->getIndexOrder(indexId);
640  size_t arity = getArity(abstractExist.getRelation());
641  SuperInstruction superOp(arity);
642  const auto& children = abstractExist.getValues();
643  for (size_t i = 0; i < arity; ++i) {
644  auto& child = children[order[i]];
645 
646  // Unbounded
647  if (isUndefValue(child)) {
648  superOp.first[i] = MIN_RAM_SIGNED;
649  superOp.second[i] = MAX_RAM_SIGNED;
650  continue;
651  }
652 
653  // Constant
654  if (isA<ram::Constant>(child)) {
655  superOp.first[i] = dynamic_cast<ram::Constant*>(child)->getConstant();
656  superOp.second[i] = superOp.first[i];
657  continue;
658  }
659 
660  // TupleElement
661  if (isA<ram::TupleElement>(child)) {
662  auto tuple = dynamic_cast<ram::TupleElement*>(child);
663  size_t tupleId = tuple->getTupleId();
664  size_t elementId = tuple->getElement();
665  size_t newElementId = orderingContext.mapOrder(tupleId, elementId);
666  superOp.tupleFirst.push_back({i, tupleId, newElementId});
667  continue;
668  }
669 
670  // Generic expression
671  superOp.exprFirst.push_back(std::pair<size_t, Own<Node>>(i, visit(child)));
672  }
673  return superOp;
674 }
675 
676 SuperInstruction NodeGenerator::getProjectSuperInstInfo(const ram::Project& exist) {
677  size_t arity = getArity(exist.getRelation());
678  SuperInstruction superOp(arity);
679  const auto& children = exist.getValues();
680  for (size_t i = 0; i < arity; ++i) {
681  auto& child = children[i];
682  // Constant
683  if (isA<ram::Constant>(child)) {
684  superOp.first[i] = dynamic_cast<ram::Constant*>(child)->getConstant();
685  continue;
686  }
687 
688  // TupleElement
689  if (isA<ram::TupleElement>(child)) {
690  auto tuple = dynamic_cast<ram::TupleElement*>(child);
691  size_t tupleId = tuple->getTupleId();
692  size_t elementId = tuple->getElement();
693  size_t newElementId = orderingContext.mapOrder(tupleId, elementId);
694  superOp.tupleFirst.push_back({i, tupleId, newElementId});
695  continue;
696  }
697 
698  // Generic expression
699  superOp.exprFirst.push_back(std::pair<size_t, Own<Node>>(i, visit(child)));
700  }
701  return superOp;
702 }
703 
704 // -- Definition of OrderingContext --
705 
706 NodeGenerator::OrderingContext::OrderingContext(NodeGenerator& generator) : generator(generator) {}
707 
708 void NodeGenerator::OrderingContext::addNewTuple(size_t tupleId, size_t arity) {
709  std::vector<uint32_t> order;
710  for (size_t i = 0; i < arity; ++i) {
711  order.push_back((uint32_t)i);
712  }
713  insertOrder(tupleId, std::move(order));
714 }
715 
716 template <class RamNode>
717 void NodeGenerator::OrderingContext::addTupleWithDefaultOrder(size_t tupleId, const RamNode& node) {
718  auto interpreterRel = generator.encodeRelation(node.getRelation());
719  insertOrder(tupleId, (*generator.getRelationHandle(interpreterRel))->getIndexOrder(0));
720 }
721 
722 template <class RamNode>
723 void NodeGenerator::OrderingContext::addTupleWithIndexOrder(size_t tupleId, const RamNode& node) {
724  auto interpreterRel = generator.encodeRelation(node.getRelation());
725  auto indexId = generator.encodeIndexPos(node);
726  auto order = (*generator.getRelationHandle(interpreterRel))->getIndexOrder(indexId);
727  insertOrder(tupleId, order);
728 }
729 
730 size_t NodeGenerator::OrderingContext::mapOrder(size_t tupleId, size_t elementId) const {
731  return tupleOrders[tupleId][elementId];
732 }
733 
734 void NodeGenerator::OrderingContext::insertOrder(size_t tupleId, const Order& order) {
735  if (tupleId >= tupleOrders.size()) {
736  tupleOrders.resize(tupleId + 1);
737  }
738 
739  std::vector<uint32_t> decodeOrder(order.size());
740  for (size_t i = 0; i < order.size(); ++i) {
741  decodeOrder[order[i]] = i;
742  }
743 
744  tupleOrders[tupleId] = std::move(decodeOrder);
745 }
746 }; // namespace souffle::interpreter
souffle::ram::Break
Breaks out of the loop if a condition holds.
Definition: Break.h:49
souffle::ram::IndexOperation
Definition: IndexOperation.h:48
souffle::interpreter::NodeGenerator::OrderingContext::mapOrder
size_t mapOrder(size_t tupleId, size_t elementId) const
Map the decoded order of elementId based on current context.
Definition: Generator.cpp:735
souffle::ram::analysis::SearchSignature
search signature of a RAM operation; each bit represents an attribute of a relation.
Definition: Index.h:52
souffle::ram::AbstractOperator::getArguments
std::vector< Expression * > getArguments() const
Get argument values.
Definition: AbstractOperator.h:49
TCB_SPAN_NAMESPACE_NAME::detail::size
constexpr auto size(const C &c) -> decltype(c.size())
Definition: span.h:198
souffle::ram::AutoIncrement
Increment a counter and return its value.
Definition: AutoIncrement.h:36
souffle::ram::UserDefinedOperator
Operator that represents an extrinsic (user-defined) functor.
Definition: UserDefinedOperator.h:43
souffle::ram::AbstractExistenceCheck::getValues
const std::vector< Expression * > getValues() const
Get arguments of the tuple/pattern A null pointer element in the vector denotes an unspecified patter...
Definition: AbstractExistenceCheck.h:66
souffle::interpreter::SuperInstruction::second
std::vector< RamDomain > second
constant value in the upper bound
Definition: Node.h:295
souffle::ram::ParallelIndexScan
Search for tuples of a relation matching a criteria.
Definition: ParallelIndexScan.h:58
souffle::ram::UnpackRecord::getArity
std::size_t getArity() const
Get arity of record.
Definition: UnpackRecord.h:65
souffle::ram::UnpackRecord
Record lookup.
Definition: UnpackRecord.h:51
souffle::ram::Swap
Swap operation with respect to two relations.
Definition: Swap.h:43
souffle::MAX_RAM_SIGNED
constexpr RamSigned MAX_RAM_SIGNED
Definition: RamTypes.h:97
souffle::ram::Query
A relational algebra query.
Definition: Query.h:50
souffle::ram::isUndefValue
bool isUndefValue(const Expression *expr)
Determines if an expression represents an undefined value.
Definition: Utils.h:40
souffle::ram::PackRecord
Packs a record's arguments into a reference.
Definition: PackRecord.h:42
souffle::ram::Constraint::getRHS
const Expression & getRHS() const
Get right-hand side.
Definition: Constraint.h:69
souffle::ram::ListStatement::getStatements
std::vector< Statement * > getStatements() const
Get statements.
Definition: ListStatement.h:51
souffle::ram::IndexOperation::getRangePattern
std::pair< std::vector< Expression * >, std::vector< Expression * > > getRangePattern() const
Get range pattern.
Definition: IndexOperation.h:70
souffle::ram::Loop
Execute statement until statement terminates loop via an exit statement.
Definition: Loop.h:48
low
d d low
Definition: htmlJsChartistMin.h:15
souffle::interpreter::NodeGenerator::OrderingContext::addNewTuple
void addNewTuple(size_t tupleId, size_t arity)
Bind tuple with a natural full order.
Definition: Generator.cpp:713
souffle::ram::AbstractAggregate::getCondition
const Condition & getCondition() const
Get condition.
Definition: AbstractAggregate.h:53
souffle::ram::Query::getOperation
const Operation & getOperation() const
Get RAM operation.
Definition: Query.h:57
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::Call
Call a subroutine.
Definition: Call.h:42
souffle::ram::NestedOperation::getOperation
Operation & getOperation() const
Get nested operation.
Definition: NestedOperation.h:62
souffle::ram::SubroutineReturn::getValues
std::vector< Expression * > getValues() const
Getter for expressions.
Definition: SubroutineReturn.h:55
relation
Relation & relation
Definition: Reader.h:130
souffle::ram::RelationStatement::getRelation
const std::string & getRelation() const
Get RAM relation.
Definition: RelationStatement.h:42
souffle::ram::EmptinessCheck::getRelation
const std::string & getRelation() const
Get relation.
Definition: EmptinessCheck.h:58
souffle::ram::AbstractAggregate::getExpression
const Expression & getExpression() const
Get target expression.
Definition: AbstractAggregate.h:64
souffle::interpreter::NodeGenerator::NodePtr
Own< Node > NodePtr
Definition: Generator.h:120
souffle::ram::LogTimer
Execution time logger for a statement.
Definition: LogTimer.h:55
souffle::interpreter::NodeGenerator::OrderingContext::addTupleWithDefaultOrder
void addTupleWithDefaultOrder(size_t tupleId, const RamNode &node)
Bind tuple with the default order.
Definition: Generator.cpp:722
Engine.h
souffle::ram::Conjunction::getLHS
const Condition & getLHS() const
Get left-hand side of conjunction.
Definition: Conjunction.h:62
souffle::ram::RelationOperation::getRelation
const std::string & getRelation() const
Get search relation.
Definition: RelationOperation.h:49
souffle::ram::ExistenceCheck
Existence check for a tuple(-pattern) in a relation.
Definition: ExistenceCheck.h:49
souffle::interpreter::NodePtr
Own< Node > NodePtr
Definition: Generator.cpp:26
souffle::ram::TupleElement
Access element from the current tuple in a tuple environment.
Definition: TupleElement.h:42
souffle::interpreter::SuperInstruction::first
std::vector< RamDomain > first
constant value in the lower bound/pattern
Definition: Node.h:293
souffle::ram::Constraint::getLHS
const Expression & getLHS() const
Get left-hand side.
Definition: Constraint.h:64
souffle::ram::False
Definition: False.h:38
souffle::ram::analysis::SearchSignature::arity
size_t arity() const
Definition: Index.cpp:47
souffle::interpreter::SuperInstruction::tupleFirst
std::vector< std::array< size_t, 3 > > tupleFirst
Encoded tupleElement expressions in the lower bound/pattern.
Definition: Node.h:297
souffle::ram::findConjunctiveTerms
std::vector< const ram::Condition * > findConjunctiveTerms(const ram::Condition *condition)
store terms of a conjunction in an array of pointers without cloning
Definition: Utils.h:102
souffle::interpreter::Order
An order to be enforced for storing tuples within indexes.
Definition: Index.h:48
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::interpreter
Definition: BrieIndex.cpp:22
souffle::interpreter::NodeType
NodeType
Definition: Node.h:129
souffle::ram::Node
Node is a superclass for all RAM IR classes.
Definition: Node.h:42
souffle::ram::NestedIntrinsicOperator::getArguments
std::vector< Expression * > getArguments() const
Definition: NestedIntrinsicOperator.h:71
souffle::ram::Project
Project a result into the target relation.
Definition: Project.h:50
i
size_t i
Definition: json11.h:663
souffle::filter
std::vector< A > filter(std::vector< A > xs, F &&f)
Filter a vector to include certain elements.
Definition: FunctionalUtil.h:155
souffle::interpreter::SuperInstruction::exprSecond
std::vector< std::pair< size_t, Own< Node > > > exprSecond
Generic expressions in the upper bound.
Definition: Node.h:303
souffle::interpreter::RelationHandle
Own< RelationWrapper > RelationHandle
Definition: Generator.cpp:28
souffle::ram::AbstractLog::getStatement
const Statement & getStatement() const
Get logging statement.
Definition: AbstractLog.h:55
souffle::interpreter::NodeGenerator::OrderingContext::addTupleWithIndexOrder
void addTupleWithIndexOrder(size_t tupleId, const RamNode &node)
Bind tuple with the corresponding index order.
Definition: Generator.cpp:728
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
souffle::ram::AbstractExistenceCheck
Abstract existence check for a tuple in a relation.
Definition: AbstractExistenceCheck.h:47
souffle::ram::NestedOperation
Abstract class for a nesting operations in a loop-nest.
Definition: NestedOperation.h:52
souffle::interpreter::NodeGenerator::NodeGenerator
NodeGenerator(Engine &engine)
Definition: Generator.cpp:30
souffle::ram::Aggregate
Aggregation function applied on some relation.
Definition: Aggregate.h:53
souffle::ram::ParallelAggregate
Parallel Aggregation function applied on some relation.
Definition: ParallelAggregate.h:53
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::interpreter::SuperInstruction::tupleSecond
std::vector< std::array< size_t, 3 > > tupleSecond
Encoded tupleElement expressions in the upper bound.
Definition: Node.h:299
souffle::ram::PackRecord::getArguments
std::vector< Expression * > getArguments() const
Get record arguments.
Definition: PackRecord.h:51
souffle::ram::TupleOperation::getTupleId
int getTupleId() const
Get identifier.
Definition: TupleOperation.h:43
souffle::ram::Operation
Abstract class for a relational algebra operation.
Definition: Operation.h:34
souffle::ram::ParallelScan
Iterate all tuples of a relation in parallel.
Definition: ParallelScan.h:52
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
souffle::ram::AbstractExistenceCheck::getRelation
const std::string & getRelation() const
Get relation.
Definition: AbstractExistenceCheck.h:57
souffle::MIN_RAM_SIGNED
constexpr RamSigned MIN_RAM_SIGNED
lower and upper boundaries for the ram types
Definition: RamTypes.h:96
souffle::ram::BinRelationStatement::getSecondRelation
const std::string & getSecondRelation() const
Get second relation.
Definition: BinRelationStatement.h:51
souffle::interpreter::SuperInstruction::exprFirst
std::vector< std::pair< size_t, Own< Node > > > exprFirst
Generic expressions in the lower bound/pattern.
Definition: Node.h:301
souffle::ram::TupleOperation
Abstract class for relation searches and lookups.
Definition: TupleOperation.h:35
souffle::interpreter::NodeGenerator::NodePtrVec
std::vector< NodePtr > NodePtrVec
Definition: Generator.h:121
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
souffle::interpreter::Order::size
size_t size() const
Definition: Index.h:75
souffle::ram::AbstractConditional::getCondition
const Condition & getCondition() const
Get condition that must be satisfied.
Definition: AbstractConditional.h:49
souffle::interpreter::NodeGenerator::OrderingContext::insertOrder
void insertOrder(size_t tupleId, const Order &order)
Definition: Generator.cpp:739
souffle::interpreter::constructNodeType
NodeType constructNodeType(std::string tokBase, const ram::Relation &rel)
Construct interpreterNodeType by looking at the representation and the arity of the given rel.
Definition: Node.h:146
souffle::ram::analysis::SearchSignature::getFullSearchSignature
static SearchSignature getFullSearchSignature(size_t arity)
Definition: Index.cpp:140
souffle::interpreter::SuperInstruction
This class encodes information for a super-instruction, which is used to eliminate Number and TupleEl...
Definition: Node.h:281
souffle::ram::Constraint
Evaluates a binary constraint with respect to two Expressions.
Definition: Constraint.h:55
souffle::ram::Project::getRelation
const std::string & getRelation() const
Get relation.
Definition: Project.h:60
souffle::ram::Negation
Negates a given condition.
Definition: Negation.h:49
souffle::ram::Call::getName
const std::string & getName() const
Get call name.
Definition: Call.h:47
souffle::fatal
void fatal(const char *format, const Args &... args)
Definition: MiscUtil.h:198
souffle::ram::UndefValue
An undefined expression.
Definition: UndefValue.h:36
souffle::ram::BinRelationStatement::getFirstRelation
const std::string & getFirstRelation() const
Get first relation.
Definition: BinRelationStatement.h:46
souffle::ram::NestedIntrinsicOperator
Effectively identical to IntrinsicOperator, except it can produce multiple results.
Definition: NestedIntrinsicOperator.h:62
souffle::ast::visitDepthFirst
void visitDepthFirst(const Node &root, Visitor< R, Ps... > &visitor, Args &... args)
A utility function visiting all nodes within the ast rooted by the given node recursively in a depth-...
Definition: Visitor.h:273
souffle::ram::True
False value condition.
Definition: True.h:38
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::Negation::getOperand
const Condition & getOperand() const
Get operand of negation.
Definition: Negation.h:56
souffle::ram::Loop::getBody
const Statement & getBody() const
Get loop body.
Definition: Loop.h:55
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
rel
void rel(size_t limit, bool showLimit=true)
Definition: Tui.h:1086
souffle::interpreter::NodePtrVec
std::vector< NodePtr > NodePtrVec
Definition: Generator.cpp:27
souffle::tuple
Defines a tuple for the OO interface such that relations with varying columns can be accessed.
Definition: SouffleInterface.h:443
souffle::ram::Conjunction::getRHS
const Condition & getRHS() const
Get right-hand side of conjunction.
Definition: Conjunction.h:67
Generator.h
souffle::ram::Sequence
Sequence of RAM statements.
Definition: Sequence.h:37
souffle::ram::AbstractChoice::getCondition
const Condition & getCondition() const
Getter for the condition.
Definition: AbstractChoice.h:45
id
void id(std::string col)
Definition: Tui.h:1124
souffle::ram::UnpackRecord::getExpression
const Expression & getExpression() const
Get record expression.
Definition: UnpackRecord.h:59
souffle::ram::analysis::SearchSignature::empty
bool empty() const
Definition: Index.cpp:77
souffle::ram::LogRelationTimer
Execution time logger for a statement.
Definition: LogRelationTimer.h:55
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::TupleElement::getTupleId
int getTupleId() const
Get identifier.
Definition: TupleElement.h:46