11cb0ef41Sopenharmony_ci// Copyright 2017 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#ifndef V8_COMPILER_PERSISTENT_MAP_H_ 61cb0ef41Sopenharmony_ci#define V8_COMPILER_PERSISTENT_MAP_H_ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include <array> 91cb0ef41Sopenharmony_ci#include <tuple> 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ci#include "src/base/functional.h" 121cb0ef41Sopenharmony_ci#include "src/zone/zone-containers.h" 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cinamespace v8 { 151cb0ef41Sopenharmony_cinamespace internal { 161cb0ef41Sopenharmony_cinamespace compiler { 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ci// PersistentMap is a persistent map datastructure based on hash trees (a binary 191cb0ef41Sopenharmony_ci// tree using the bits of a hash value as addresses). The map is a conceptually 201cb0ef41Sopenharmony_ci// infinite: All keys are initially mapped to a default value, values are 211cb0ef41Sopenharmony_ci// deleted by overwriting them with the default value. The iterators produce 221cb0ef41Sopenharmony_ci// exactly the keys that are not the default value. The hash values should have 231cb0ef41Sopenharmony_ci// high variance in their high bits, so dense integers are a bad choice. 241cb0ef41Sopenharmony_ci// Complexity: 251cb0ef41Sopenharmony_ci// - Copy and assignment: O(1) 261cb0ef41Sopenharmony_ci// - access: O(log n) 271cb0ef41Sopenharmony_ci// - update: O(log n) time and space 281cb0ef41Sopenharmony_ci// - iteration: amortized O(1) per step 291cb0ef41Sopenharmony_ci// - Zip: O(n) 301cb0ef41Sopenharmony_ci// - equality check: O(n) 311cb0ef41Sopenharmony_ci// TODO(turbofan): Cache map transitions to avoid re-allocation of the same map. 321cb0ef41Sopenharmony_ci// TODO(turbofan): Implement an O(1) equality check based on hash consing or 331cb0ef41Sopenharmony_ci// something similar. 341cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher = base::hash<Key>> 351cb0ef41Sopenharmony_ciclass PersistentMap { 361cb0ef41Sopenharmony_ci public: 371cb0ef41Sopenharmony_ci using key_type = Key; 381cb0ef41Sopenharmony_ci using mapped_type = Value; 391cb0ef41Sopenharmony_ci using value_type = std::pair<Key, Value>; 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci private: 421cb0ef41Sopenharmony_ci static constexpr size_t kHashBits = 32; 431cb0ef41Sopenharmony_ci enum Bit : int { kLeft = 0, kRight = 1 }; 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci // Access hash bits starting from the high bits and compare them according to 461cb0ef41Sopenharmony_ci // their unsigned value. This way, the order in the hash tree is compatible 471cb0ef41Sopenharmony_ci // with numeric hash comparisons. 481cb0ef41Sopenharmony_ci class HashValue; 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci struct KeyValue : std::pair<Key, Value> { 511cb0ef41Sopenharmony_ci const Key& key() const { return this->first; } 521cb0ef41Sopenharmony_ci const Value& value() const { return this->second; } 531cb0ef41Sopenharmony_ci using std::pair<Key, Value>::pair; 541cb0ef41Sopenharmony_ci }; 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci struct FocusedTree; 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci public: 591cb0ef41Sopenharmony_ci // Depth of the last added element. This is a cheap estimate for the size of 601cb0ef41Sopenharmony_ci // the hash tree. 611cb0ef41Sopenharmony_ci size_t last_depth() const { 621cb0ef41Sopenharmony_ci if (tree_) { 631cb0ef41Sopenharmony_ci return tree_->length; 641cb0ef41Sopenharmony_ci } else { 651cb0ef41Sopenharmony_ci return 0; 661cb0ef41Sopenharmony_ci } 671cb0ef41Sopenharmony_ci } 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci const Value& Get(const Key& key) const { 701cb0ef41Sopenharmony_ci HashValue key_hash = HashValue(Hasher()(key)); 711cb0ef41Sopenharmony_ci const FocusedTree* tree = FindHash(key_hash); 721cb0ef41Sopenharmony_ci return GetFocusedValue(tree, key); 731cb0ef41Sopenharmony_ci } 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci // Add or overwrite an existing key-value pair. 761cb0ef41Sopenharmony_ci void Set(Key key, Value value); 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ci bool operator==(const PersistentMap& other) const { 791cb0ef41Sopenharmony_ci if (tree_ == other.tree_) return true; 801cb0ef41Sopenharmony_ci if (def_value_ != other.def_value_) return false; 811cb0ef41Sopenharmony_ci for (std::tuple<Key, Value, Value> triple : Zip(other)) { 821cb0ef41Sopenharmony_ci if (std::get<1>(triple) != std::get<2>(triple)) return false; 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci return true; 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci bool operator!=(const PersistentMap& other) const { 881cb0ef41Sopenharmony_ci return !(*this == other); 891cb0ef41Sopenharmony_ci } 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci // The iterator produces key-value pairs in the lexicographical order of 921cb0ef41Sopenharmony_ci // hash value and key. It produces exactly the key-value pairs where the value 931cb0ef41Sopenharmony_ci // is not the default value. 941cb0ef41Sopenharmony_ci class iterator; 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci iterator begin() const { 971cb0ef41Sopenharmony_ci if (!tree_) return end(); 981cb0ef41Sopenharmony_ci return iterator::begin(tree_, def_value_); 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci iterator end() const { return iterator::end(def_value_); } 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci // Iterator to traverse two maps in lockstep, producing matching value pairs 1031cb0ef41Sopenharmony_ci // for each key where at least one value is different from the respective 1041cb0ef41Sopenharmony_ci // default. 1051cb0ef41Sopenharmony_ci class double_iterator; 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci // An iterable to iterate over the two maps in lockstep. 1081cb0ef41Sopenharmony_ci struct ZipIterable { 1091cb0ef41Sopenharmony_ci PersistentMap a; 1101cb0ef41Sopenharmony_ci PersistentMap b; 1111cb0ef41Sopenharmony_ci double_iterator begin() { return double_iterator(a.begin(), b.begin()); } 1121cb0ef41Sopenharmony_ci double_iterator end() { return double_iterator(a.end(), b.end()); } 1131cb0ef41Sopenharmony_ci }; 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci ZipIterable Zip(const PersistentMap& other) const { return {*this, other}; } 1161cb0ef41Sopenharmony_ci 1171cb0ef41Sopenharmony_ci explicit PersistentMap(Zone* zone, Value def_value = Value()) 1181cb0ef41Sopenharmony_ci : PersistentMap(nullptr, zone, def_value) {} 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci private: 1211cb0ef41Sopenharmony_ci // Find the {FocusedTree} that contains a key-value pair with key hash {hash}. 1221cb0ef41Sopenharmony_ci const FocusedTree* FindHash(HashValue hash) const; 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ci // Find the {FocusedTree} that contains a key-value pair with key hash {hash}. 1251cb0ef41Sopenharmony_ci // Output the path to this {FocusedTree} and its length. If no such 1261cb0ef41Sopenharmony_ci // {FocusedTree} exists, return {nullptr} and output the path to the last node 1271cb0ef41Sopenharmony_ci // with a matching hash prefix. Note that {length} is the length of the found 1281cb0ef41Sopenharmony_ci // path and may be less than the length of the found {FocusedTree}. 1291cb0ef41Sopenharmony_ci const FocusedTree* FindHash(HashValue hash, 1301cb0ef41Sopenharmony_ci std::array<const FocusedTree*, kHashBits>* path, 1311cb0ef41Sopenharmony_ci int* length) const; 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci // Load value from the leaf node on the focused path of {tree}. 1341cb0ef41Sopenharmony_ci const Value& GetFocusedValue(const FocusedTree* tree, const Key& key) const; 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci // Return the {FocusedTree} representing the left (bit==kLeft) or right 1371cb0ef41Sopenharmony_ci // (bit==kRight) child of the node on the path of {tree} at tree level 1381cb0ef41Sopenharmony_ci // {level}. 1391cb0ef41Sopenharmony_ci static const FocusedTree* GetChild(const FocusedTree* tree, int level, 1401cb0ef41Sopenharmony_ci Bit bit); 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci // Find the leftmost path in the tree, starting at the node at tree level 1431cb0ef41Sopenharmony_ci // {level} on the path of {start}. Output the level of the leaf to {level} and 1441cb0ef41Sopenharmony_ci // the path to {path}. 1451cb0ef41Sopenharmony_ci static const FocusedTree* FindLeftmost( 1461cb0ef41Sopenharmony_ci const FocusedTree* start, int* level, 1471cb0ef41Sopenharmony_ci std::array<const FocusedTree*, kHashBits>* path); 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci PersistentMap(const FocusedTree* tree, Zone* zone, Value def_value) 1501cb0ef41Sopenharmony_ci : tree_(tree), def_value_(def_value), zone_(zone) {} 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ci const FocusedTree* tree_; 1531cb0ef41Sopenharmony_ci Value def_value_; 1541cb0ef41Sopenharmony_ci Zone* zone_; 1551cb0ef41Sopenharmony_ci}; 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci// This structure represents a hash tree with one focused path to a specific 1581cb0ef41Sopenharmony_ci// leaf. For the focused leaf, it stores key, value and key hash. The path is 1591cb0ef41Sopenharmony_ci// defined by the hash bits of the focused leaf. In a traditional tree 1601cb0ef41Sopenharmony_ci// datastructure, the nodes of a path form a linked list with the values being 1611cb0ef41Sopenharmony_ci// the pointers outside of this path. Instead of storing all of these nodes, 1621cb0ef41Sopenharmony_ci// we store an array of the pointers pointing outside of the path. This is 1631cb0ef41Sopenharmony_ci// similar to the stack used when doing DFS traversal of a tree. The hash of 1641cb0ef41Sopenharmony_ci// the leaf is used to know if the pointers point to the left or the 1651cb0ef41Sopenharmony_ci// right of the path. As there is no explicit representation of a tree node, 1661cb0ef41Sopenharmony_ci// this structure also represents all the nodes on its path. The intended node 1671cb0ef41Sopenharmony_ci// depends on the tree depth, which is always clear from the referencing 1681cb0ef41Sopenharmony_ci// context. So the pointer to a {FocusedTree} stored in the 1691cb0ef41Sopenharmony_ci// {PersistentMap.tree_} always references the root, while a pointer from a 1701cb0ef41Sopenharmony_ci// focused node of another {FocusedTree} always references to one tree level 1711cb0ef41Sopenharmony_ci// lower than before. 1721cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher> 1731cb0ef41Sopenharmony_cistruct PersistentMap<Key, Value, Hasher>::FocusedTree { 1741cb0ef41Sopenharmony_ci KeyValue key_value; 1751cb0ef41Sopenharmony_ci // The depth of the focused path, that is, the number of pointers stored in 1761cb0ef41Sopenharmony_ci // this structure. 1771cb0ef41Sopenharmony_ci int8_t length; 1781cb0ef41Sopenharmony_ci HashValue key_hash; 1791cb0ef41Sopenharmony_ci // Out-of-line storage for hash collisions. 1801cb0ef41Sopenharmony_ci const ZoneMap<Key, Value>* more; 1811cb0ef41Sopenharmony_ci using more_iterator = typename ZoneMap<Key, Value>::const_iterator; 1821cb0ef41Sopenharmony_ci // {path_array} has to be the last member: To store an array inline, we 1831cb0ef41Sopenharmony_ci // over-allocate memory for this structure and access memory beyond 1841cb0ef41Sopenharmony_ci // {path_array}. This corresponds to a flexible array member as defined in 1851cb0ef41Sopenharmony_ci // C99. 1861cb0ef41Sopenharmony_ci const FocusedTree* path_array[1]; 1871cb0ef41Sopenharmony_ci const FocusedTree*& path(int i) { 1881cb0ef41Sopenharmony_ci DCHECK(i < length); 1891cb0ef41Sopenharmony_ci return reinterpret_cast<const FocusedTree**>( 1901cb0ef41Sopenharmony_ci reinterpret_cast<byte*>(this) + offsetof(FocusedTree, path_array))[i]; 1911cb0ef41Sopenharmony_ci } 1921cb0ef41Sopenharmony_ci const FocusedTree* path(int i) const { 1931cb0ef41Sopenharmony_ci DCHECK(i < length); 1941cb0ef41Sopenharmony_ci return reinterpret_cast<const FocusedTree* const*>( 1951cb0ef41Sopenharmony_ci reinterpret_cast<const byte*>(this) + 1961cb0ef41Sopenharmony_ci offsetof(FocusedTree, path_array))[i]; 1971cb0ef41Sopenharmony_ci } 1981cb0ef41Sopenharmony_ci}; 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher> 2011cb0ef41Sopenharmony_ciclass PersistentMap<Key, Value, Hasher>::HashValue { 2021cb0ef41Sopenharmony_ci public: 2031cb0ef41Sopenharmony_ci explicit HashValue(size_t hash) : bits_(static_cast<uint32_t>(hash)) {} 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci Bit operator[](int pos) const { 2061cb0ef41Sopenharmony_ci DCHECK_LT(pos, kHashBits); 2071cb0ef41Sopenharmony_ci return bits_ & (static_cast<decltype(bits_)>(1) << (kHashBits - pos - 1)) 2081cb0ef41Sopenharmony_ci ? kRight 2091cb0ef41Sopenharmony_ci : kLeft; 2101cb0ef41Sopenharmony_ci } 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_ci bool operator<(HashValue other) const { return bits_ < other.bits_; } 2131cb0ef41Sopenharmony_ci bool operator==(HashValue other) const { return bits_ == other.bits_; } 2141cb0ef41Sopenharmony_ci bool operator!=(HashValue other) const { return bits_ != other.bits_; } 2151cb0ef41Sopenharmony_ci HashValue operator^(HashValue other) const { 2161cb0ef41Sopenharmony_ci return HashValue(bits_ ^ other.bits_); 2171cb0ef41Sopenharmony_ci } 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci private: 2201cb0ef41Sopenharmony_ci static_assert(sizeof(uint32_t) * 8 == kHashBits, "wrong type for bits_"); 2211cb0ef41Sopenharmony_ci uint32_t bits_; 2221cb0ef41Sopenharmony_ci}; 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher> 2251cb0ef41Sopenharmony_ciclass PersistentMap<Key, Value, Hasher>::iterator { 2261cb0ef41Sopenharmony_ci public: 2271cb0ef41Sopenharmony_ci const value_type operator*() const { 2281cb0ef41Sopenharmony_ci if (current_->more) { 2291cb0ef41Sopenharmony_ci return *more_iter_; 2301cb0ef41Sopenharmony_ci } else { 2311cb0ef41Sopenharmony_ci return current_->key_value; 2321cb0ef41Sopenharmony_ci } 2331cb0ef41Sopenharmony_ci } 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci iterator& operator++() { 2361cb0ef41Sopenharmony_ci do { 2371cb0ef41Sopenharmony_ci if (!current_) { 2381cb0ef41Sopenharmony_ci // Iterator is past the end. 2391cb0ef41Sopenharmony_ci return *this; 2401cb0ef41Sopenharmony_ci } 2411cb0ef41Sopenharmony_ci if (current_->more) { 2421cb0ef41Sopenharmony_ci DCHECK(more_iter_ != current_->more->end()); 2431cb0ef41Sopenharmony_ci ++more_iter_; 2441cb0ef41Sopenharmony_ci if (more_iter_ != current_->more->end()) return *this; 2451cb0ef41Sopenharmony_ci } 2461cb0ef41Sopenharmony_ci if (level_ == 0) { 2471cb0ef41Sopenharmony_ci *this = end(def_value_); 2481cb0ef41Sopenharmony_ci return *this; 2491cb0ef41Sopenharmony_ci } 2501cb0ef41Sopenharmony_ci --level_; 2511cb0ef41Sopenharmony_ci while (current_->key_hash[level_] == kRight || path_[level_] == nullptr) { 2521cb0ef41Sopenharmony_ci if (level_ == 0) { 2531cb0ef41Sopenharmony_ci *this = end(def_value_); 2541cb0ef41Sopenharmony_ci return *this; 2551cb0ef41Sopenharmony_ci } 2561cb0ef41Sopenharmony_ci --level_; 2571cb0ef41Sopenharmony_ci } 2581cb0ef41Sopenharmony_ci const FocusedTree* first_right_alternative = path_[level_]; 2591cb0ef41Sopenharmony_ci level_++; 2601cb0ef41Sopenharmony_ci current_ = FindLeftmost(first_right_alternative, &level_, &path_); 2611cb0ef41Sopenharmony_ci if (current_->more) { 2621cb0ef41Sopenharmony_ci more_iter_ = current_->more->begin(); 2631cb0ef41Sopenharmony_ci } 2641cb0ef41Sopenharmony_ci } while (!((**this).second != def_value())); 2651cb0ef41Sopenharmony_ci return *this; 2661cb0ef41Sopenharmony_ci } 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_ci bool operator==(const iterator& other) const { 2691cb0ef41Sopenharmony_ci if (is_end()) return other.is_end(); 2701cb0ef41Sopenharmony_ci if (other.is_end()) return false; 2711cb0ef41Sopenharmony_ci if (current_->key_hash != other.current_->key_hash) { 2721cb0ef41Sopenharmony_ci return false; 2731cb0ef41Sopenharmony_ci } else { 2741cb0ef41Sopenharmony_ci return (**this).first == (*other).first; 2751cb0ef41Sopenharmony_ci } 2761cb0ef41Sopenharmony_ci } 2771cb0ef41Sopenharmony_ci bool operator!=(const iterator& other) const { return !(*this == other); } 2781cb0ef41Sopenharmony_ci 2791cb0ef41Sopenharmony_ci bool operator<(const iterator& other) const { 2801cb0ef41Sopenharmony_ci if (is_end()) return false; 2811cb0ef41Sopenharmony_ci if (other.is_end()) return true; 2821cb0ef41Sopenharmony_ci if (current_->key_hash == other.current_->key_hash) { 2831cb0ef41Sopenharmony_ci return (**this).first < (*other).first; 2841cb0ef41Sopenharmony_ci } else { 2851cb0ef41Sopenharmony_ci return current_->key_hash < other.current_->key_hash; 2861cb0ef41Sopenharmony_ci } 2871cb0ef41Sopenharmony_ci } 2881cb0ef41Sopenharmony_ci 2891cb0ef41Sopenharmony_ci bool is_end() const { return current_ == nullptr; } 2901cb0ef41Sopenharmony_ci 2911cb0ef41Sopenharmony_ci const Value& def_value() { return def_value_; } 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ci static iterator begin(const FocusedTree* tree, Value def_value) { 2941cb0ef41Sopenharmony_ci iterator i(def_value); 2951cb0ef41Sopenharmony_ci i.current_ = FindLeftmost(tree, &i.level_, &i.path_); 2961cb0ef41Sopenharmony_ci if (i.current_->more) { 2971cb0ef41Sopenharmony_ci i.more_iter_ = i.current_->more->begin(); 2981cb0ef41Sopenharmony_ci } 2991cb0ef41Sopenharmony_ci // Skip entries with default value. PersistentMap iterators must never point 3001cb0ef41Sopenharmony_ci // to a default value. 3011cb0ef41Sopenharmony_ci while (!i.is_end() && !((*i).second != def_value)) ++i; 3021cb0ef41Sopenharmony_ci return i; 3031cb0ef41Sopenharmony_ci } 3041cb0ef41Sopenharmony_ci 3051cb0ef41Sopenharmony_ci static iterator end(Value def_value) { return iterator(def_value); } 3061cb0ef41Sopenharmony_ci 3071cb0ef41Sopenharmony_ci private: 3081cb0ef41Sopenharmony_ci int level_; 3091cb0ef41Sopenharmony_ci typename FocusedTree::more_iterator more_iter_; 3101cb0ef41Sopenharmony_ci const FocusedTree* current_; 3111cb0ef41Sopenharmony_ci std::array<const FocusedTree*, kHashBits> path_; 3121cb0ef41Sopenharmony_ci Value def_value_; 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci explicit iterator(Value def_value) 3151cb0ef41Sopenharmony_ci : level_(0), current_(nullptr), def_value_(def_value) {} 3161cb0ef41Sopenharmony_ci}; 3171cb0ef41Sopenharmony_ci 3181cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher> 3191cb0ef41Sopenharmony_ciclass PersistentMap<Key, Value, Hasher>::double_iterator { 3201cb0ef41Sopenharmony_ci public: 3211cb0ef41Sopenharmony_ci std::tuple<Key, Value, Value> operator*() { 3221cb0ef41Sopenharmony_ci if (first_current_) { 3231cb0ef41Sopenharmony_ci auto pair = *first_; 3241cb0ef41Sopenharmony_ci return std::make_tuple( 3251cb0ef41Sopenharmony_ci pair.first, pair.second, 3261cb0ef41Sopenharmony_ci second_current_ ? (*second_).second : second_.def_value()); 3271cb0ef41Sopenharmony_ci } else { 3281cb0ef41Sopenharmony_ci DCHECK(second_current_); 3291cb0ef41Sopenharmony_ci auto pair = *second_; 3301cb0ef41Sopenharmony_ci return std::make_tuple(pair.first, first_.def_value(), pair.second); 3311cb0ef41Sopenharmony_ci } 3321cb0ef41Sopenharmony_ci } 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci double_iterator& operator++() { 3351cb0ef41Sopenharmony_ci#ifdef DEBUG 3361cb0ef41Sopenharmony_ci iterator old_first = first_; 3371cb0ef41Sopenharmony_ci iterator old_second = second_; 3381cb0ef41Sopenharmony_ci#endif 3391cb0ef41Sopenharmony_ci if (first_current_) { 3401cb0ef41Sopenharmony_ci ++first_; 3411cb0ef41Sopenharmony_ci DCHECK(old_first < first_); 3421cb0ef41Sopenharmony_ci } 3431cb0ef41Sopenharmony_ci if (second_current_) { 3441cb0ef41Sopenharmony_ci ++second_; 3451cb0ef41Sopenharmony_ci DCHECK(old_second < second_); 3461cb0ef41Sopenharmony_ci } 3471cb0ef41Sopenharmony_ci return *this = double_iterator(first_, second_); 3481cb0ef41Sopenharmony_ci } 3491cb0ef41Sopenharmony_ci 3501cb0ef41Sopenharmony_ci double_iterator(iterator first, iterator second) 3511cb0ef41Sopenharmony_ci : first_(first), second_(second) { 3521cb0ef41Sopenharmony_ci if (first_ == second_) { 3531cb0ef41Sopenharmony_ci first_current_ = second_current_ = true; 3541cb0ef41Sopenharmony_ci } else if (first_ < second_) { 3551cb0ef41Sopenharmony_ci first_current_ = true; 3561cb0ef41Sopenharmony_ci second_current_ = false; 3571cb0ef41Sopenharmony_ci } else { 3581cb0ef41Sopenharmony_ci DCHECK(second_ < first_); 3591cb0ef41Sopenharmony_ci first_current_ = false; 3601cb0ef41Sopenharmony_ci second_current_ = true; 3611cb0ef41Sopenharmony_ci } 3621cb0ef41Sopenharmony_ci } 3631cb0ef41Sopenharmony_ci 3641cb0ef41Sopenharmony_ci bool operator!=(const double_iterator& other) { 3651cb0ef41Sopenharmony_ci return first_ != other.first_ || second_ != other.second_; 3661cb0ef41Sopenharmony_ci } 3671cb0ef41Sopenharmony_ci 3681cb0ef41Sopenharmony_ci bool is_end() const { return first_.is_end() && second_.is_end(); } 3691cb0ef41Sopenharmony_ci 3701cb0ef41Sopenharmony_ci private: 3711cb0ef41Sopenharmony_ci iterator first_; 3721cb0ef41Sopenharmony_ci iterator second_; 3731cb0ef41Sopenharmony_ci bool first_current_; 3741cb0ef41Sopenharmony_ci bool second_current_; 3751cb0ef41Sopenharmony_ci}; 3761cb0ef41Sopenharmony_ci 3771cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher> 3781cb0ef41Sopenharmony_civoid PersistentMap<Key, Value, Hasher>::Set(Key key, Value value) { 3791cb0ef41Sopenharmony_ci HashValue key_hash = HashValue(Hasher()(key)); 3801cb0ef41Sopenharmony_ci std::array<const FocusedTree*, kHashBits> path; 3811cb0ef41Sopenharmony_ci int length = 0; 3821cb0ef41Sopenharmony_ci const FocusedTree* old = FindHash(key_hash, &path, &length); 3831cb0ef41Sopenharmony_ci ZoneMap<Key, Value>* more = nullptr; 3841cb0ef41Sopenharmony_ci if (!(GetFocusedValue(old, key) != value)) return; 3851cb0ef41Sopenharmony_ci if (old && !(old->more == nullptr && old->key_value.key() == key)) { 3861cb0ef41Sopenharmony_ci more = zone_->New<ZoneMap<Key, Value>>(zone_); 3871cb0ef41Sopenharmony_ci if (old->more) { 3881cb0ef41Sopenharmony_ci *more = *old->more; 3891cb0ef41Sopenharmony_ci } else { 3901cb0ef41Sopenharmony_ci more->erase(old->key_value.key()); 3911cb0ef41Sopenharmony_ci more->emplace(old->key_value.key(), old->key_value.value()); 3921cb0ef41Sopenharmony_ci } 3931cb0ef41Sopenharmony_ci more->erase(key); 3941cb0ef41Sopenharmony_ci more->emplace(key, value); 3951cb0ef41Sopenharmony_ci } 3961cb0ef41Sopenharmony_ci size_t size = sizeof(FocusedTree) + 3971cb0ef41Sopenharmony_ci std::max(0, length - 1) * sizeof(const FocusedTree*); 3981cb0ef41Sopenharmony_ci FocusedTree* tree = new (zone_->Allocate<FocusedTree>(size)) 3991cb0ef41Sopenharmony_ci FocusedTree{KeyValue(std::move(key), std::move(value)), 4001cb0ef41Sopenharmony_ci static_cast<int8_t>(length), 4011cb0ef41Sopenharmony_ci key_hash, 4021cb0ef41Sopenharmony_ci more, 4031cb0ef41Sopenharmony_ci {}}; 4041cb0ef41Sopenharmony_ci for (int i = 0; i < length; ++i) { 4051cb0ef41Sopenharmony_ci tree->path(i) = path[i]; 4061cb0ef41Sopenharmony_ci } 4071cb0ef41Sopenharmony_ci *this = PersistentMap(tree, zone_, def_value_); 4081cb0ef41Sopenharmony_ci} 4091cb0ef41Sopenharmony_ci 4101cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher> 4111cb0ef41Sopenharmony_ciconst typename PersistentMap<Key, Value, Hasher>::FocusedTree* 4121cb0ef41Sopenharmony_ciPersistentMap<Key, Value, Hasher>::FindHash(HashValue hash) const { 4131cb0ef41Sopenharmony_ci const FocusedTree* tree = tree_; 4141cb0ef41Sopenharmony_ci int level = 0; 4151cb0ef41Sopenharmony_ci while (tree && hash != tree->key_hash) { 4161cb0ef41Sopenharmony_ci while ((hash ^ tree->key_hash)[level] == 0) { 4171cb0ef41Sopenharmony_ci ++level; 4181cb0ef41Sopenharmony_ci } 4191cb0ef41Sopenharmony_ci tree = level < tree->length ? tree->path(level) : nullptr; 4201cb0ef41Sopenharmony_ci ++level; 4211cb0ef41Sopenharmony_ci } 4221cb0ef41Sopenharmony_ci return tree; 4231cb0ef41Sopenharmony_ci} 4241cb0ef41Sopenharmony_ci 4251cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher> 4261cb0ef41Sopenharmony_ciconst typename PersistentMap<Key, Value, Hasher>::FocusedTree* 4271cb0ef41Sopenharmony_ciPersistentMap<Key, Value, Hasher>::FindHash( 4281cb0ef41Sopenharmony_ci HashValue hash, std::array<const FocusedTree*, kHashBits>* path, 4291cb0ef41Sopenharmony_ci int* length) const { 4301cb0ef41Sopenharmony_ci const FocusedTree* tree = tree_; 4311cb0ef41Sopenharmony_ci int level = 0; 4321cb0ef41Sopenharmony_ci while (tree && hash != tree->key_hash) { 4331cb0ef41Sopenharmony_ci int map_length = tree->length; 4341cb0ef41Sopenharmony_ci while ((hash ^ tree->key_hash)[level] == 0) { 4351cb0ef41Sopenharmony_ci (*path)[level] = level < map_length ? tree->path(level) : nullptr; 4361cb0ef41Sopenharmony_ci ++level; 4371cb0ef41Sopenharmony_ci } 4381cb0ef41Sopenharmony_ci (*path)[level] = tree; 4391cb0ef41Sopenharmony_ci tree = level < tree->length ? tree->path(level) : nullptr; 4401cb0ef41Sopenharmony_ci ++level; 4411cb0ef41Sopenharmony_ci } 4421cb0ef41Sopenharmony_ci if (tree) { 4431cb0ef41Sopenharmony_ci while (level < tree->length) { 4441cb0ef41Sopenharmony_ci (*path)[level] = tree->path(level); 4451cb0ef41Sopenharmony_ci ++level; 4461cb0ef41Sopenharmony_ci } 4471cb0ef41Sopenharmony_ci } 4481cb0ef41Sopenharmony_ci *length = level; 4491cb0ef41Sopenharmony_ci return tree; 4501cb0ef41Sopenharmony_ci} 4511cb0ef41Sopenharmony_ci 4521cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher> 4531cb0ef41Sopenharmony_ciconst Value& PersistentMap<Key, Value, Hasher>::GetFocusedValue( 4541cb0ef41Sopenharmony_ci const FocusedTree* tree, const Key& key) const { 4551cb0ef41Sopenharmony_ci if (!tree) { 4561cb0ef41Sopenharmony_ci return def_value_; 4571cb0ef41Sopenharmony_ci } 4581cb0ef41Sopenharmony_ci if (tree->more) { 4591cb0ef41Sopenharmony_ci auto it = tree->more->find(key); 4601cb0ef41Sopenharmony_ci if (it == tree->more->end()) 4611cb0ef41Sopenharmony_ci return def_value_; 4621cb0ef41Sopenharmony_ci else 4631cb0ef41Sopenharmony_ci return it->second; 4641cb0ef41Sopenharmony_ci } else { 4651cb0ef41Sopenharmony_ci if (key == tree->key_value.key()) { 4661cb0ef41Sopenharmony_ci return tree->key_value.value(); 4671cb0ef41Sopenharmony_ci } else { 4681cb0ef41Sopenharmony_ci return def_value_; 4691cb0ef41Sopenharmony_ci } 4701cb0ef41Sopenharmony_ci } 4711cb0ef41Sopenharmony_ci} 4721cb0ef41Sopenharmony_ci 4731cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher> 4741cb0ef41Sopenharmony_ciconst typename PersistentMap<Key, Value, Hasher>::FocusedTree* 4751cb0ef41Sopenharmony_ciPersistentMap<Key, Value, Hasher>::GetChild(const FocusedTree* tree, int level, 4761cb0ef41Sopenharmony_ci Bit bit) { 4771cb0ef41Sopenharmony_ci if (tree->key_hash[level] == bit) { 4781cb0ef41Sopenharmony_ci return tree; 4791cb0ef41Sopenharmony_ci } else if (level < tree->length) { 4801cb0ef41Sopenharmony_ci return tree->path(level); 4811cb0ef41Sopenharmony_ci } else { 4821cb0ef41Sopenharmony_ci return nullptr; 4831cb0ef41Sopenharmony_ci } 4841cb0ef41Sopenharmony_ci} 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher> 4871cb0ef41Sopenharmony_ciconst typename PersistentMap<Key, Value, Hasher>::FocusedTree* 4881cb0ef41Sopenharmony_ciPersistentMap<Key, Value, Hasher>::FindLeftmost( 4891cb0ef41Sopenharmony_ci const FocusedTree* start, int* level, 4901cb0ef41Sopenharmony_ci std::array<const FocusedTree*, kHashBits>* path) { 4911cb0ef41Sopenharmony_ci const FocusedTree* current = start; 4921cb0ef41Sopenharmony_ci while (*level < current->length) { 4931cb0ef41Sopenharmony_ci if (const FocusedTree* left_child = GetChild(current, *level, kLeft)) { 4941cb0ef41Sopenharmony_ci (*path)[*level] = GetChild(current, *level, kRight); 4951cb0ef41Sopenharmony_ci current = left_child; 4961cb0ef41Sopenharmony_ci ++*level; 4971cb0ef41Sopenharmony_ci } else if (const FocusedTree* right_child = 4981cb0ef41Sopenharmony_ci GetChild(current, *level, kRight)) { 4991cb0ef41Sopenharmony_ci (*path)[*level] = GetChild(current, *level, kLeft); 5001cb0ef41Sopenharmony_ci current = right_child; 5011cb0ef41Sopenharmony_ci ++*level; 5021cb0ef41Sopenharmony_ci } else { 5031cb0ef41Sopenharmony_ci UNREACHABLE(); 5041cb0ef41Sopenharmony_ci } 5051cb0ef41Sopenharmony_ci } 5061cb0ef41Sopenharmony_ci return current; 5071cb0ef41Sopenharmony_ci} 5081cb0ef41Sopenharmony_ci 5091cb0ef41Sopenharmony_citemplate <class Key, class Value, class Hasher> 5101cb0ef41Sopenharmony_cistd::ostream& operator<<(std::ostream& os, 5111cb0ef41Sopenharmony_ci const PersistentMap<Key, Value, Hasher>& map) { 5121cb0ef41Sopenharmony_ci os << "{"; 5131cb0ef41Sopenharmony_ci bool first = true; 5141cb0ef41Sopenharmony_ci for (auto pair : map) { 5151cb0ef41Sopenharmony_ci if (!first) os << ", "; 5161cb0ef41Sopenharmony_ci first = false; 5171cb0ef41Sopenharmony_ci os << pair.first << ": " << pair.second; 5181cb0ef41Sopenharmony_ci } 5191cb0ef41Sopenharmony_ci return os << "}"; 5201cb0ef41Sopenharmony_ci} 5211cb0ef41Sopenharmony_ci 5221cb0ef41Sopenharmony_ci} // namespace compiler 5231cb0ef41Sopenharmony_ci} // namespace internal 5241cb0ef41Sopenharmony_ci} // namespace v8 5251cb0ef41Sopenharmony_ci 5261cb0ef41Sopenharmony_ci#endif // V8_COMPILER_PERSISTENT_MAP_H_ 527