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