| // Copyright 2022 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 TOOLS_GN_TARGET_PUBLIC_PAIR_H_ |
| #define TOOLS_GN_TARGET_PUBLIC_PAIR_H_ |
| |
| #include "gn/unique_vector.h" |
| |
| class Target; |
| |
| // C++ and Rust target resolution requires computing uniquified and |
| // ordered lists of static/shared libraries that are collected through |
| // the target's dependency tree. |
| // |
| // Maintaining the order is important to ensure the libraries are linked |
| // in the correct order in the final link command line. |
| // |
| // Also each library must only appear once in the final list, even though |
| // it may appear multiple times during the dependency tree walk, either as |
| // a "private" or "public" dependency. |
| // |
| // The TargetPublicPair class below encodes a (target_ptr, is_public_flag) |
| // pair, with convenience accessors and utility structs. |
| // |
| // The TargetPublicPairListBuilder is a builder-pattern class that generates |
| // a unique vector of TargetPublicPair values (i.e. the final list described |
| // above), and supporting the special logic required to build these lists |
| // (see the comments for its Append() and AppendInherited() methods). |
| // |
| // A convenience encoding for a (target_ptr, is_public_flag) pair. |
| class TargetPublicPair { |
| public: |
| TargetPublicPair() = default; |
| TargetPublicPair(const Target* target, bool is_public) |
| : target_(target), is_public_(is_public) {} |
| TargetPublicPair(std::pair<const Target*, bool> pair) |
| : target_(pair.first), is_public_(pair.second) {} |
| |
| const Target* target() const { return target_; } |
| void set_target(const Target* target) { target_ = target; } |
| |
| bool is_public() const { return is_public_; } |
| void set_is_public(bool is_public) { is_public_ = is_public; } |
| |
| // Utility structs that can be used to instantiante containers |
| // that only use the target for lookups / comparisons. E.g. |
| // |
| // std::unordered_set<TargetPublicPair, |
| // TargetPublicPair::TargetHash, |
| // TargetPublicPair::TargetEqualTo> |
| // |
| // std::set<TargetPublicPair, TargetPublicPair::TargetLess> |
| // |
| struct TargetHash { |
| size_t operator()(TargetPublicPair p) const noexcept { |
| return std::hash<const Target*>()(p.target()); |
| } |
| }; |
| |
| struct TargetEqualTo { |
| bool operator()(TargetPublicPair a, TargetPublicPair b) const noexcept { |
| return a.target() == b.target(); |
| } |
| }; |
| |
| struct TargetLess { |
| bool operator()(TargetPublicPair a, TargetPublicPair b) const noexcept { |
| return a.target() < b.target(); |
| } |
| }; |
| |
| private: |
| const Target* target_ = nullptr; |
| bool is_public_ = false; |
| }; |
| |
| // A helper type to build a uniquified ordered vector of TargetPublicPair |
| // instances. Usage is: |
| // |
| // 1) Create builder instance. |
| // |
| // 2) Call Append() to add a direct dependency, or AppendInherited() to add |
| // transitive ones, as many times as necessary. |
| // |
| // 3) Call Build() to retrieve final list as a vector. |
| // |
| class TargetPublicPairListBuilder |
| : public UniqueVector<TargetPublicPair, |
| TargetPublicPair::TargetHash, |
| TargetPublicPair::TargetEqualTo> { |
| public: |
| // Add (target, is_public) to the list being constructed. If the target |
| // was not already in the list, record the |is_public| flag as is, |
| // otherwise, set the recorded flag to true only if |is_public| is true, or |
| // don't do anything otherwise. |
| void Append(const Target* target, bool is_public) { |
| auto ret = EmplaceBackWithIndex(target, is_public); |
| if (!ret.first && is_public) { |
| // UniqueVector<T>::operator[]() always returns a const reference |
| // because the returned values are lookup keys in its set-like data |
| // structure (thus modifying them would break its internal consistency). |
| // However, because TargetHash and TargetEqualTo are being used to |
| // instantiate this template, only the target() part of the value must |
| // remain constant, and it is possible to modify the is_public() part |
| // in-place safely. |
| auto* pair = const_cast<TargetPublicPair*>(&(*this)[ret.second]); |
| pair->set_is_public(true); |
| } |
| } |
| |
| // Append all pairs from any container with begin() and end() iterators |
| // that dereference to values that convert to a TargetPublicPair value. |
| // If |is_public| is false, the input pair will be appended with the |
| // value of the public flag to false. |
| template < |
| typename C, |
| typename = std::void_t< |
| decltype(static_cast<TargetPublicPair>(*std::declval<C>().begin())), |
| decltype(static_cast<TargetPublicPair>(*std::declval<C>().end()))>> |
| void AppendInherited(const C& other, bool is_public) { |
| for (const auto& pair : other) { |
| Append(pair.target(), is_public && pair.is_public()); |
| } |
| } |
| |
| // Build and return the final list to the caller. |
| std::vector<TargetPublicPair> Build() { return release(); } |
| }; |
| |
| #endif // TOOLS_GN_TARGET_PUBLIC_PAIR_H_ |