|
||||
File indexing completed on 2025-01-31 10:12:19
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 // Author: kenton@google.com (Kenton Varda) 0009 // Based on original Protocol Buffers design by 0010 // Sanjay Ghemawat, Jeff Dean, and others. 0011 // 0012 // Interface for manipulating databases of descriptors. 0013 0014 #ifndef GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__ 0015 #define GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__ 0016 0017 #include <string> 0018 #include <utility> 0019 #include <vector> 0020 0021 #include "absl/container/btree_map.h" 0022 #include "google/protobuf/descriptor.h" 0023 #include "google/protobuf/port.h" 0024 0025 // Must be included last. 0026 #include "google/protobuf/port_def.inc" 0027 0028 #ifdef SWIG 0029 #error "You cannot SWIG proto headers" 0030 #endif 0031 0032 namespace google { 0033 namespace protobuf { 0034 0035 // Defined in this file. 0036 class DescriptorDatabase; 0037 class SimpleDescriptorDatabase; 0038 class EncodedDescriptorDatabase; 0039 class DescriptorPoolDatabase; 0040 class MergedDescriptorDatabase; 0041 0042 // Abstract interface for a database of descriptors. 0043 // 0044 // This is useful if you want to create a DescriptorPool which loads 0045 // descriptors on-demand from some sort of large database. If the database 0046 // is large, it may be inefficient to enumerate every .proto file inside it 0047 // calling DescriptorPool::BuildFile() for each one. Instead, a DescriptorPool 0048 // can be created which wraps a DescriptorDatabase and only builds particular 0049 // descriptors when they are needed. 0050 class PROTOBUF_EXPORT DescriptorDatabase { 0051 public: 0052 inline DescriptorDatabase() {} 0053 DescriptorDatabase(const DescriptorDatabase&) = delete; 0054 DescriptorDatabase& operator=(const DescriptorDatabase&) = delete; 0055 virtual ~DescriptorDatabase(); 0056 0057 // Find a file by file name. Fills in in *output and returns true if found. 0058 // Otherwise, returns false, leaving the contents of *output undefined. 0059 virtual bool FindFileByName(const std::string& filename, 0060 FileDescriptorProto* output) = 0; 0061 0062 // Find the file that declares the given fully-qualified symbol name. 0063 // If found, fills in *output and returns true, otherwise returns false 0064 // and leaves *output undefined. 0065 virtual bool FindFileContainingSymbol(const std::string& symbol_name, 0066 FileDescriptorProto* output) = 0; 0067 0068 // Find the file which defines an extension extending the given message type 0069 // with the given field number. If found, fills in *output and returns true, 0070 // otherwise returns false and leaves *output undefined. containing_type 0071 // must be a fully-qualified type name. 0072 virtual bool FindFileContainingExtension(const std::string& containing_type, 0073 int field_number, 0074 FileDescriptorProto* output) = 0; 0075 0076 // Finds the tag numbers used by all known extensions of 0077 // extendee_type, and appends them to output in an undefined 0078 // order. This method is best-effort: it's not guaranteed that the 0079 // database will find all extensions, and it's not guaranteed that 0080 // FindFileContainingExtension will return true on all of the found 0081 // numbers. Returns true if the search was successful, otherwise 0082 // returns false and leaves output unchanged. 0083 // 0084 // This method has a default implementation that always returns 0085 // false. 0086 virtual bool FindAllExtensionNumbers(const std::string& /* extendee_type */, 0087 std::vector<int>* /* output */) { 0088 return false; 0089 } 0090 0091 0092 // Finds the file names and appends them to the output in an 0093 // undefined order. This method is best-effort: it's not guaranteed that the 0094 // database will find all files. Returns true if the database supports 0095 // searching all file names, otherwise returns false and leaves output 0096 // unchanged. 0097 // 0098 // This method has a default implementation that always returns 0099 // false. 0100 virtual bool FindAllFileNames(std::vector<std::string>* /*output*/) { 0101 return false; 0102 } 0103 0104 // Finds the package names and appends them to the output in an 0105 // undefined order. This method is best-effort: it's not guaranteed that the 0106 // database will find all packages. Returns true if the database supports 0107 // searching all package names, otherwise returns false and leaves output 0108 // unchanged. 0109 bool FindAllPackageNames(std::vector<std::string>* output); 0110 0111 // Finds the message names and appends them to the output in an 0112 // undefined order. This method is best-effort: it's not guaranteed that the 0113 // database will find all messages. Returns true if the database supports 0114 // searching all message names, otherwise returns false and leaves output 0115 // unchanged. 0116 bool FindAllMessageNames(std::vector<std::string>* output); 0117 }; 0118 0119 // A DescriptorDatabase into which you can insert files manually. 0120 // 0121 // FindFileContainingSymbol() is fully-implemented. When you add a file, its 0122 // symbols will be indexed for this purpose. Note that the implementation 0123 // may return false positives, but only if it isn't possible for the symbol 0124 // to be defined in any other file. In particular, if a file defines a symbol 0125 // "Foo", then searching for "Foo.[anything]" will match that file. This way, 0126 // the database does not need to aggressively index all children of a symbol. 0127 // 0128 // FindFileContainingExtension() is mostly-implemented. It works if and only 0129 // if the original FieldDescriptorProto defining the extension has a 0130 // fully-qualified type name in its "extendee" field (i.e. starts with a '.'). 0131 // If the extendee is a relative name, SimpleDescriptorDatabase will not 0132 // attempt to resolve the type, so it will not know what type the extension is 0133 // extending. Therefore, calling FindFileContainingExtension() with the 0134 // extension's containing type will never actually find that extension. Note 0135 // that this is an unlikely problem, as all FileDescriptorProtos created by the 0136 // protocol compiler (as well as ones created by calling 0137 // FileDescriptor::CopyTo()) will always use fully-qualified names for all 0138 // types. You only need to worry if you are constructing FileDescriptorProtos 0139 // yourself, or are calling compiler::Parser directly. 0140 class PROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase { 0141 public: 0142 SimpleDescriptorDatabase(); 0143 SimpleDescriptorDatabase(const SimpleDescriptorDatabase&) = delete; 0144 SimpleDescriptorDatabase& operator=(const SimpleDescriptorDatabase&) = delete; 0145 ~SimpleDescriptorDatabase() override; 0146 0147 // Adds the FileDescriptorProto to the database, making a copy. The object 0148 // can be deleted after Add() returns. Returns false if the file conflicted 0149 // with a file already in the database, in which case an error will have 0150 // been written to ABSL_LOG(ERROR). 0151 bool Add(const FileDescriptorProto& file); 0152 0153 // Adds the FileDescriptorProto to the database and takes ownership of it. 0154 bool AddAndOwn(const FileDescriptorProto* file); 0155 0156 // Adds the FileDescriptorProto to the database and not take ownership of it. 0157 // The owner must ensure file outlives the SimpleDescriptorDatabase. 0158 bool AddUnowned(const FileDescriptorProto* file); 0159 0160 // implements DescriptorDatabase ----------------------------------- 0161 bool FindFileByName(const std::string& filename, 0162 FileDescriptorProto* output) override; 0163 bool FindFileContainingSymbol(const std::string& symbol_name, 0164 FileDescriptorProto* output) override; 0165 bool FindFileContainingExtension(const std::string& containing_type, 0166 int field_number, 0167 FileDescriptorProto* output) override; 0168 bool FindAllExtensionNumbers(const std::string& extendee_type, 0169 std::vector<int>* output) override; 0170 0171 bool FindAllFileNames(std::vector<std::string>* output) override; 0172 0173 private: 0174 // An index mapping file names, symbol names, and extension numbers to 0175 // some sort of values. 0176 template <typename Value> 0177 class DescriptorIndex { 0178 public: 0179 // Helpers to recursively add particular descriptors and all their contents 0180 // to the index. 0181 bool AddFile(const FileDescriptorProto& file, Value value); 0182 bool AddSymbol(absl::string_view name, Value value); 0183 bool AddNestedExtensions(const std::string& filename, 0184 const DescriptorProto& message_type, Value value); 0185 bool AddExtension(const std::string& filename, 0186 const FieldDescriptorProto& field, Value value); 0187 0188 Value FindFile(const std::string& filename); 0189 Value FindSymbol(const std::string& name); 0190 Value FindExtension(const std::string& containing_type, int field_number); 0191 bool FindAllExtensionNumbers(const std::string& containing_type, 0192 std::vector<int>* output); 0193 void FindAllFileNames(std::vector<std::string>* output); 0194 0195 private: 0196 absl::btree_map<std::string, Value> by_name_; 0197 absl::btree_map<std::string, Value> by_symbol_; 0198 absl::btree_map<std::pair<std::string, int>, Value> by_extension_; 0199 0200 // Invariant: The by_symbol_ map does not contain any symbols which are 0201 // prefixes of other symbols in the map. For example, "foo.bar" is a 0202 // prefix of "foo.bar.baz" (but is not a prefix of "foo.barbaz"). 0203 // 0204 // This invariant is important because it means that given a symbol name, 0205 // we can find a key in the map which is a prefix of the symbol in O(lg n) 0206 // time, and we know that there is at most one such key. 0207 // 0208 // The prefix lookup algorithm works like so: 0209 // 1) Find the last key in the map which is less than or equal to the 0210 // search key. 0211 // 2) If the found key is a prefix of the search key, then return it. 0212 // Otherwise, there is no match. 0213 // 0214 // I am sure this algorithm has been described elsewhere, but since I 0215 // wasn't able to find it quickly I will instead prove that it works 0216 // myself. The key to the algorithm is that if a match exists, step (1) 0217 // will find it. Proof: 0218 // 1) Define the "search key" to be the key we are looking for, the "found 0219 // key" to be the key found in step (1), and the "match key" to be the 0220 // key which actually matches the search key (i.e. the key we're trying 0221 // to find). 0222 // 2) The found key must be less than or equal to the search key by 0223 // definition. 0224 // 3) The match key must also be less than or equal to the search key 0225 // (because it is a prefix). 0226 // 4) The match key cannot be greater than the found key, because if it 0227 // were, then step (1) of the algorithm would have returned the match 0228 // key instead (since it finds the *greatest* key which is less than or 0229 // equal to the search key). 0230 // 5) Therefore, the found key must be between the match key and the search 0231 // key, inclusive. 0232 // 6) Since the search key must be a sub-symbol of the match key, if it is 0233 // not equal to the match key, then search_key[match_key.size()] must 0234 // be '.'. 0235 // 7) Since '.' sorts before any other character that is valid in a symbol 0236 // name, then if the found key is not equal to the match key, then 0237 // found_key[match_key.size()] must also be '.', because any other value 0238 // would make it sort after the search key. 0239 // 8) Therefore, if the found key is not equal to the match key, then the 0240 // found key must be a sub-symbol of the match key. However, this would 0241 // contradict our map invariant which says that no symbol in the map is 0242 // a sub-symbol of any other. 0243 // 9) Therefore, the found key must match the match key. 0244 // 0245 // The above proof assumes the match key exists. In the case that the 0246 // match key does not exist, then step (1) will return some other symbol. 0247 // That symbol cannot be a super-symbol of the search key since if it were, 0248 // then it would be a match, and we're assuming the match key doesn't exist. 0249 // Therefore, step 2 will correctly return no match. 0250 }; 0251 0252 DescriptorIndex<const FileDescriptorProto*> index_; 0253 std::vector<std::unique_ptr<const FileDescriptorProto>> files_to_delete_; 0254 0255 // If file is non-nullptr, copy it into *output and return true, otherwise 0256 // return false. 0257 bool MaybeCopy(const FileDescriptorProto* file, FileDescriptorProto* output); 0258 }; 0259 0260 // Very similar to SimpleDescriptorDatabase, but stores all the descriptors 0261 // as raw bytes and generally tries to use as little memory as possible. 0262 // 0263 // The same caveats regarding FindFileContainingExtension() apply as with 0264 // SimpleDescriptorDatabase. 0265 class PROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase { 0266 public: 0267 EncodedDescriptorDatabase(); 0268 EncodedDescriptorDatabase(const EncodedDescriptorDatabase&) = delete; 0269 EncodedDescriptorDatabase& operator=(const EncodedDescriptorDatabase&) = 0270 delete; 0271 ~EncodedDescriptorDatabase() override; 0272 0273 // Adds the FileDescriptorProto to the database. The descriptor is provided 0274 // in encoded form. The database does not make a copy of the bytes, nor 0275 // does it take ownership; it's up to the caller to make sure the bytes 0276 // remain valid for the life of the database. Returns false and logs an error 0277 // if the bytes are not a valid FileDescriptorProto or if the file conflicted 0278 // with a file already in the database. 0279 bool Add(const void* encoded_file_descriptor, int size); 0280 0281 // Like Add(), but makes a copy of the data, so that the caller does not 0282 // need to keep it around. 0283 bool AddCopy(const void* encoded_file_descriptor, int size); 0284 0285 // Like FindFileContainingSymbol but returns only the name of the file. 0286 bool FindNameOfFileContainingSymbol(const std::string& symbol_name, 0287 std::string* output); 0288 0289 // implements DescriptorDatabase ----------------------------------- 0290 bool FindFileByName(const std::string& filename, 0291 FileDescriptorProto* output) override; 0292 bool FindFileContainingSymbol(const std::string& symbol_name, 0293 FileDescriptorProto* output) override; 0294 bool FindFileContainingExtension(const std::string& containing_type, 0295 int field_number, 0296 FileDescriptorProto* output) override; 0297 bool FindAllExtensionNumbers(const std::string& extendee_type, 0298 std::vector<int>* output) override; 0299 bool FindAllFileNames(std::vector<std::string>* output) override; 0300 0301 private: 0302 class DescriptorIndex; 0303 // Keep DescriptorIndex by pointer to hide the implementation to keep a 0304 // cleaner header. 0305 std::unique_ptr<DescriptorIndex> index_; 0306 std::vector<void*> files_to_delete_; 0307 0308 // If encoded_file.first is non-nullptr, parse the data into *output and 0309 // return true, otherwise return false. 0310 bool MaybeParse(std::pair<const void*, int> encoded_file, 0311 FileDescriptorProto* output); 0312 }; 0313 0314 struct PROTOBUF_EXPORT DescriptorPoolDatabaseOptions { 0315 // If true, the database will preserve source code info when returning 0316 // descriptors. 0317 bool preserve_source_code_info = false; 0318 }; 0319 0320 // A DescriptorDatabase that fetches files from a given pool. 0321 class PROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase { 0322 public: 0323 explicit DescriptorPoolDatabase(const DescriptorPool& pool, 0324 DescriptorPoolDatabaseOptions options = {}); 0325 DescriptorPoolDatabase(const DescriptorPoolDatabase&) = delete; 0326 DescriptorPoolDatabase& operator=(const DescriptorPoolDatabase&) = delete; 0327 ~DescriptorPoolDatabase() override; 0328 0329 // implements DescriptorDatabase ----------------------------------- 0330 bool FindFileByName(const std::string& filename, 0331 FileDescriptorProto* output) override; 0332 bool FindFileContainingSymbol(const std::string& symbol_name, 0333 FileDescriptorProto* output) override; 0334 bool FindFileContainingExtension(const std::string& containing_type, 0335 int field_number, 0336 FileDescriptorProto* output) override; 0337 bool FindAllExtensionNumbers(const std::string& extendee_type, 0338 std::vector<int>* output) override; 0339 0340 private: 0341 const DescriptorPool& pool_; 0342 DescriptorPoolDatabaseOptions options_; 0343 }; 0344 0345 // A DescriptorDatabase that wraps two or more others. It first searches the 0346 // first database and, if that fails, tries the second, and so on. 0347 class PROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase { 0348 public: 0349 // Merge just two databases. The sources remain property of the caller. 0350 MergedDescriptorDatabase(DescriptorDatabase* source1, 0351 DescriptorDatabase* source2); 0352 // Merge more than two databases. The sources remain property of the caller. 0353 // The vector may be deleted after the constructor returns but the 0354 // DescriptorDatabases need to stick around. 0355 explicit MergedDescriptorDatabase( 0356 const std::vector<DescriptorDatabase*>& sources); 0357 MergedDescriptorDatabase(const MergedDescriptorDatabase&) = delete; 0358 MergedDescriptorDatabase& operator=(const MergedDescriptorDatabase&) = delete; 0359 ~MergedDescriptorDatabase() override; 0360 0361 // implements DescriptorDatabase ----------------------------------- 0362 bool FindFileByName(const std::string& filename, 0363 FileDescriptorProto* output) override; 0364 bool FindFileContainingSymbol(const std::string& symbol_name, 0365 FileDescriptorProto* output) override; 0366 bool FindFileContainingExtension(const std::string& containing_type, 0367 int field_number, 0368 FileDescriptorProto* output) override; 0369 // Merges the results of calling all databases. Returns true iff any 0370 // of the databases returned true. 0371 bool FindAllExtensionNumbers(const std::string& extendee_type, 0372 std::vector<int>* output) override; 0373 0374 0375 // This function is best-effort. Returns true if at least one underlying 0376 // DescriptorDatabase returns true. 0377 bool FindAllFileNames(std::vector<std::string>* output) override; 0378 0379 private: 0380 std::vector<DescriptorDatabase*> sources_; 0381 }; 0382 0383 } // namespace protobuf 0384 } // namespace google 0385 0386 #include "google/protobuf/port_undef.inc" 0387 0388 #endif // GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |