Back to home page

EIC code displayed by LXR

 
 

    


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 // Protocol Buffers - Google's data interchange format
0002 // Copyright 2008 Google Inc.  All rights reserved.
0003 //
0004 // Use of this source code is governed by a BSD-style
0005 // license that can be found in the LICENSE file or at
0006 // https://developers.google.com/open-source/licenses/bsd
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 // Must be included last.
0021 #include "google/protobuf/port_def.inc"
0022 
0023 namespace google {
0024 namespace protobuf {
0025 namespace compiler {
0026 
0027 // Description of each strongly connected component. Note that the order
0028 // of both the descriptors in this SCC and the order of children is
0029 // deterministic.
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   // All messages must necessarily be in the same file.
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 // This class is used for analyzing the SCC for each message, to ensure linear
0046 // instead of quadratic performance, if we do this per message we would get
0047 // O(V*(V+E)).
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;  // if null it means its still on the stack
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   // Tarjan's Strongly Connected Components algo
0083   NodeData DFS(const Descriptor* descriptor) {
0084     // Mark visited by inserting in map.
0085     auto ins = cache_.try_emplace(descriptor, absl::make_unique<NodeData>());
0086     // Must not have visited already.
0087     ABSL_DCHECK(ins.second);
0088     NodeData& result = *ins.first->second;
0089     // Initialize data structures.
0090     result.index = result.lowlink = index_++;
0091     stack_.push_back(descriptor);
0092 
0093     // Recurse the fields / nodes in graph
0094     for (const auto* dep : DepsGenerator()(descriptor)) {
0095       ABSL_CHECK(dep);
0096       auto it = cache_.find(dep);
0097       if (it == cache_.end()) {
0098         // unexplored node
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           // Still in the stack_ so we found a back edge
0105           result.lowlink = std::min(result.lowlink, child_data.index);
0106         }
0107       }
0108     }
0109     if (result.index == result.lowlink) {
0110       // This is the root of a strongly connected component
0111       SCC* scc = CreateSCC();
0112       while (true) {
0113         const Descriptor* scc_desc = stack_.back();
0114         scc->descriptors.push_back(scc_desc);
0115         // Remove from stack
0116         stack_.pop_back();
0117         cache_[scc_desc]->scc = scc;
0118 
0119         if (scc_desc == descriptor) break;
0120       }
0121 
0122       // The order of descriptors is random and depends how this SCC was
0123       // discovered. In-order to ensure maximum stability we sort it by name.
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   // Add the SCC's that are children of this SCC to its children.
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 }  // namespace compiler
0150 }  // namespace protobuf
0151 }  // namespace google
0152 
0153 #include "google/protobuf/port_undef.inc"
0154 
0155 #endif  // GOOGLE_PROTOBUF_COMPILER_SCC_H__