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