kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/cxx/verifier/souffle_entrysteam_support.cc (about) 1 /* 2 * Copyright 2020 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "absl/base/no_destructor.h" 18 #include "google/protobuf/io/coded_stream.h" 19 #include "google/protobuf/io/zero_copy_stream.h" 20 #include "google/protobuf/io/zero_copy_stream_impl.h" 21 #include "kythe/proto/storage.pb.h" 22 // clang-format off 23 // IOSystem.h depends on ContainerUtil.h without transitively including it. 24 #include "souffle/utility/ContainerUtil.h" 25 #include "souffle/io/IOSystem.h" 26 // clang-format on 27 28 namespace kythe { 29 namespace { 30 31 /// Number of elements in the vname representation and their offsets. 32 constexpr int kVNameElements = 5; 33 constexpr int kSignatureEntry = 0; 34 constexpr int kCorpusEntry = 1; 35 constexpr int kPathEntry = 2; 36 constexpr int kRootEntry = 3; 37 constexpr int kLanguageEntry = 4; 38 /// Number of elements in the entry representation and their offsets. 39 constexpr int kEntryElements = 4; 40 constexpr int kSourceEntry = 0; 41 constexpr int kKindEntry = 1; 42 constexpr int kTargetEntry = 2; 43 constexpr int kValueEntry = 3; 44 45 class KytheEntryStreamReadStream : public souffle::ReadStream { 46 public: 47 explicit KytheEntryStreamReadStream( 48 const std::map<std::string, std::string>& rw_operation, 49 souffle::SymbolTable& symbol_table, souffle::RecordTable& record_table) 50 : souffle::ReadStream(rw_operation, symbol_table, record_table), 51 raw_input_(STDIN_FILENO) { 52 // Check that the relation has the correct type. 53 if (typeAttributes.size() == kEntryElements && 54 typeAttributes[0] == "r:vname" && typeAttributes[1] == "s:symbol" && 55 typeAttributes[2] == "r:vname" && typeAttributes[3] == "s:symbol") { 56 const auto& record_info = types["records"]["r:vname"]; 57 size_t arity = record_info["arity"].long_value(); 58 const auto& types = record_info["types"]; 59 if (arity == kVNameElements) { 60 relation_ok_ = true; 61 for (size_t i = 0; i < arity; ++i) { 62 if (types[i].string_value() != "s:symbol") { 63 relation_ok_ = false; 64 break; 65 } 66 } 67 } 68 } 69 if (!relation_ok_) { 70 fprintf(stderr, R"(error: bad relation for kythe_entrystream. Use: 71 72 .type vname = [ 73 signature:symbol, 74 corpus:symbol, 75 path:symbol, 76 root:symbol, 77 language:symbol 78 ] 79 80 .decl entry(source:vname, kind:symbol, target:vname, value:symbol) 81 82 Note that this is an experimental feature and this declaration may change. 83 )"); 84 } 85 empty_symbol_ = symbolTable.unsafeEncode(""); 86 std::array<souffle::RamDomain, 5> fields = {empty_symbol_, empty_symbol_, 87 empty_symbol_, empty_symbol_, 88 empty_symbol_}; 89 empty_vname_ = record_table.pack(fields.data(), fields.size()); 90 } 91 92 protected: 93 souffle::Own<souffle::RamDomain[]> readNextTuple() override { 94 if (!relation_ok_) { 95 return nullptr; 96 } 97 google::protobuf::uint32 byte_size; 98 google::protobuf::io::CodedInputStream coded_input(&raw_input_); 99 coded_input.SetTotalBytesLimit(INT_MAX); 100 if (!coded_input.ReadVarint32(&byte_size)) { 101 return nullptr; 102 } 103 coded_input.PushLimit(byte_size); 104 kythe::proto::Entry entry; 105 if (!entry.ParseFromCodedStream(&coded_input)) { 106 fprintf(stderr, "error reading input stream\n"); 107 return nullptr; 108 } 109 auto tuple = std::make_unique<souffle::RamDomain[]>(kEntryElements); 110 souffle::RamDomain vname[kVNameElements]; 111 CopyVName(entry.source(), vname); 112 tuple[kSourceEntry] = recordTable.pack(vname, kVNameElements); 113 if (entry.has_target()) { 114 tuple[kKindEntry] = symbolTable.unsafeEncode(entry.edge_kind()); 115 CopyVName(entry.target(), vname); 116 tuple[kTargetEntry] = recordTable.pack(vname, kVNameElements); 117 tuple[kValueEntry] = empty_symbol_; 118 } else { 119 tuple[kKindEntry] = symbolTable.unsafeEncode(entry.fact_name()); 120 tuple[kTargetEntry] = empty_vname_; 121 tuple[kValueEntry] = symbolTable.unsafeEncode(entry.fact_value()); 122 } 123 124 return tuple; 125 } 126 127 private: 128 /// Copies the fields from `vname` to `target`. 129 void CopyVName(const kythe::proto::VName& vname, souffle::RamDomain* target) { 130 target[kSignatureEntry] = symbolTable.unsafeEncode(vname.signature()); 131 target[kCorpusEntry] = symbolTable.unsafeEncode(vname.corpus()); 132 target[kPathEntry] = symbolTable.unsafeEncode(vname.path()); 133 target[kRootEntry] = symbolTable.unsafeEncode(vname.root()); 134 target[kLanguageEntry] = symbolTable.unsafeEncode(vname.language()); 135 } 136 /// This `FileInputStream` reads from stdin. 137 google::protobuf::io::FileInputStream raw_input_; 138 /// True when the relation we're reading has the expected type. 139 bool relation_ok_ = false; 140 /// The empty symbol. 141 souffle::RamDomain empty_symbol_; 142 /// An empty VName. 143 souffle::RamDomain empty_vname_; 144 }; 145 146 class KytheEntryStreamReadFactory : public souffle::ReadStreamFactory { 147 public: 148 souffle::Own<souffle::ReadStream> getReader( 149 const std::map<std::string, std::string>& rw_operation, 150 souffle::SymbolTable& symbol_table, 151 souffle::RecordTable& record_table) override { 152 return souffle::mk<KytheEntryStreamReadStream>(rw_operation, symbol_table, 153 record_table); 154 } 155 156 const std::string& getName() const override { 157 static absl::NoDestructor<std::string> name("kythe_entrystream"); 158 return *name; 159 } 160 }; 161 162 struct AutoRegisterReader { 163 AutoRegisterReader() { 164 souffle::IOSystem::getInstance().registerReadStreamFactory( 165 std::make_shared<KytheEntryStreamReadFactory>()); 166 } 167 } register_reader; 168 169 } // anonymous namespace 170 } // namespace kythe