OILS / vendor / souffle / SouffleInterface.h View on Github | oilshell.org

1145 lines, 295 significant
1/*
2 * Souffle - A Datalog Compiler
3 * Copyright (c) 2015, 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 SouffleInterface.h
12 *
13 * Main include file for generated C++ classes of Souffle
14 *
15 ***********************************************************************/
16
17#pragma once
18
19#include "souffle/RamTypes.h"
20#include "souffle/RecordTable.h"
21#include "souffle/SymbolTable.h"
22#include "souffle/datastructure/ConcurrentCache.h"
23#include "souffle/utility/MiscUtil.h"
24#include <algorithm>
25#include <cassert>
26#include <cstddef>
27#include <cstdint>
28#include <initializer_list>
29#include <iostream>
30#include <map>
31#include <memory>
32#include <optional>
33#include <regex>
34#include <string>
35#include <tuple>
36#include <utility>
37#include <vector>
38
39namespace souffle {
40
41class tuple;
42
43/**
44 * Object-oriented wrapper class for Souffle's templatized relations.
45 */
46class Relation {
47public:
48 using arity_type = std::size_t;
49
50protected:
51 /**
52 * Abstract iterator class.
53 *
54 * When tuples are inserted into a relation, they will be stored contiguously.
55 * Intially, the iterator_base of a relation will point to the first tuple inserted.
56 * iterator_base can be moved to point to the next tuple until the end.
57 * The tuple iterator_base is pointing to can be accessed.
58 * However, users can not use this to access tuples since iterator class is protected.
59 * Instead, they should use the public class - iterator which interacts with iterator_base.
60 */
61 class iterator_base {
62 protected:
63 /**
64 * Required for identifying type of iterator
65 * (NB: LLVM has no typeinfo).
66 *
67 * Note: The above statement is not true anymore - should this be made to work the same
68 * as Node::operator==?
69 *
70 * TODO (Honghyw) : Provide a clear documentation of what id is used for.
71 */
72 std::size_t id;
73
74 public:
75 /**
76 * Get the ID of the iterator_base object.
77 *
78 * @return ID of the iterator_base object (std::size_t)
79 */
80 virtual std::size_t getId() const {
81 return id;
82 }
83
84 /**
85 * Constructor.
86 *
87 * Create an instance of iterator_base and set its ID to be arg_id.
88 *
89 * @param arg_id ID of an iterator object (std::size_t)
90 */
91 iterator_base(std::size_t arg_id) : id(arg_id) {}
92
93 /**
94 * Destructor.
95 */
96 virtual ~iterator_base() = default;
97
98 /**
99 * Overload the "++" operator.
100 *
101 * Increment the iterator_base so that the iterator_base will now point to the next tuple.
102 * The definition of this overloading has to be defined by the child class of iterator_base.
103 */
104 virtual void operator++() = 0;
105
106 /**
107 * Overload the "*" operator.
108 *
109 * Return the tuple that is pointed to by the iterator_base.
110 * The definition of this overloading has to be defined by the child class of iterator_base.
111 *
112 * @return tuple Reference to a tuple object
113 */
114 virtual tuple& operator*() = 0;
115
116 /**
117 * Overload the "==" operator.
118 *
119 * @param o Reference to an object of the iterator_base class
120 * @return A boolean value, if the ID of o is the same as the ID of the current object and equal(o)
121 * returns true. Otherwise return false
122 */
123 bool operator==(const iterator_base& o) const {
124 return this->getId() == o.getId() && equal(o);
125 }
126
127 /**
128 * Clone the iterator_base.
129 * The definition of clone has to be defined by the child class of iterator_base.
130 *
131 * @return An iterator_base pointer
132 */
133 virtual iterator_base* clone() const = 0;
134
135 protected:
136 /**
137 * Check if the passed-in object of o is the the same as the current iterator_base.
138 *
139 * TODO (Honghyw) : Provide a clear documentation of what equal function does.
140 *
141 * @param o Reference to an object of the iterator_base class
142 * @return A boolean value. If two iterator_base are the same return true. Otherwise return false
143 */
144 virtual bool equal(const iterator_base& o) const = 0;
145 };
146
147public:
148 /**
149 * Destructor.
150 */
151 virtual ~Relation() = default;
152
153 /**
154 * Wrapper class for abstract iterator.
155 *
156 * Users must use iterator class to access the tuples stored in a relation.
157 */
158 class iterator {
159 protected:
160 /*
161 * iterator_base class pointer.
162 *
163 */
164 std::unique_ptr<iterator_base> iter = nullptr;
165
166 public:
167 /**
168 * Constructor.
169 */
170 iterator() = default;
171
172 /**
173 * Move constructor.
174 *
175 * The new iterator now has ownerhsip of the iterator base.
176 *
177 * @param arg lvalue reference to an iterator object
178 */
179 iterator(iterator&& arg) = default;
180
181 /**
182 * Constructor.
183 *
184 * Initialise this iterator with a given iterator base
185 *
186 * The new iterator has ownership of the iterator base.
187 *
188 * @param arg An iterator_base class pointer
189 */
190 iterator(std::unique_ptr<iterator_base> it) : iter(std::move(it)) {}
191
192 /**
193 * Destructor.
194 *
195 * The iterator_base instance iter is pointing is destructed.
196 */
197 ~iterator() = default;
198
199 /**
200 * Constructor.
201 *
202 * Initialise the iter to be the clone of arg.
203 *
204 * @param o Reference to an iterator object
205 */
206 iterator(const iterator& o) : iter(o.iter->clone()) {}
207
208 /**
209 * Overload the "=" operator.
210 *
211 * The original iterator_base instance is destructed.
212 */
213 iterator& operator=(const iterator& o) {
214 iter.reset(o.iter->clone());
215 return *this;
216 }
217
218 iterator& operator=(iterator&& o) {
219 iter.swap(o.iter);
220 return *this;
221 }
222
223 /**
224 * Overload the "++" operator.
225 *
226 * Increment the iterator_base object that iter is pointing to so that iterator_base object points to
227 * next tuple.
228 *
229 * @return Reference to the iterator object which points to the next tuple in a relation
230 */
231 iterator& operator++() {
232 ++(*iter);
233 return *this;
234 }
235
236 /**
237 * Overload the "++" operator.
238 *
239 * Copies the iterator, increments itself, and returns the (pre-increment) copy.
240 * WARNING: Expensive due to copy! Included for API compatibility.
241 *
242 * @return Pre-increment copy of `this`.
243 */
244 iterator operator++(int) {
245 auto cpy = *this;
246 ++(*this);
247 return cpy;
248 }
249
250 /**
251 * Overload the "*" operator.
252 *
253 * This will return the tuple that the iterator is pointing to.
254 *
255 * @return Reference to a tuple object
256 */
257
258 tuple& operator*() const {
259 return *(*iter);
260 }
261
262 /**
263 * Overload the "==" operator.
264 *
265 * Check if either the iter of o and the iter of current object are the same or the corresponding
266 * iterator_base objects are the same.
267 *
268 * @param o Reference to a iterator object
269 * @return Boolean. True, if either of them is true. False, otherwise
270 */
271 bool operator==(const iterator& o) const {
272 return (iter == o.iter) || (*iter == *o.iter);
273 }
274
275 /**
276 * Overload the "!=" operator.
277 *
278 * Check if the iterator object o is not the same as the current object.
279 *
280 * @param o Reference to a iterator object
281 * @return Boolean. True, if they are not the same. False, otherwise
282 */
283 bool operator!=(const iterator& o) const {
284 return !(*this == o);
285 }
286 };
287
288 /**
289 * Insert a new tuple into the relation.
290 * The definition of insert function has to be defined by the child class of relation class.
291 *
292 * @param t Reference to a tuple class object
293 */
294 virtual void insert(const tuple& t) = 0;
295
296 /**
297 * Check whether a tuple exists in a relation.
298 * The definition of contains has to be defined by the child class of relation class.
299 *
300 * @param t Reference to a tuple object
301 * @return Boolean. True, if the tuple exists. False, otherwise
302 */
303 virtual bool contains(const tuple& t) const = 0;
304
305 /**
306 * Return an iterator pointing to the first tuple of the relation.
307 * This iterator is used to access the tuples of the relation.
308 *
309 * @return Iterator
310 */
311 virtual iterator begin() const = 0;
312
313 /**
314 * Return an iterator pointing to next to the last tuple of the relation.
315 *
316 * @return Iterator
317 */
318 virtual iterator end() const = 0;
319
320 /**
321 * Get the number of tuples in a relation.
322 *
323 * @return The number of tuples in a relation (std::size_t)
324 */
325 virtual std::size_t size() const = 0;
326
327 /**
328 * Get the name of a relation.
329 *
330 * @return The name of a relation (std::string)
331 */
332 virtual std::string getName() const = 0;
333
334 /**
335 * Get the attribute type of a relation at the column specified by the parameter.
336 * The attribute type is in the form "<primitive type>:<type name>".
337 * <primitive type> can be s, f, u, i, r, or + standing for symbol, float,
338 * unsigned, integer, record, and ADT respectively,
339 * which are the primitive types in Souffle.
340 * <type name> is the name given by the user in the Souffle program
341 *
342 * @param The index of the column starting starting from 0 (std::size_t)
343 * @return The constant string of the attribute type
344 */
345 virtual const char* getAttrType(std::size_t) const = 0;
346
347 /**
348 * Get the attribute name of a relation at the column specified by the parameter.
349 * The attribute name is the name given to the type by the user in the .decl statement. For example, for
350 * ".decl edge (node1:Node, node2:Node)", the attribute names are node1 and node2.
351 *
352 * @param The index of the column starting starting from 0 (std::size_t)
353 * @return The constant string of the attribute name
354 */
355 virtual const char* getAttrName(std::size_t) const = 0;
356
357 /**
358 * Return the arity of a relation.
359 * For example for a tuple (1 2) the arity is 2 and for a tuple (1 2 3) the arity is 3.
360 *
361 * @return Arity of a relation (`arity_type`)
362 */
363 virtual arity_type getArity() const = 0;
364
365 /**
366 * Return the number of auxiliary attributes. Auxiliary attributes
367 * are used for provenance and and other alternative evaluation
368 * strategies. They are stored as the last attributes of a tuple.
369 *
370 * @return Number of auxiliary attributes of a relation (`arity_type`)
371 */
372 virtual arity_type getAuxiliaryArity() const = 0;
373
374 /**
375 * Return the number of non-auxiliary attributes.
376 * Auxiliary attributes are used for provenance and and other alternative
377 * evaluation strategies.
378 * They are stored as the last attributes of a tuple.
379 *
380 * @return Number of non-auxiliary attributes of a relation (`arity_type`)
381 */
382 arity_type getPrimaryArity() const {
383 assert(getAuxiliaryArity() <= getArity());
384 return getArity() - getAuxiliaryArity();
385 }
386
387 /**
388 * Get the symbol table of a relation.
389 * The symbols in a tuple to be stored into a relation are stored and assigned with a number in a table
390 * called symbol table. For example, to insert ("John","Student") to a relation, "John" and "Student" are
391 * stored in symbol table and they are assigned with number say 0 and 1. After this, instead of inserting
392 * ("John","Student"), (0, 1) is inserted. When accessing this tuple, 0 and 1 will be looked up in the
393 * table and replaced by "John" and "Student". This is done so to save memory space if same symbols are
394 * inserted many times. Symbol table has many rows where each row contains a symbol and its corresponding
395 * assigned number.
396 *
397 * @return Reference to a symbolTable object
398 */
399 virtual SymbolTable& getSymbolTable() const = 0;
400
401 /**
402 * Get the signature of a relation.
403 * The signature is in the form <<primitive type 1>:<type name 1>,<primitive type 2>:<type name 2>...> for
404 * all the attributes in a relation. For example, <s:Node,s:Node>. The primitive type and type name are
405 * explained in getAttrType.
406 *
407 * @return String of the signature of a relation
408 */
409 std::string getSignature() {
410 if (getArity() == 0) {
411 return "<>";
412 }
413
414 std::string signature = "<" + std::string(getAttrType(0));
415 for (arity_type i = 1; i < getArity(); i++) {
416 signature += "," + std::string(getAttrType(i));
417 }
418 signature += ">";
419 return signature;
420 }
421
422 /**
423 * Delete all the tuples in relation.
424 *
425 * When purge() is called, it sets the head and tail of the table (table is a
426 * singly-linked list structure) to nullptr, and for every elements
427 * in the table, set the next element pointer points to the current element itself.
428 */
429 virtual void purge() = 0;
430};
431
432/**
433 * Defines a tuple for the OO interface such that
434 * relations with varying columns can be accessed.
435 *
436 * Tuples are stored in relations.
437 * In Souffle, one row of data to be stored into a relation is represented as a tuple.
438 * For example if we have a relation called dog with attributes name, colour and age which are string, string
439 * and interger type respectively. One row of data a relation to be stored can be (mydog, black, 3). However,
440 * this is not directly stored as a tuple. There will be a symbol table storing the actual content and
441 * associate them with numbers (For example, |1|mydog| |2|black| |3|3|). And when this row of data is stored
442 * as a tuple, (1, 2, 3) will be stored.
443 */
444class tuple {
445 /**
446 * The relation to which the tuple belongs.
447 */
448 const Relation& relation;
449
450 /**
451 * Dynamic array used to store the elements in a tuple.
452 */
453 std::vector<RamDomain> array;
454
455 /**
456 * pos shows what the current position of a tuple is.
457 * Initially, pos is 0 meaning we are at the head of the tuple.
458 * If we have an empty tuple and try to insert things, pos lets us know where to insert the element. After
459 * the element is inserted, pos will be incremented by 1. If we have a tuple with content, pos lets us
460 * know where to read the element. After we have read one element, pos will be incremented by 1. pos also
461 * helps to make sure we access an insert a tuple within the bound by making sure pos never exceeds the
462 * arity of the relation.
463 */
464 std::size_t pos;
465
466public:
467 /**
468 * Constructor.
469 *
470 * Tuples are constructed here by passing a relation, then may be subsequently inserted into that same
471 * passed relation. The passed relation pointer will be stored within the tuple instance, while the arity
472 * of the relation will be used to initialize the vector holding the elements of the tuple. Where such an
473 * element is of integer type, it will be stored directly within the vector. Otherwise, if the element is
474 * of a string type, the index of that string within the associated symbol table will be stored instead.
475 * The tuple also stores the index of some "current" element, referred to as its position. The constructor
476 * initially sets this position to the first (zeroth) element of the tuple, while subsequent methods of
477 * this class use that position for element access and modification.
478 *
479 * @param r Relation pointer pointing to a relation
480 */
481 tuple(const Relation* r) : relation(*r), array(r->getArity()), pos(0), data(array.data()) {}
482
483 /**
484 * Constructor.
485 *
486 * Tuples are constructed here by passing a tuple.
487 * The relation to which the passed tuple belongs to will be stored.
488 * The array of the passed tuple, which stores the elements will be stroed.
489 * The pos will be set to be the same as the pos of passed tuple.
490 * belongs to.
491 *
492 * @param Reference to a tuple object.
493 */
494 tuple(const tuple& t) : relation(t.relation), array(t.array), pos(t.pos), data(array.data()) {}
495
496 /**
497 * Allows printing using WriteStream.
498 */
499 const RamDomain* data = nullptr;
500
501 /**
502 * Get the reference to the relation to which the tuple belongs.
503 *
504 * @return Reference to a relation.
505 */
506 const Relation& getRelation() const {
507 return relation;
508 }
509
510 /**
511 * Return the number of elements in the tuple.
512 *
513 * @return the number of elements in the tuple (std::size_t).
514 */
515 Relation::arity_type size() const {
516 assert(array.size() <= std::numeric_limits<Relation::arity_type>::max());
517 return Relation::arity_type(array.size());
518 }
519
520 /**
521 * Overload the operator [].
522 *
523 * Direct access to tuple elements via index and
524 * return the element in idx position of a tuple.
525 *
526 * TODO (Honghyw) : This interface should be hidden and
527 * only be used by friendly classes such as
528 * iterators; users should not use this interface.
529 *
530 * @param idx This is the idx of element in a tuple (std::size_t).
531 */
532 RamDomain& operator[](std::size_t idx) {
533 return array[idx];
534 }
535
536 /**
537 * Overload the operator [].
538 *
539 * Direct access to tuple elements via index and
540 * Return the element in idx position of a tuple. The returned element can not be changed.
541 *
542 * TODO (Honghyw) : This interface should be hidden and
543 * only be used by friendly classes such as
544 * iterators; users should not use this interface.
545 *
546 * @param idx This is the idx of element in a tuple (std::size_t).
547 */
548 const RamDomain& operator[](std::size_t idx) const {
549 return array[idx];
550 }
551
552 /**
553 * Reset the index giving the "current element" of the tuple to zero.
554 */
555 void rewind() {
556 pos = 0;
557 }
558
559 /**
560 * Set the "current element" of the tuple to the given string, then increment the index giving the current
561 * element.
562 *
563 * @param str Symbol to be added (std::string)
564 * @return Reference to the tuple
565 */
566 tuple& operator<<(const std::string& str) {
567 assert(pos < size() && "exceeded tuple's size");
568 assert(*relation.getAttrType(pos) == 's' && "wrong element type");
569 array[pos++] = relation.getSymbolTable().encode(str);
570 return *this;
571 }
572
573 /**
574 * Set the "current element" of the tuple to the given int, then increment the index giving the current
575 * element.
576 *
577 * @param integer Integer to be added
578 * @return Reference to the tuple
579 */
580 tuple& operator<<(RamSigned integer) {
581 assert(pos < size() && "exceeded tuple's size");
582 assert((*relation.getAttrType(pos) == 'i' || *relation.getAttrType(pos) == 'r' ||
583 *relation.getAttrType(pos) == '+') &&
584 "wrong element type");
585 array[pos++] = integer;
586 return *this;
587 }
588
589 /**
590 * Set the "current element" of the tuple to the given uint, then increment the index giving the current
591 * element.
592 *
593 * @param uint Unsigned number to be added
594 * @return Reference to the tuple
595 */
596 tuple& operator<<(RamUnsigned uint) {
597 assert(pos < size() && "exceeded tuple's size");
598 assert((*relation.getAttrType(pos) == 'u') && "wrong element type");
599 array[pos++] = ramBitCast(uint);
600 return *this;
601 }
602
603 /**
604 * Set the "current element" of the tuple to the given float, then increment the index giving the current
605 * element.
606 *
607 * @param float float to be added
608 * @return Reference to the tuple
609 */
610 tuple& operator<<(RamFloat ramFloat) {
611 assert(pos < size() && "exceeded tuple's size");
612 assert((*relation.getAttrType(pos) == 'f') && "wrong element type");
613 array[pos++] = ramBitCast(ramFloat);
614 return *this;
615 }
616
617 /**
618 * Get the "current element" of the tuple as a string, then increment the index giving the current
619 * element.
620 *
621 * @param str Symbol to be loaded from the tuple(std::string)
622 * @return Reference to the tuple
623 */
624 tuple& operator>>(std::string& str) {
625 assert(pos < size() && "exceeded tuple's size");
626 assert(*relation.getAttrType(pos) == 's' && "wrong element type");
627 str = relation.getSymbolTable().decode(array[pos++]);
628 return *this;
629 }
630
631 /**
632 * Get the "current element" of the tuple as a int, then increment the index giving the current
633 * element.
634 *
635 * @param integer Integer to be loaded from the tuple
636 * @return Reference to the tuple
637 */
638 tuple& operator>>(RamSigned& integer) {
639 assert(pos < size() && "exceeded tuple's size");
640 assert((*relation.getAttrType(pos) == 'i' || *relation.getAttrType(pos) == 'r' ||
641 *relation.getAttrType(pos) == '+') &&
642 "wrong element type");
643 integer = ramBitCast<RamSigned>(array[pos++]);
644 return *this;
645 }
646
647 /**
648 * Get the "current element" of the tuple as a unsigned, then increment the index giving the current
649 * element.
650 *
651 * @param uint Unsigned number to be loaded from the tuple
652 * @return Reference to the tuple
653 */
654 tuple& operator>>(RamUnsigned& uint) {
655 assert(pos < size() && "exceeded tuple's size");
656 assert((*relation.getAttrType(pos) == 'u') && "wrong element type");
657 uint = ramBitCast<RamUnsigned>(array[pos++]);
658 return *this;
659 }
660
661 /**
662 * Get the "current element" of the tuple as a float, then increment the index giving the current
663 * element.
664 *
665 * @param ramFloat Float to be loaded from the tuple
666 * @return Reference to the tuple
667 */
668 tuple& operator>>(RamFloat& ramFloat) {
669 assert(pos < size() && "exceeded tuple's size");
670 assert((*relation.getAttrType(pos) == 'f') && "wrong element type");
671 ramFloat = ramBitCast<RamFloat>(array[pos++]);
672 return *this;
673 }
674
675 /**
676 * Iterator for direct access to tuple's data.
677 *
678 * @see Relation::iteraor::begin()
679 */
680 decltype(array)::iterator begin() {
681 return array.begin();
682 }
683
684 /**
685 * Construct using initialisation list.
686 */
687 tuple(const Relation* relation, std::initializer_list<RamDomain> tupleList)
688 : relation(*relation), array(tupleList), pos(tupleList.size()), data(array.data()) {
689 assert(tupleList.size() == relation->getArity() && "tuple arity does not match relation arity");
690 }
691};
692
693/**
694 * Abstract base class for generated Datalog programs.
695 */
696class SouffleProgram {
697protected:
698 /**
699 * Define a relation map for external access, when getRelation(name) is called,
700 * the relation with the given name will be returned from this map,
701 * relationMap stores all the relations in a map with its name
702 * as the key and relation as the value.
703 */
704 std::map<std::string, Relation*> relationMap;
705
706 /**
707 * inputRelations stores all the input relation in a vector.
708 */
709 std::vector<Relation*> inputRelations;
710
711 /**
712 * outputRelations stores all the output relation in a vector.
713 */
714 std::vector<Relation*> outputRelations;
715
716 /**
717 * internalRelation stores all the relation in a vector that are neither an input or an output.
718 */
719 std::vector<Relation*> internalRelations;
720
721 /**
722 * allRelations store all the relation in a vector.
723 */
724 std::vector<Relation*> allRelations;
725
726 /**
727 * The number of threads used by OpenMP
728 */
729 std::size_t numThreads = 1;
730
731 /**
732 * Enable I/O
733 */
734 bool performIO = false;
735
736 /**
737 * Prune Intermediate Relations when there is no further use for them.
738 */
739 bool pruneImdtRels = true;
740
741 /**
742 * Add the relation to relationMap (with its name) and allRelations,
743 * depends on the properties of the relation, if the relation is an input relation, it will be added to
744 * inputRelations, else if the relation is an output relation, it will be added to outputRelations,
745 * otherwise will add to internalRelations. (a relation could be both input and output at the same time.)
746 *
747 * @param name the name of the relation (std::string)
748 * @param rel a reference to the relation
749 * @param isInput a bool argument, true if the relation is a input relation, else false (bool)
750 * @param isOnput a bool argument, true if the relation is a ouput relation, else false (bool)
751 */
752 void addRelation(const std::string& name, Relation& rel, bool isInput, bool isOutput) {
753 relationMap[name] = &rel;
754 allRelations.push_back(&rel);
755 if (isInput) {
756 inputRelations.push_back(&rel);
757 }
758 if (isOutput) {
759 outputRelations.push_back(&rel);
760 }
761 if (!isInput && !isOutput) {
762 internalRelations.push_back(&rel);
763 }
764 }
765
766 [[deprecated("pass `rel` by reference; `rel` may not be null"), maybe_unused]] void addRelation(
767 const std::string& name, Relation* rel, bool isInput, bool isOutput) {
768 assert(rel && "`rel` may not be null");
769 addRelation(name, *rel, isInput, isOutput);
770 }
771
772public:
773 /**
774 * Destructor.
775 *
776 * Destructor of SouffleProgram.
777 */
778 virtual ~SouffleProgram() = default;
779
780 /**
781 * Execute the souffle program, without any loads or stores, and live-profiling (in case it is switched
782 * on).
783 */
784 virtual void run() {}
785
786 /**
787 * Execute program, loading inputs and storing outputs as required.
788 * File IO types can use the given directories to find their input file.
789 *
790 * @param inputDirectory If non-empty, specifies the input directory
791 * @param outputDirectory If non-empty, specifies the output directory
792 * @param performIO Enable I/O operations
793 * @param pruneImdtRels Prune intermediate relations
794 */
795 virtual void runAll(std::string inputDirectory = "", std::string outputDirectory = "",
796 bool performIO = false, bool pruneImdtRels = true) = 0;
797
798 /**
799 * Read all input relations.
800 *
801 * File IO types can use the given directory to find their input file.
802 * @param inputDirectory If non-empty, specifies the input directory
803 */
804 virtual void loadAll(std::string inputDirectory = "") = 0;
805
806 /**
807 * Store all output relations.
808 *
809 * File IO types can use the given directory to find their input file.
810 * @param outputDirectory If non-empty, specifies the output directory
811 */
812 virtual void printAll(std::string outputDirectory = "") = 0;
813
814 /**
815 * Output all the input relations in stdout, without generating any files. (for debug purposes).
816 */
817 virtual void dumpInputs() = 0;
818
819 /**
820 * Output all the output relations in stdout, without generating any files. (for debug purposes).
821 */
822 virtual void dumpOutputs() = 0;
823
824 /**
825 * Set the number of threads to be used
826 */
827 virtual void setNumThreads(std::size_t numThreadsValue) {
828 this->numThreads = numThreadsValue;
829 }
830
831 /**
832 * Get the number of threads to be used
833 */
834 std::size_t getNumThreads() {
835 return numThreads;
836 }
837
838 /**
839 * Get Relation by its name from relationMap, if relation not found, return a nullptr.
840 *
841 * @param name The name of the target relation (const std::string)
842 * @return The pointer of the target relation, or null pointer if the relation not found (Relation*)
843 */
844 Relation* getRelation(const std::string& name) const {
845 auto it = relationMap.find(name);
846 if (it != relationMap.end()) {
847 return (*it).second;
848 } else {
849 return nullptr;
850 }
851 };
852
853 /**
854 * Return the size of the target relation from relationMap.
855 *
856 * @param name The name of the target relation (const std::string)
857 * @return The size of the target relation (std::size_t)
858 */
859 std::optional<std::size_t> getRelationSize(const std::string& name) const {
860 if (auto* rel = getRelation(name)) {
861 return rel->size();
862 }
863
864 return std::nullopt;
865 }
866
867 /**
868 * Return the name of the target relation from relationMap.
869 *
870 * @param name The name of the target relation (const std::string)
871 * @return The name of the target relation (std::string)
872 */
873 std::optional<std::string> getRelationName(const std::string& name) const {
874 if (auto* rel = getRelation(name)) {
875 return rel->getName();
876 }
877
878 return std::nullopt;
879 }
880
881 /**
882 * Getter of outputRelations, which this vector structure contains all output relations.
883 *
884 * @return outputRelations (std::vector)
885 * @see outputRelations
886 */
887 std::vector<Relation*> getOutputRelations() const {
888 return outputRelations;
889 }
890
891 /**
892 * Getter of inputRelations, which this vector structure contains all input relations.
893 *
894 * @return intputRelations (std::vector)
895 * @see inputRelations
896 */
897 std::vector<Relation*> getInputRelations() const {
898 return inputRelations;
899 }
900
901 /**
902 * Getter of internalRelations, which this vector structure contains all relations
903 * that are neither an input relation or an output relation.
904 *
905 * @return internalRelations (std::vector)
906 * @see internalRelations
907 */
908 std::vector<Relation*> getInternalRelations() const {
909 return internalRelations;
910 }
911
912 /**
913 * Getter of allRelations, which this vector structure contains all relations.
914 *
915 * @return allRelations (std::vector)
916 * @see allRelations
917 */
918 std::vector<Relation*> getAllRelations() const {
919 return allRelations;
920 }
921
922 /**
923 * Execute a subroutine
924 * @param name Name of a subroutine (std:string)
925 * @param arg Arguments of the subroutine (std::vector<RamDomain>&)
926 * @param ret Return values of the subroutine (std::vector<RamDomain>&)
927 */
928 virtual void executeSubroutine(std::string /* name */, const std::vector<RamDomain>& /* args */,
929 std::vector<RamDomain>& /* ret */) {
930 fatal("unknown subroutine");
931 }
932
933 /**
934 * Get the symbol table of the program.
935 */
936 virtual SymbolTable& getSymbolTable() = 0;
937
938 /**
939 * Get the record table of the program.
940 */
941 virtual RecordTable& getRecordTable() = 0;
942
943 /**
944 * Remove all the tuples from the outputRelations, calling the purge method of each.
945 *
946 * @see Relation::purge()
947 */
948 void purgeOutputRelations() {
949 for (Relation* relation : outputRelations) {
950 relation->purge();
951 }
952 }
953
954 /**
955 * Remove all the tuples from the inputRelations, calling the purge method of each.
956 *
957 * @see Relation::purge()
958 */
959 void purgeInputRelations() {
960 for (Relation* relation : inputRelations) {
961 relation->purge();
962 }
963 }
964
965 /**
966 * Remove all the tuples from the internalRelations, calling the purge method of each.
967 *
968 * @see Relation::purge()
969 */
970 void purgeInternalRelations() {
971 for (Relation* relation : internalRelations) {
972 relation->purge();
973 }
974 }
975
976 /**
977 * Helper function for the wrapper function Relation::insert() and Relation::contains().
978 */
979 template <typename Tuple, std::size_t N>
980 struct tuple_insert {
981 static void add(const Tuple& t, souffle::tuple& t1) {
982 tuple_insert<Tuple, N - 1>::add(t, t1);
983 t1 << std::get<N - 1>(t);
984 }
985 };
986
987 /**
988 * Helper function for the wrapper function Relation::insert() and Relation::contains() for the
989 * first element of the tuple.
990 */
991 template <typename Tuple>
992 struct tuple_insert<Tuple, 1> {
993 static void add(const Tuple& t, souffle::tuple& t1) {
994 t1 << std::get<0>(t);
995 }
996 };
997
998 /**
999 * Insert function with std::tuple as input (wrapper)
1000 *
1001 * @param t The insert tuple (std::tuple)
1002 * @param relation The relation that perform insert operation (Relation*)
1003 * @see Relation::insert()
1004 */
1005 template <typename... Args>
1006 void insert(const std::tuple<Args...>& t, Relation* relation) {
1007 tuple t1(relation);
1008 tuple_insert<decltype(t), sizeof...(Args)>::add(t, t1);
1009 relation->insert(t1);
1010 }
1011
1012 /**
1013 * Contains function with std::tuple as input (wrapper)
1014 *
1015 * @param t The existence searching tuple (std::tuple)
1016 * @param relation The relation that perform contains operation (Relation*)
1017 * @return A boolean value, return true if the tuple found, otherwise return false
1018 * @see Relation::contains()
1019 */
1020 template <typename... Args>
1021 bool contains(const std::tuple<Args...>& t, Relation* relation) {
1022 tuple t1(relation);
1023 tuple_insert<decltype(t), sizeof...(Args)>::add(t, t1);
1024 return relation->contains(t1);
1025 }
1026
1027 /**
1028 * Set perform-I/O flag
1029 */
1030 void setPerformIO(bool performIOArg) {
1031 performIO = performIOArg;
1032 }
1033
1034 /**
1035 * Set prune-intermediate-relations flag
1036 */
1037 void setPruneImdtRels(bool pruneImdtRelsArg) {
1038 pruneImdtRels = pruneImdtRelsArg;
1039 }
1040};
1041
1042/**
1043 * Abstract program factory class.
1044 */
1045class ProgramFactory {
1046protected:
1047 /**
1048 * Singly linked-list to store all program factories
1049 * Note that STL data-structures are not possible due
1050 * to "static initialization order fiasco (problem)".
1051 * (The problem of the order static objects get initialized, causing effect
1052 * such as program access static variables before they initialized.)
1053 * The static container needs to be a primitive type such as pointer
1054 * set to NULL.
1055 * Link to next factory.
1056 */
1057 ProgramFactory* link = nullptr;
1058
1059 /**
1060 * The name of factory.
1061 */
1062 std::string name;
1063
1064protected:
1065 /**
1066 * Constructor.
1067 *
1068 * Constructor adds factory to static singly-linked list
1069 * for registration.
1070 */
1071 ProgramFactory(std::string name) : name(std::move(name)) {
1072 registerFactory(this);
1073 }
1074
1075private:
1076 /**
1077 * Helper method for creating a factory map, which map key is the name of the program factory, map value
1078 * is the pointer of the ProgramFactory.
1079 *
1080 * TODO (NubKel) : Improve documentation of use and interaction between inline and static, here and for
1081 * the whole class.
1082 *
1083 * @return The factory registration map (std::map)
1084 */
1085 static inline std::map<std::string, ProgramFactory*>& getFactoryRegistry() {
1086 static std::map<std::string, ProgramFactory*> factoryReg;
1087 return factoryReg;
1088 }
1089
1090protected:
1091 /**
1092 * Create and insert a factory into the factoryReg map.
1093 *
1094 * @param factory Pointer of the program factory (ProgramFactory*)
1095 */
1096 static inline void registerFactory(ProgramFactory* factory) {
1097 auto& entry = getFactoryRegistry()[factory->name];
1098 assert(!entry && "double-linked/defined souffle analyis");
1099 entry = factory;
1100 }
1101
1102 /**
1103 * Find a factory by its name, return the fatory if found, return nullptr if the
1104 * factory not found.
1105 *
1106 * @param factoryName The factory name (const std::string)
1107 * @return The pointer of the target program factory, or null pointer if the program factory not found
1108 * (ProgramFactory*)
1109 */
1110 static inline ProgramFactory* find(const std::string& factoryName) {
1111 const auto& reg = getFactoryRegistry();
1112 auto pos = reg.find(factoryName);
1113 return (pos == reg.end()) ? nullptr : pos->second;
1114 }
1115
1116 /**
1117 * Create new instance (abstract).
1118 */
1119 virtual SouffleProgram* newInstance() = 0;
1120
1121public:
1122 /**
1123 * Destructor.
1124 *
1125 * Destructor of ProgramFactory.
1126 */
1127 virtual ~ProgramFactory() = default;
1128
1129 /**
1130 * Create an instance by finding the name of the program factory, return nullptr if the instance not
1131 * found.
1132 *
1133 * @param name Instance name (const std::string)
1134 * @return The new instance(SouffleProgram*), or null pointer if the instance not found
1135 */
1136 static SouffleProgram* newInstance(const std::string& name) {
1137 ProgramFactory* factory = find(name);
1138 if (factory != nullptr) {
1139 return factory->newInstance();
1140 } else {
1141 return nullptr;
1142 }
1143 }
1144};
1145} // namespace souffle