Add ResolvedTargetDeps class Which provides simpler and faster ways to parse target dependencies. This will be used in a future CL that moves and caches target resolution computations to a dedicated class. Change-Id: Ic411989d136346cee72ca877e3c96021113dc901 Reviewed-on: https://gn-review.googlesource.com/c/gn/+/14881 Reviewed-by: Brett Wilson <brettw@chromium.org> Commit-Queue: David Turner <digit@google.com>
diff --git a/build/gen.py b/build/gen.py index eae97f9..2d109ed 100755 --- a/build/gen.py +++ b/build/gen.py
@@ -807,6 +807,7 @@ 'src/gn/path_output_unittest.cc', 'src/gn/pattern_unittest.cc', 'src/gn/pointer_set_unittest.cc', + 'src/gn/resolved_target_deps_unittest.cc', 'src/gn/runtime_deps_unittest.cc', 'src/gn/scope_per_file_provider_unittest.cc', 'src/gn/scope_unittest.cc',
diff --git a/src/gn/resolved_target_deps.h b/src/gn/resolved_target_deps.h new file mode 100644 index 0000000..57e961f --- /dev/null +++ b/src/gn/resolved_target_deps.h
@@ -0,0 +1,90 @@ +// 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_RESOLVED_TARGET_DEPS_H_ +#define TOOLS_GN_RESOLVED_TARGET_DEPS_H_ + +#include "base/containers/span.h" +#include "gn/label_ptr.h" + +#include <memory> + +// A class used to record the dependencies of a given Target in +// a way that is much more efficient to iterate over than having three +// separate LabelTargetVector instances. Technically equivalent to +// DepsIterator, but profiling shows that this class is much faster +// to use during graph-traversal heavy operations. +// +// Usage is: +// 1) Create instance, passing const references to the LabelTargetVector +// instances for the private, public and data deps for the target. +// +// 2) Use private_deps(), public_deps(), data_deps(), linked_deps() +// and all_deps() to retrieve spans that cover various subsets of +// interests. These can be used directly in for-range loops as in: +// +// for (const Target* target : resolved.linked_deps()) { +// .. +// } +// +class ResolvedTargetDeps { + public: + ResolvedTargetDeps() = default; + + ResolvedTargetDeps(const LabelTargetVector& public_deps, + const LabelTargetVector& private_deps, + const LabelTargetVector& data_deps) + : public_count_(static_cast<uint32_t>(public_deps.size())), + private_count_(static_cast<uint32_t>(private_deps.size())), + data_count_(static_cast<uint32_t>(data_deps.size())), + deps_(Allocate(public_deps, private_deps, data_deps)) {} + + size_t size() const { return private_count_ + public_count_ + data_count_; } + + base::span<const Target*> public_deps() const { + return {deps_.get(), public_count_}; + } + + base::span<const Target*> private_deps() const { + return {deps_.get() + public_count_, private_count_}; + } + + base::span<const Target*> data_deps() const { + return {deps_.get() + private_count_ + public_count_, data_count_}; + } + + base::span<const Target*> linked_deps() const { + return {deps_.get(), private_count_ + public_count_}; + } + + base::span<const Target*> all_deps() const { + return {deps_.get(), private_count_ + public_count_ + data_count_}; + } + + static std::unique_ptr<const Target*[]> Allocate( + const LabelTargetVector& public_deps, + const LabelTargetVector& private_deps, + const LabelTargetVector& data_deps) { + size_t total_size = + private_deps.size() + public_deps.size() + data_deps.size(); + auto result = std::make_unique<const Target*[]>(total_size); + const Target** ptr = result.get(); + for (const auto& pair : public_deps) + *ptr++ = pair.ptr; + for (const auto& pair : private_deps) + *ptr++ = pair.ptr; + for (const auto& pair : data_deps) + *ptr++ = pair.ptr; + return result; + } + + private: + uint32_t public_count_ = 0; + uint32_t private_count_ = 0; + uint32_t data_count_ = 0; + // Store the pointers in the following order: public, private, data. + std::unique_ptr<const Target*[]> deps_; +}; + +#endif // TOOLS_GN_RESOLVED_TARGET_DEPS_H_
diff --git a/src/gn/resolved_target_deps_unittest.cc b/src/gn/resolved_target_deps_unittest.cc new file mode 100644 index 0000000..74d623d --- /dev/null +++ b/src/gn/resolved_target_deps_unittest.cc
@@ -0,0 +1,63 @@ +// 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. + +#include "gn/resolved_target_deps.h" +#include "gn/test_with_scope.h" +#include "util/test/test.h" + +TEST(ResolvedTargetDeps, DefaultConstruction) { + ResolvedTargetDeps deps; + EXPECT_EQ(0u, deps.size()); + EXPECT_TRUE(deps.public_deps().empty()); + EXPECT_TRUE(deps.private_deps().empty()); + EXPECT_TRUE(deps.data_deps().empty()); + EXPECT_TRUE(deps.linked_deps().empty()); + EXPECT_TRUE(deps.all_deps().empty()); +} + +TEST(ResolvedTargetDeps, Construction) { + TestWithScope setup; + TestTarget a(setup, "//foo:a", Target::STATIC_LIBRARY); + TestTarget b(setup, "//foo:b", Target::SOURCE_SET); + TestTarget c(setup, "//foo:c", Target::SOURCE_SET); + TestTarget d(setup, "//foo:d", Target::SOURCE_SET); + TestTarget e(setup, "//foo:e", Target::EXECUTABLE); + + LabelTargetVector public_vec; + LabelTargetVector private_vec; + LabelTargetVector data_vec; + + public_vec.emplace_back(&a); + public_vec.emplace_back(&b); + private_vec.emplace_back(&c); + private_vec.emplace_back(&d); + data_vec.emplace_back(&e); + + ResolvedTargetDeps deps(public_vec, private_vec, data_vec); + EXPECT_EQ(5u, deps.size()); + + EXPECT_EQ(2u, deps.public_deps().size()); + EXPECT_EQ(&a, deps.public_deps()[0]); + EXPECT_EQ(&b, deps.public_deps()[1]); + + EXPECT_EQ(2u, deps.private_deps().size()); + EXPECT_EQ(&c, deps.private_deps()[0]); + EXPECT_EQ(&d, deps.private_deps()[1]); + + EXPECT_EQ(1u, deps.data_deps().size()); + EXPECT_EQ(&e, deps.data_deps()[0]); + + EXPECT_EQ(4u, deps.linked_deps().size()); + EXPECT_EQ(&a, deps.linked_deps()[0]); + EXPECT_EQ(&b, deps.linked_deps()[1]); + EXPECT_EQ(&c, deps.linked_deps()[2]); + EXPECT_EQ(&d, deps.linked_deps()[3]); + + EXPECT_EQ(5u, deps.all_deps().size()); + EXPECT_EQ(&a, deps.all_deps()[0]); + EXPECT_EQ(&b, deps.all_deps()[1]); + EXPECT_EQ(&c, deps.all_deps()[2]); + EXPECT_EQ(&d, deps.all_deps()[3]); + EXPECT_EQ(&e, deps.all_deps()[4]); +}