blob: c8ff655c7410a520f09361ce3331b11b5929a594 [file] [log] [blame]
// 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/immutable_vector.h"
#include "gn/tagged_pointer.h"
#include "gn/unique_vector.h"
class Target;
// A Compact encoding for a (target_ptr, is_public_flag) pair.
class TargetPublicPair {
public:
TargetPublicPair() = default;
TargetPublicPair(const Target* target, bool is_public)
: pair_(target, static_cast<unsigned>(is_public)) {}
TargetPublicPair(std::pair<const Target*, bool> pair)
: pair_(pair.first, static_cast<unsigned>(pair.second)) {}
const Target* target() const { return pair_.ptr(); }
void set_target(const Target* target) { pair_.set_ptr(target); }
bool is_public() const { return pair_.tag() != 0; }
void set_is_public(bool is_public) { pair_.set_tag(is_public ? 1 : 0); }
// 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:
TaggedPointer<const Target, 1> pair_;
};
// A helper type to build a list of (target, is_public) pairs, where target
// pointers are unique. Usage is:
//
// 1) Create builder instance.
// 2) Call Append() or AppendInherited() as many times as necessary.
// 3) Call Build() to retrieve final list as an immutable 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, recorded 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());
}
}
ImmutableVector<TargetPublicPair> Build() {
return ImmutableVector<TargetPublicPair>(release());
}
};
#endif // TOOLS_GN_TARGET_PUBLIC_PAIR_H_