• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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