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/unique_vector.h" 9 10 class Target; 11 12 // C++ and Rust target resolution requires computing uniquified and 13 // ordered lists of static/shared libraries that are collected through 14 // the target's dependency tree. 15 // 16 // Maintaining the order is important to ensure the libraries are linked 17 // in the correct order in the final link command line. 18 // 19 // Also each library must only appear once in the final list, even though 20 // it may appear multiple times during the dependency tree walk, either as 21 // a "private" or "public" dependency. 22 // 23 // The TargetPublicPair class below encodes a (target_ptr, is_public_flag) 24 // pair, with convenience accessors and utility structs. 25 // 26 // The TargetPublicPairListBuilder is a builder-pattern class that generates 27 // a unique vector of TargetPublicPair values (i.e. the final list described 28 // above), and supporting the special logic required to build these lists 29 // (see the comments for its Append() and AppendInherited() methods). 30 // 31 // A convenience encoding for a (target_ptr, is_public_flag) pair. 32 class TargetPublicPair { 33 public: 34 TargetPublicPair() = default; TargetPublicPair(const Target * target,bool is_public)35 TargetPublicPair(const Target* target, bool is_public) 36 : target_(target), is_public_(is_public) {} TargetPublicPair(std::pair<const Target *,bool> pair)37 TargetPublicPair(std::pair<const Target*, bool> pair) 38 : target_(pair.first), is_public_(pair.second) {} 39 target()40 const Target* target() const { return target_; } set_target(const Target * target)41 void set_target(const Target* target) { target_ = target; } 42 is_public()43 bool is_public() const { return is_public_; } set_is_public(bool is_public)44 void set_is_public(bool is_public) { is_public_ = is_public; } 45 46 // Utility structs that can be used to instantiante containers 47 // that only use the target for lookups / comparisons. E.g. 48 // 49 // std::unordered_set<TargetPublicPair, 50 // TargetPublicPair::TargetHash, 51 // TargetPublicPair::TargetEqualTo> 52 // 53 // std::set<TargetPublicPair, TargetPublicPair::TargetLess> 54 // 55 struct TargetHash { operatorTargetHash56 size_t operator()(TargetPublicPair p) const noexcept { 57 return std::hash<const Target*>()(p.target()); 58 } 59 }; 60 61 struct TargetEqualTo { operatorTargetEqualTo62 bool operator()(TargetPublicPair a, TargetPublicPair b) const noexcept { 63 return a.target() == b.target(); 64 } 65 }; 66 67 struct TargetLess { operatorTargetLess68 bool operator()(TargetPublicPair a, TargetPublicPair b) const noexcept { 69 return a.target() < b.target(); 70 } 71 }; 72 73 private: 74 const Target* target_ = nullptr; 75 bool is_public_ = false; 76 }; 77 78 // A helper type to build a uniquified ordered vector of TargetPublicPair 79 // instances. Usage is: 80 // 81 // 1) Create builder instance. 82 // 83 // 2) Call Append() to add a direct dependency, or AppendInherited() to add 84 // transitive ones, as many times as necessary. 85 // 86 // 3) Call Build() to retrieve final list as a vector. 87 // 88 class TargetPublicPairListBuilder 89 : public UniqueVector<TargetPublicPair, 90 TargetPublicPair::TargetHash, 91 TargetPublicPair::TargetEqualTo> { 92 public: 93 // Add (target, is_public) to the list being constructed. If the target 94 // was not already in the list, record the |is_public| flag as is, 95 // otherwise, set the recorded flag to true only if |is_public| is true, or 96 // don't do anything otherwise. Append(const Target * target,bool is_public)97 void Append(const Target* target, bool is_public) { 98 auto ret = EmplaceBackWithIndex(target, is_public); 99 if (!ret.first && is_public) { 100 // UniqueVector<T>::operator[]() always returns a const reference 101 // because the returned values are lookup keys in its set-like data 102 // structure (thus modifying them would break its internal consistency). 103 // However, because TargetHash and TargetEqualTo are being used to 104 // instantiate this template, only the target() part of the value must 105 // remain constant, and it is possible to modify the is_public() part 106 // in-place safely. 107 auto* pair = const_cast<TargetPublicPair*>(&(*this)[ret.second]); 108 pair->set_is_public(true); 109 } 110 } 111 112 // Append all pairs from any container with begin() and end() iterators 113 // that dereference to values that convert to a TargetPublicPair value. 114 // If |is_public| is false, the input pair will be appended with the 115 // value of the public flag to false. 116 template < 117 typename C, 118 typename = std::void_t< 119 decltype(static_cast<TargetPublicPair>(*std::declval<C>().begin())), 120 decltype(static_cast<TargetPublicPair>(*std::declval<C>().end()))>> AppendInherited(const C & other,bool is_public)121 void AppendInherited(const C& other, bool is_public) { 122 for (const auto& pair : other) { 123 Append(pair.target(), is_public && pair.is_public()); 124 } 125 } 126 127 // Build and return the final list to the caller. Build()128 std::vector<TargetPublicPair> Build() { return release(); } 129 }; 130 131 #endif // TOOLS_GN_TARGET_PUBLIC_PAIR_H_ 132