| // Copyright 2021 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef SRC_GN_BUILDER_RECORD_MAP_H_ | |
| #define SRC_GN_BUILDER_RECORD_MAP_H_ | |
| #include "gn/builder_record.h" | |
| #include "gn/hash_table_base.h" | |
| // This header implements a custom Label -> BuilderRecord map that is critical | |
| // for performance of the Builder class. | |
| // | |
| // Measurements show it performs better than | |
| // std::unordered_map<Label, BuilderRecord>, which itself performs much better | |
| // than base::flat_map<Label, BuilderRecord> or std::map<Label, BuilderRecord> | |
| // | |
| // NOTE: This only implements the features required by the Builder class. | |
| // | |
| struct BuilderRecordNode { | |
| BuilderRecord* record; | |
| bool is_null() const { return !record; } | |
| static constexpr bool is_tombstone() { return false; } | |
| bool is_valid() const { return !is_null() && !is_tombstone(); } | |
| size_t hash_value() const { return record->label().hash(); } | |
| }; | |
| class BuilderRecordMap : public HashTableBase<BuilderRecordNode> { | |
| public: | |
| using NodeType = BuilderRecordNode; | |
| ~BuilderRecordMap() { | |
| for (auto it = NodeBegin(); it.valid(); ++it) { | |
| delete it->record; | |
| } | |
| } | |
| // Find BuilderRecord matching |label| or return nullptr. | |
| BuilderRecord* find(const Label& label) const { | |
| return Lookup(label)->record; | |
| } | |
| // Try to find BuilderRecord matching |label|, and create one if | |
| // none is found. result.first will be true to indicate that a new | |
| // record was created. | |
| std::pair<bool, BuilderRecord*> try_emplace(const Label& label, | |
| const ParseNode* request_from, | |
| BuilderRecord::ItemType type) { | |
| NodeType* node = Lookup(label); | |
| if (node->is_valid()) { | |
| return {false, node->record}; | |
| } | |
| BuilderRecord* record = new BuilderRecord(type, label, request_from); | |
| node->record = record; | |
| UpdateAfterInsert(false); | |
| return {true, record}; | |
| } | |
| // Iteration support | |
| struct const_iterator : public NodeIterator { | |
| const BuilderRecord& operator*() const { return *node_->record; } | |
| BuilderRecord& operator*() { return *node_->record; } | |
| const BuilderRecord* operator->() const { return node_->record; } | |
| BuilderRecord* operator->() { return node_->record; } | |
| const_iterator& operator++() { | |
| NodeIterator::operator++(); | |
| return *this; | |
| } | |
| const_iterator operator++(int) { | |
| const_iterator result = *this; | |
| NodeIterator::operator++(); | |
| return result; | |
| } | |
| }; | |
| const_iterator begin() const { return {NodeBegin()}; } | |
| const_iterator end() const { return {NodeEnd()}; } | |
| private: | |
| NodeType* Lookup(const Label& label) const { | |
| return NodeLookup(label.hash(), [&label](const NodeType* node) { | |
| return node->record->label() == label; | |
| }); | |
| } | |
| }; | |
| #endif // SRC_GN_BUILDER_RECORD_MAP_H_ |