16d528ed9Sopenharmony_ci// Copyright 2014 The Chromium Authors. All rights reserved. 26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 36d528ed9Sopenharmony_ci// found in the LICENSE file. 46d528ed9Sopenharmony_ci 56d528ed9Sopenharmony_ci#ifndef TOOLS_GN_UNIQUE_VECTOR_H_ 66d528ed9Sopenharmony_ci#define TOOLS_GN_UNIQUE_VECTOR_H_ 76d528ed9Sopenharmony_ci 86d528ed9Sopenharmony_ci#include <stddef.h> 96d528ed9Sopenharmony_ci#include <stdint.h> 106d528ed9Sopenharmony_ci 116d528ed9Sopenharmony_ci#include <algorithm> 126d528ed9Sopenharmony_ci#include <functional> 136d528ed9Sopenharmony_ci#include <vector> 146d528ed9Sopenharmony_ci 156d528ed9Sopenharmony_ci#include "hash_table_base.h" 166d528ed9Sopenharmony_ci 176d528ed9Sopenharmony_ci// A HashTableBase node type used by all UniqueVector<> instantiations. 186d528ed9Sopenharmony_ci// The node stores the item's hash value and its index plus 1, in order 196d528ed9Sopenharmony_ci// to follow the HashTableBase requirements (i.e. zero-initializable null 206d528ed9Sopenharmony_ci// value). 216d528ed9Sopenharmony_cistruct UniqueVectorNode { 226d528ed9Sopenharmony_ci uint32_t hash32; 236d528ed9Sopenharmony_ci uint32_t index_plus1; 246d528ed9Sopenharmony_ci 256d528ed9Sopenharmony_ci size_t hash_value() const { return hash32; } 266d528ed9Sopenharmony_ci 276d528ed9Sopenharmony_ci bool is_valid() const { return !is_null(); } 286d528ed9Sopenharmony_ci 296d528ed9Sopenharmony_ci bool is_null() const { return index_plus1 == 0; } 306d528ed9Sopenharmony_ci 316d528ed9Sopenharmony_ci // Do not support deletion, making lookup faster. 326d528ed9Sopenharmony_ci static constexpr bool is_tombstone() { return false; } 336d528ed9Sopenharmony_ci 346d528ed9Sopenharmony_ci // Return vector index. 356d528ed9Sopenharmony_ci size_t index() const { return index_plus1 - 1u; } 366d528ed9Sopenharmony_ci 376d528ed9Sopenharmony_ci static uint32_t ToHash32(size_t hash) { return static_cast<uint32_t>(hash); } 386d528ed9Sopenharmony_ci 396d528ed9Sopenharmony_ci // Create new instance from hash value and vector index. 406d528ed9Sopenharmony_ci static UniqueVectorNode Make(size_t hash, size_t index) { 416d528ed9Sopenharmony_ci return {ToHash32(hash), static_cast<uint32_t>(index + 1u)}; 426d528ed9Sopenharmony_ci } 436d528ed9Sopenharmony_ci}; 446d528ed9Sopenharmony_ci 456d528ed9Sopenharmony_ciusing UniqueVectorHashTableBase = HashTableBase<UniqueVectorNode>; 466d528ed9Sopenharmony_ci 476d528ed9Sopenharmony_ci// A common HashSet implementation used by all UniqueVector instantiations. 486d528ed9Sopenharmony_ciclass UniqueVectorHashSet : public UniqueVectorHashTableBase { 496d528ed9Sopenharmony_ci public: 506d528ed9Sopenharmony_ci using BaseType = UniqueVectorHashTableBase; 516d528ed9Sopenharmony_ci using Node = BaseType::Node; 526d528ed9Sopenharmony_ci 536d528ed9Sopenharmony_ci // Specialized Lookup() template function. 546d528ed9Sopenharmony_ci // |hash| is the hash value for |item|. 556d528ed9Sopenharmony_ci // |item| is the item search key being looked up. 566d528ed9Sopenharmony_ci // |vector| is containing vector for existing items. 576d528ed9Sopenharmony_ci // 586d528ed9Sopenharmony_ci // Returns a non-null mutable Node pointer. 596d528ed9Sopenharmony_ci template <typename T, typename EqualTo = std::equal_to<T>> 606d528ed9Sopenharmony_ci Node* Lookup(size_t hash, const T& item, const std::vector<T>& vector) const { 616d528ed9Sopenharmony_ci uint32_t hash32 = Node::ToHash32(hash); 626d528ed9Sopenharmony_ci return BaseType::NodeLookup(hash32, [&](const Node* node) { 636d528ed9Sopenharmony_ci return hash32 == node->hash32 && EqualTo()(vector[node->index()], item); 646d528ed9Sopenharmony_ci }); 656d528ed9Sopenharmony_ci } 666d528ed9Sopenharmony_ci 676d528ed9Sopenharmony_ci // Specialized Insert() function that converts |index| into the proper 686d528ed9Sopenharmony_ci // UniqueVectorKey type. 696d528ed9Sopenharmony_ci void Insert(Node* node, size_t hash, size_t index) { 706d528ed9Sopenharmony_ci *node = Node::Make(hash, index); 716d528ed9Sopenharmony_ci BaseType::UpdateAfterInsert(); 726d528ed9Sopenharmony_ci } 736d528ed9Sopenharmony_ci 746d528ed9Sopenharmony_ci void Clear() { NodeClear(); } 756d528ed9Sopenharmony_ci}; 766d528ed9Sopenharmony_ci 776d528ed9Sopenharmony_ci// An ordered set optimized for GN's usage. Such sets are used to store lists 786d528ed9Sopenharmony_ci// of configs and libraries, and are appended to but not randomly inserted 796d528ed9Sopenharmony_ci// into. 806d528ed9Sopenharmony_citemplate <typename T, 816d528ed9Sopenharmony_ci typename Hash = std::hash<T>, 826d528ed9Sopenharmony_ci typename EqualTo = std::equal_to<T>> 836d528ed9Sopenharmony_ciclass UniqueVector { 846d528ed9Sopenharmony_ci public: 856d528ed9Sopenharmony_ci using Vector = std::vector<T>; 866d528ed9Sopenharmony_ci using iterator = typename Vector::iterator; 876d528ed9Sopenharmony_ci using const_iterator = typename Vector::const_iterator; 886d528ed9Sopenharmony_ci 896d528ed9Sopenharmony_ci const Vector& vector() const { return vector_; } 906d528ed9Sopenharmony_ci size_t size() const { return vector_.size(); } 916d528ed9Sopenharmony_ci bool empty() const { return vector_.empty(); } 926d528ed9Sopenharmony_ci void clear() { 936d528ed9Sopenharmony_ci vector_.clear(); 946d528ed9Sopenharmony_ci set_.Clear(); 956d528ed9Sopenharmony_ci } 966d528ed9Sopenharmony_ci void reserve(size_t s) { vector_.reserve(s); } 976d528ed9Sopenharmony_ci 986d528ed9Sopenharmony_ci const T& operator[](size_t index) const { return vector_[index]; } 996d528ed9Sopenharmony_ci 1006d528ed9Sopenharmony_ci const_iterator begin() const { return vector_.begin(); } 1016d528ed9Sopenharmony_ci const_iterator end() const { return vector_.end(); } 1026d528ed9Sopenharmony_ci 1036d528ed9Sopenharmony_ci // Extract the vector out of the instance, clearing it at the same time. 1046d528ed9Sopenharmony_ci Vector release() { 1056d528ed9Sopenharmony_ci Vector result = std::move(vector_); 1066d528ed9Sopenharmony_ci clear(); 1076d528ed9Sopenharmony_ci return result; 1086d528ed9Sopenharmony_ci } 1096d528ed9Sopenharmony_ci 1106d528ed9Sopenharmony_ci // Returns true if the item was appended, false if it already existed (and 1116d528ed9Sopenharmony_ci // thus the vector was not modified). 1126d528ed9Sopenharmony_ci bool push_back(const T& t) { 1136d528ed9Sopenharmony_ci size_t hash; 1146d528ed9Sopenharmony_ci auto* node = Lookup(t, &hash); 1156d528ed9Sopenharmony_ci if (node->is_valid()) { 1166d528ed9Sopenharmony_ci return false; // Already have this one. 1176d528ed9Sopenharmony_ci } 1186d528ed9Sopenharmony_ci vector_.push_back(t); 1196d528ed9Sopenharmony_ci set_.Insert(node, hash, vector_.size() - 1); 1206d528ed9Sopenharmony_ci return true; 1216d528ed9Sopenharmony_ci } 1226d528ed9Sopenharmony_ci 1236d528ed9Sopenharmony_ci // Same as above, but moves the item into the vector if possible. 1246d528ed9Sopenharmony_ci bool push_back(T&& t) { 1256d528ed9Sopenharmony_ci size_t hash = Hash()(t); 1266d528ed9Sopenharmony_ci auto* node = Lookup(t, &hash); 1276d528ed9Sopenharmony_ci if (node->is_valid()) { 1286d528ed9Sopenharmony_ci return false; // Already have this one. 1296d528ed9Sopenharmony_ci } 1306d528ed9Sopenharmony_ci vector_.push_back(std::move(t)); 1316d528ed9Sopenharmony_ci set_.Insert(node, hash, vector_.size() - 1); 1326d528ed9Sopenharmony_ci return true; 1336d528ed9Sopenharmony_ci } 1346d528ed9Sopenharmony_ci 1356d528ed9Sopenharmony_ci // Construct an item in-place if possible. Return true if it was 1366d528ed9Sopenharmony_ci // appended, false otherwise. 1376d528ed9Sopenharmony_ci template <typename... ARGS> 1386d528ed9Sopenharmony_ci bool emplace_back(ARGS... args) { 1396d528ed9Sopenharmony_ci return push_back(T{std::forward<ARGS>(args)...}); 1406d528ed9Sopenharmony_ci } 1416d528ed9Sopenharmony_ci 1426d528ed9Sopenharmony_ci // Try to add an item to the vector. Return (true, index) in 1436d528ed9Sopenharmony_ci // case of insertion, or (false, index) otherwise. In both cases 1446d528ed9Sopenharmony_ci // |index| will be the item's index in the set and will not be 1456d528ed9Sopenharmony_ci // kIndexNone. This can be used to implement a map using a 1466d528ed9Sopenharmony_ci // UniqueVector<> for keys, and a parallel array for values. 1476d528ed9Sopenharmony_ci std::pair<bool, size_t> PushBackWithIndex(const T& t) { 1486d528ed9Sopenharmony_ci size_t hash; 1496d528ed9Sopenharmony_ci auto* node = Lookup(t, &hash); 1506d528ed9Sopenharmony_ci if (node->is_valid()) { 1516d528ed9Sopenharmony_ci return {false, node->index()}; 1526d528ed9Sopenharmony_ci } 1536d528ed9Sopenharmony_ci size_t result = vector_.size(); 1546d528ed9Sopenharmony_ci vector_.push_back(t); 1556d528ed9Sopenharmony_ci set_.Insert(node, hash, result); 1566d528ed9Sopenharmony_ci return {true, result}; 1576d528ed9Sopenharmony_ci } 1586d528ed9Sopenharmony_ci 1596d528ed9Sopenharmony_ci // Same as above, but moves the item into the set on success. 1606d528ed9Sopenharmony_ci std::pair<bool, size_t> PushBackWithIndex(T&& t) { 1616d528ed9Sopenharmony_ci size_t hash; 1626d528ed9Sopenharmony_ci auto* node = Lookup(t, &hash); 1636d528ed9Sopenharmony_ci if (node->is_valid()) { 1646d528ed9Sopenharmony_ci return {false, node->index()}; 1656d528ed9Sopenharmony_ci } 1666d528ed9Sopenharmony_ci size_t result = vector_.size(); 1676d528ed9Sopenharmony_ci vector_.push_back(std::move(t)); 1686d528ed9Sopenharmony_ci set_.Insert(node, hash, result); 1696d528ed9Sopenharmony_ci return {true, result}; 1706d528ed9Sopenharmony_ci } 1716d528ed9Sopenharmony_ci 1726d528ed9Sopenharmony_ci // Construct an item in-place if possible. If a corresponding 1736d528ed9Sopenharmony_ci // item is already in the vector, return (false, index), otherwise 1746d528ed9Sopenharmony_ci // perform the insertion and return (true, index). In both cases 1756d528ed9Sopenharmony_ci // |index| will be the item's index in the vector and will not be 1766d528ed9Sopenharmony_ci // kIndexNone. 1776d528ed9Sopenharmony_ci template <typename... ARGS> 1786d528ed9Sopenharmony_ci std::pair<bool, size_t> EmplaceBackWithIndex(ARGS... args) { 1796d528ed9Sopenharmony_ci return PushBackWithIndex(T{std::forward<ARGS>(args)...}); 1806d528ed9Sopenharmony_ci } 1816d528ed9Sopenharmony_ci 1826d528ed9Sopenharmony_ci // Appends a range of items from an iterator. 1836d528ed9Sopenharmony_ci template <typename iter> 1846d528ed9Sopenharmony_ci void Append(const iter& begin, const iter& end) { 1856d528ed9Sopenharmony_ci for (iter i = begin; i != end; ++i) 1866d528ed9Sopenharmony_ci push_back(*i); 1876d528ed9Sopenharmony_ci } 1886d528ed9Sopenharmony_ci 1896d528ed9Sopenharmony_ci // Append from any iterable container with begin() and end() 1906d528ed9Sopenharmony_ci // methods, whose iterators derefence to values convertible to T. 1916d528ed9Sopenharmony_ci template <typename C, 1926d528ed9Sopenharmony_ci typename = std::void_t< 1936d528ed9Sopenharmony_ci decltype(static_cast<const T>(*std::declval<C>().begin())), 1946d528ed9Sopenharmony_ci decltype(static_cast<const T>(*std::declval<C>().end()))>> 1956d528ed9Sopenharmony_ci void Append(const C& other) { 1966d528ed9Sopenharmony_ci Append(other.begin(), other.end()); 1976d528ed9Sopenharmony_ci } 1986d528ed9Sopenharmony_ci 1996d528ed9Sopenharmony_ci // Append from any moveable iterable container with begin() and 2006d528ed9Sopenharmony_ci // end() methods. This variant moves items from the container 2016d528ed9Sopenharmony_ci // into the UniqueVector instance. 2026d528ed9Sopenharmony_ci template <typename C, 2036d528ed9Sopenharmony_ci typename = std::void_t< 2046d528ed9Sopenharmony_ci decltype(static_cast<T>(*std::declval<C>().begin())), 2056d528ed9Sopenharmony_ci decltype(static_cast<T>(*std::declval<C>().end()))>> 2066d528ed9Sopenharmony_ci void Append(C&& other) { 2076d528ed9Sopenharmony_ci for (auto it = other.begin(); it != other.end(); ++it) 2086d528ed9Sopenharmony_ci push_back(std::move(*it)); 2096d528ed9Sopenharmony_ci } 2106d528ed9Sopenharmony_ci 2116d528ed9Sopenharmony_ci // Returns true if the item is already in the vector. 2126d528ed9Sopenharmony_ci bool Contains(const T& t) const { 2136d528ed9Sopenharmony_ci size_t hash; 2146d528ed9Sopenharmony_ci return Lookup(t, &hash)->is_valid(); 2156d528ed9Sopenharmony_ci } 2166d528ed9Sopenharmony_ci 2176d528ed9Sopenharmony_ci // Returns the index of the item matching the given value in the list, or 2186d528ed9Sopenharmony_ci // kIndexNone if it's not found. 2196d528ed9Sopenharmony_ci size_t IndexOf(const T& t) const { 2206d528ed9Sopenharmony_ci size_t hash; 2216d528ed9Sopenharmony_ci return Lookup(t, &hash)->index(); 2226d528ed9Sopenharmony_ci } 2236d528ed9Sopenharmony_ci 2246d528ed9Sopenharmony_ci static constexpr size_t kIndexNone = 0xffffffffu; 2256d528ed9Sopenharmony_ci 2266d528ed9Sopenharmony_ci private: 2276d528ed9Sopenharmony_ci // Lookup hash set node for item |t|, also sets |*hash| to the hash value. 2286d528ed9Sopenharmony_ci UniqueVectorNode* Lookup(const T& t, size_t* hash) const { 2296d528ed9Sopenharmony_ci *hash = Hash()(t); 2306d528ed9Sopenharmony_ci return set_.Lookup<T, EqualTo>(*hash, t, vector_); 2316d528ed9Sopenharmony_ci } 2326d528ed9Sopenharmony_ci 2336d528ed9Sopenharmony_ci Vector vector_; 2346d528ed9Sopenharmony_ci UniqueVectorHashSet set_; 2356d528ed9Sopenharmony_ci}; 2366d528ed9Sopenharmony_ci 2376d528ed9Sopenharmony_ci#endif // TOOLS_GN_UNIQUE_VECTOR_H_ 238