File indexing completed on 2025-01-31 10:12:01
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef GOOGLE_PROTOBUF_COMPILER_SCC_H__
0009 #define GOOGLE_PROTOBUF_COMPILER_SCC_H__
0010
0011 #include <memory>
0012
0013 #include "absl/container/flat_hash_map.h"
0014 #include "absl/container/flat_hash_set.h"
0015 #include "absl/log/absl_check.h"
0016 #include "absl/memory/memory.h"
0017 #include "google/protobuf/descriptor.h"
0018
0019
0020 #include "google/protobuf/port_def.inc"
0021
0022 namespace google {
0023 namespace protobuf {
0024 namespace compiler {
0025
0026
0027
0028
0029 struct SCC {
0030 std::vector<const Descriptor*> descriptors;
0031 std::vector<const SCC*> children;
0032
0033 const Descriptor* GetRepresentative() const { return descriptors[0]; }
0034
0035
0036 const FileDescriptor* GetFile() const { return descriptors[0]->file(); }
0037 };
0038
0039
0040
0041
0042 template <class DepsGenerator>
0043 class PROTOC_EXPORT SCCAnalyzer {
0044 public:
0045 explicit SCCAnalyzer() : index_(0) {}
0046 SCCAnalyzer(const SCCAnalyzer&) = delete;
0047 SCCAnalyzer& operator=(const SCCAnalyzer&) = delete;
0048
0049 const SCC* GetSCC(const Descriptor* descriptor) {
0050 auto it = cache_.find(descriptor);
0051 if (it == cache_.end()) {
0052 return DFS(descriptor).scc;
0053 }
0054 return it->second->scc;
0055 }
0056
0057 private:
0058 struct NodeData {
0059 const SCC* scc;
0060 int index;
0061 int lowlink;
0062 };
0063
0064 absl::flat_hash_map<const Descriptor*, std::unique_ptr<NodeData>> cache_;
0065 std::vector<const Descriptor*> stack_;
0066 int index_;
0067 std::vector<std::unique_ptr<SCC>> garbage_bin_;
0068
0069 SCC* CreateSCC() {
0070 garbage_bin_.emplace_back(new SCC());
0071 return garbage_bin_.back().get();
0072 }
0073
0074
0075 NodeData DFS(const Descriptor* descriptor) {
0076
0077 auto ins = cache_.try_emplace(descriptor, absl::make_unique<NodeData>());
0078
0079 ABSL_DCHECK(ins.second);
0080 NodeData& result = *ins.first->second;
0081
0082 result.index = result.lowlink = index_++;
0083 stack_.push_back(descriptor);
0084
0085
0086 for (const auto* dep : DepsGenerator()(descriptor)) {
0087 ABSL_CHECK(dep);
0088 auto it = cache_.find(dep);
0089 if (it == cache_.end()) {
0090
0091 NodeData child_data = DFS(dep);
0092 result.lowlink = std::min(result.lowlink, child_data.lowlink);
0093 } else {
0094 NodeData& child_data = *it->second;
0095 if (child_data.scc == nullptr) {
0096
0097 result.lowlink = std::min(result.lowlink, child_data.index);
0098 }
0099 }
0100 }
0101 if (result.index == result.lowlink) {
0102
0103 SCC* scc = CreateSCC();
0104 while (true) {
0105 const Descriptor* scc_desc = stack_.back();
0106 scc->descriptors.push_back(scc_desc);
0107
0108 stack_.pop_back();
0109 cache_[scc_desc]->scc = scc;
0110
0111 if (scc_desc == descriptor) break;
0112 }
0113
0114
0115
0116 std::sort(scc->descriptors.begin(), scc->descriptors.end(),
0117 [](const Descriptor* a, const Descriptor* b) {
0118 return a->full_name() < b->full_name();
0119 });
0120 AddChildren(scc);
0121 }
0122 return result;
0123 }
0124
0125
0126 void AddChildren(SCC* scc) {
0127 absl::flat_hash_set<const SCC*> seen;
0128 for (auto descriptor : scc->descriptors) {
0129 for (auto child_msg : DepsGenerator()(descriptor)) {
0130 ABSL_CHECK(child_msg);
0131 const SCC* child = GetSCC(child_msg);
0132 if (child == scc) continue;
0133 if (seen.insert(child).second) {
0134 scc->children.push_back(child);
0135 }
0136 }
0137 }
0138 }
0139 };
0140
0141 }
0142 }
0143 }
0144
0145 #include "google/protobuf/port_undef.inc"
0146
0147 #endif