1 // Copyright 2022 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef TOOLS_GN_TARGET_PUBLIC_PAIR_H_ 6 #define TOOLS_GN_TARGET_PUBLIC_PAIR_H_ 7 8 #include "gn/immutable_vector.h" 9 #include "gn/tagged_pointer.h" 10 #include "gn/unique_vector.h" 11 12 class Target; 13 14 // A Compact encoding for a (target_ptr, is_public_flag) pair. 15 class TargetPublicPair { 16 public: 17 TargetPublicPair() = default; TargetPublicPair(const Target * target,bool is_public)18 TargetPublicPair(const Target* target, bool is_public) 19 : pair_(target, static_cast<unsigned>(is_public)) {} TargetPublicPair(std::pair<const Target *,bool> pair)20 TargetPublicPair(std::pair<const Target*, bool> pair) 21 : pair_(pair.first, static_cast<unsigned>(pair.second)) {} 22 target()23 const Target* target() const { return pair_.ptr(); } set_target(const Target * target)24 void set_target(const Target* target) { pair_.set_ptr(target); } 25 is_public()26 bool is_public() const { return pair_.tag() != 0; } set_is_public(bool is_public)27 void set_is_public(bool is_public) { pair_.set_tag(is_public ? 1 : 0); } 28 29 // Utility structs that can be used to instantiante containers 30 // that only use the target for lookups / comparisons. E.g. 31 // 32 // std::unordered_set<TargetPublicPair, 33 // TargetPublicPair::TargetHash, 34 // TargetPublicPair::TargetEqualTo> 35 // 36 // std::set<TargetPublicPair, TargetPublicPair::TargetLess> 37 // 38 struct TargetHash { operatorTargetHash39 size_t operator()(TargetPublicPair p) const noexcept { 40 return std::hash<const Target*>()(p.target()); 41 } 42 }; 43 44 struct TargetEqualTo { operatorTargetEqualTo45 bool operator()(TargetPublicPair a, TargetPublicPair b) const noexcept { 46 return a.target() == b.target(); 47 } 48 }; 49 50 struct TargetLess { operatorTargetLess51 bool operator()(TargetPublicPair a, TargetPublicPair b) const noexcept { 52 return a.target() < b.target(); 53 } 54 }; 55 56 private: 57 TaggedPointer<const Target, 1> pair_; 58 }; 59 60 // A helper type to build a list of (target, is_public) pairs, where target 61 // pointers are unique. Usage is: 62 // 63 // 1) Create builder instance. 64 // 2) Call Append() or AppendInherited() as many times as necessary. 65 // 3) Call Build() to retrieve final list as an immutable vector. 66 // 67 class TargetPublicPairListBuilder 68 : public UniqueVector<TargetPublicPair, 69 TargetPublicPair::TargetHash, 70 TargetPublicPair::TargetEqualTo> { 71 public: 72 // Add (target, is_public) to the list being constructed. If the target 73 // was not already in the list, recorded the |is_public| flag as is, 74 // otherwise, set the recorded flag to true only if |is_public| is true, or 75 // don't do anything otherwise. Append(const Target * target,bool is_public)76 void Append(const Target* target, bool is_public) { 77 auto ret = EmplaceBackWithIndex(target, is_public); 78 if (!ret.first && is_public) { 79 // UniqueVector<T>::operator[]() always returns a const reference 80 // because the returned values are lookup keys in its set-like data 81 // structure (thus modifying them would break its internal consistency). 82 // However, because TargetHash and TargetEqualTo are being used to 83 // instantiate this template, only the target() part of the value must 84 // remain constant, and it is possible to modify the is_public() part 85 // in-place safely. 86 auto* pair = const_cast<TargetPublicPair*>(&(*this)[ret.second]); 87 pair->set_is_public(true); 88 } 89 } 90 91 // Append all pairs from any container with begin() and end() iterators 92 // that dereference to values that convert to a TargetPublicPair value. 93 // If |is_public| is false, the input pair will be appended with the 94 // value of the public flag to false. 95 template < 96 typename C, 97 typename = std::void_t< 98 decltype(static_cast<TargetPublicPair>(*std::declval<C>().begin())), 99 decltype(static_cast<TargetPublicPair>(*std::declval<C>().end()))>> AppendInherited(const C & other,bool is_public)100 void AppendInherited(const C& other, bool is_public) { 101 for (const auto& pair : other) { 102 Append(pair.target(), is_public && pair.is_public()); 103 } 104 } 105 Build()106 ImmutableVector<TargetPublicPair> Build() { 107 return ImmutableVector<TargetPublicPair>(release()); 108 } 109 }; 110 111 #endif // TOOLS_GN_TARGET_PUBLIC_PAIR_H_ 112