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

112 lines, 63 significant
1/*
2 * Souffle - A Datalog Compiler
3 * Copyright (c) 2020, The Souffle Developers. All rights reserved.
4 * Licensed under the Universal Permissive License v 1.0 as shown at:
5 * - https://opensource.org/licenses/UPL
6 * - <souffle root>/licenses/SOUFFLE-UPL.txt
7 */
8
9/************************************************************************
10 *
11 * @file EvaluatorUtils.h
12 *
13 * Defines utility functions used by synthesised and interpreter code.
14 *
15 ***********************************************************************/
16
17#pragma once
18
19#include "souffle/RamTypes.h"
20#include "souffle/utility/StringUtil.h"
21#include "souffle/utility/tinyformat.h"
22#include <csignal>
23
24namespace souffle::evaluator {
25
26template <typename A, typename F /* Tuple<RamDomain,1> -> void */>
27void runRange(const A from, const A to, const A step, F&& go) {
28#define GO(x) go(Tuple<RamDomain, 1>{ramBitCast(x)})
29 if (0 < step) {
30 for (auto x = from; x < to; x += step) {
31 GO(x);
32 }
33 } else if (step < 0) {
34 for (auto x = from; to < x; x += step) {
35 GO(x);
36 }
37 } else if (from != to) {
38 // `step = 0` edge case, only if non-empty range
39 GO(from);
40 }
41#undef GO
42}
43
44template <typename A, typename F /* Tuple<RamDomain,1> -> void */>
45void runRangeBackward(const A from, const A to, F&& func) {
46 assert(from > to);
47 if (from > to) {
48 for (auto x = from; x > to; --x) {
49 func(Tuple<RamDomain, 1>{ramBitCast(x)});
50 }
51 }
52}
53
54template <typename A, typename F /* Tuple<RamDomain,1> -> void */>
55void runRange(const A from, const A to, F&& go) {
56 if constexpr (std::is_unsigned<A>()) {
57 if (from <= to) {
58 runRange(from, to, static_cast<A>(1U), std::forward<F>(go));
59 } else {
60 runRangeBackward(from, to, std::forward<F>(go));
61 }
62 } else {
63 return runRange(from, to, A(from <= to ? 1 : -1), std::forward<F>(go));
64 }
65}
66
67template <typename A>
68A symbol2numeric(const std::string& src) {
69 try {
70 if constexpr (std::is_same_v<RamFloat, A>) {
71 return RamFloatFromString(src);
72 } else if constexpr (std::is_same_v<RamSigned, A>) {
73 return RamSignedFromString(src, nullptr, 0);
74 } else if constexpr (std::is_same_v<RamUnsigned, A>) {
75 return RamUnsignedFromString(src, nullptr, 0);
76 } else {
77 static_assert(sizeof(A) == 0, "Invalid type specified for symbol2Numeric");
78 }
79
80 } catch (...) {
81 tfm::format(std::cerr, "error: wrong string provided by `to_number(\"%s\")` functor.\n", src);
82 raise(SIGFPE);
83 abort(); // UNREACHABLE: `raise` lacks a no-return attribute
84 }
85};
86
87template <typename A>
88bool lxor(A x, A y) {
89 return (x || y) && (!x != !y);
90}
91
92// HACK: C++ doesn't have an infix logical xor operator.
93// C++ doesn't allow defining new infix operators.
94// C++ isn't a very nice language, but C++ does allow overload-based war crimes.
95// This particular war crime allows a very verbose infix op for `lxor`.
96// It should only be used in macro dispatches.
97struct lxor_infix {
98 template <typename A>
99 struct curry {
100 A x;
101 bool operator+(A y) const {
102 return lxor(x, y);
103 }
104 };
105};
106
107template <typename A>
108lxor_infix::curry<A> operator+(A x, lxor_infix) {
109 return lxor_infix::curry<A>{x};
110}
111
112} // namespace souffle::evaluator