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

204 lines, 122 significant
1/*
2 * Souffle - A Datalog Compiler
3 * Copyright (c) 2021, 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 WriteStream.h
12 *
13 ***********************************************************************/
14
15#pragma once
16
17#include "souffle/RamTypes.h"
18#include "souffle/RecordTable.h"
19#include "souffle/SymbolTable.h"
20#include "souffle/io/SerialisationStream.h"
21#include "souffle/utility/MiscUtil.h"
22#include "souffle/utility/json11.h"
23#include <cassert>
24#include <cstddef>
25#include <iomanip>
26#include <map>
27#include <memory>
28#include <ostream>
29#include <string>
30
31namespace souffle {
32
33using json11::Json;
34
35class WriteStream : public SerialisationStream<true> {
36public:
37 WriteStream(const std::map<std::string, std::string>& rwOperation, const SymbolTable& symbolTable,
38 const RecordTable& recordTable)
39 : SerialisationStream(symbolTable, recordTable, rwOperation),
40 summary(rwOperation.at("IO") == "stdoutprintsize") {}
41
42 template <typename T>
43 void writeAll(const T& relation) {
44 if (summary) {
45 return writeSize(relation.size());
46 }
47 if (arity == 0) {
48 if (relation.begin() != relation.end()) {
49 writeNullary();
50 }
51 return;
52 }
53 for (const auto& current : relation) {
54 writeNext(current);
55 }
56 }
57
58 template <typename T>
59 void writeSize(const T& relation) {
60 writeSize(relation.size());
61 }
62
63protected:
64 const bool summary;
65
66 virtual void writeNullary() = 0;
67 virtual void writeNextTuple(const RamDomain* tuple) = 0;
68 virtual void writeSize(std::size_t) {
69 fatal("attempting to print size of a write operation");
70 }
71
72 template <typename Tuple>
73 void writeNext(const Tuple tuple) {
74 using tcb::make_span;
75 writeNextTuple(make_span(tuple).data());
76 }
77
78 virtual void outputSymbol(std::ostream& destination, const std::string& value) {
79 destination << value;
80 }
81
82 void outputRecord(std::ostream& destination, const RamDomain value, const std::string& name) {
83 auto&& recordInfo = types["records"][name];
84
85 // Check if record type information are present
86 assert(!recordInfo.is_null() && "Missing record type information");
87
88 // Check for nil
89 if (value == 0) {
90 destination << "nil";
91 return;
92 }
93
94 auto&& recordTypes = recordInfo["types"];
95 const std::size_t recordArity = recordInfo["arity"].long_value();
96
97 const RamDomain* tuplePtr = recordTable.unpack(value, recordArity);
98
99 destination << "[";
100
101 // print record's elements
102 for (std::size_t i = 0; i < recordArity; ++i) {
103 if (i > 0) {
104 destination << ", ";
105 }
106
107 const std::string& recordType = recordTypes[i].string_value();
108 const RamDomain recordValue = tuplePtr[i];
109
110 switch (recordType[0]) {
111 case 'i': destination << recordValue; break;
112 case 'f': destination << ramBitCast<RamFloat>(recordValue); break;
113 case 'u': destination << ramBitCast<RamUnsigned>(recordValue); break;
114 case 's': outputSymbol(destination, symbolTable.decode(recordValue)); break;
115 case 'r': outputRecord(destination, recordValue, recordType); break;
116 case '+': outputADT(destination, recordValue, recordType); break;
117 default: fatal("Unsupported type attribute: `%c`", recordType[0]);
118 }
119 }
120 destination << "]";
121 }
122
123 void outputADT(std::ostream& destination, const RamDomain value, const std::string& name) {
124 auto&& adtInfo = types["ADTs"][name];
125
126 assert(!adtInfo.is_null() && "Missing adt type information");
127 assert(adtInfo["arity"].long_value() > 0);
128
129 // adt is encoded in one of three possible ways:
130 // [branchID, [branch_args]] when |branch_args| != 1
131 // [branchID, arg] when a branch takes a single argument.
132 // branchID when ADT is an enumeration.
133 bool isEnum = adtInfo["enum"].bool_value();
134
135 RamDomain branchId = value;
136 const RamDomain* branchArgs = nullptr;
137 json11::Json branchInfo;
138 json11::Json::array branchTypes;
139
140 if (!isEnum) {
141 const RamDomain* tuplePtr = recordTable.unpack(value, 2);
142
143 branchId = tuplePtr[0];
144 branchInfo = adtInfo["branches"][branchId];
145 branchTypes = branchInfo["types"].array_items();
146
147 // Prepare branch's arguments for output.
148 branchArgs = [&]() -> const RamDomain* {
149 if (branchTypes.size() > 1) {
150 return recordTable.unpack(tuplePtr[1], branchTypes.size());
151 } else {
152 return &tuplePtr[1];
153 }
154 }();
155 } else {
156 branchInfo = adtInfo["branches"][branchId];
157 branchTypes = branchInfo["types"].array_items();
158 }
159
160 destination << "$" << branchInfo["name"].string_value();
161
162 if (branchTypes.size() > 0) {
163 destination << "(";
164 }
165
166 // Print arguments
167 for (std::size_t i = 0; i < branchTypes.size(); ++i) {
168 if (i > 0) {
169 destination << ", ";
170 }
171
172 auto argType = branchTypes[i].string_value();
173 switch (argType[0]) {
174 case 'i': destination << branchArgs[i]; break;
175 case 'f': destination << ramBitCast<RamFloat>(branchArgs[i]); break;
176 case 'u': destination << ramBitCast<RamUnsigned>(branchArgs[i]); break;
177 case 's': outputSymbol(destination, symbolTable.decode(branchArgs[i])); break;
178 case 'r': outputRecord(destination, branchArgs[i], argType); break;
179 case '+': outputADT(destination, branchArgs[i], argType); break;
180 default: fatal("Unsupported type attribute: `%c`", argType[0]);
181 }
182 }
183
184 if (branchTypes.size() > 0) {
185 destination << ")";
186 }
187 }
188};
189
190class WriteStreamFactory {
191public:
192 virtual Own<WriteStream> getWriter(const std::map<std::string, std::string>& rwOperation,
193 const SymbolTable& symbolTable, const RecordTable& recordTable) = 0;
194
195 virtual const std::string& getName() const = 0;
196 virtual ~WriteStreamFactory() = default;
197};
198
199template <>
200inline void WriteStream::writeNext(const RamDomain* tuple) {
201 writeNextTuple(tuple);
202}
203
204} /* namespace souffle */