| 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
|