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 |
|
39 | namespace souffle {
|
40 |
|
41 | class tuple;
|
42 |
|
43 | /**
|
44 | * Object-oriented wrapper class for Souffle's templatized relations.
|
45 | */
|
46 | class Relation {
|
47 | public:
|
48 | using arity_type = std::size_t;
|
49 |
|
50 | protected:
|
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 |
|
147 | public:
|
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 | */
|
444 | class 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 |
|
466 | public:
|
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 | */
|
696 | class SouffleProgram {
|
697 | protected:
|
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 |
|
772 | public:
|
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 | */
|
1045 | class ProgramFactory {
|
1046 | protected:
|
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 |
|
1064 | protected:
|
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 |
|
1075 | private:
|
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 |
|
1090 | protected:
|
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 |
|
1121 | public:
|
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
|