mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 20:30:14 +01:00
The goal is to replace our stream operator APIs with format string APIs that can be made to have much less impact on inlining and other optimizations of the performance critical path through the code. Several experiments show that the most compact representation we can arrange for is one that calls an uninlined function and passes a minimal number of arguments to it. It doesn't help to do any work to minimize the arguments such as building a lambda -- the cost of extra code to merge the arguments is likely to outweigh the benefit. Initial experiments showed that switching a hot but uninlined function to this new API enabled inlining and the subsequent performance improvement. This also adds a 'TemplateString` utility that allows using a string literal as a template parameter. This is useful to remove the format string itself from the arguments passed to the function by passing it as a template argument instead. Currently, support is left in place for both APIs because with `CARBON_VLOG` we can detect whether or not any message was provided expecting a format string. This should allow incrementally migrating code to this API. I've added some test coverage in this PR, but I'll separate out any switching of parts of the codebase over. The goal is to eventually replace all the usages and remove the streaming support entirely. This PR doesn't update `CARBON_CHECK` in the same way because it is substantially more complex to switch. I have a few experimental PRs looking at that and will discuss how best to approach this with the specific challenges check presents separately. But the goal is for all of the macro-based output APIs to move to format strings rather than streams. --------- Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com> Co-authored-by: Richard Smith <richard@metafoo.co.uk>
77 lines
2.5 KiB
C++
77 lines
2.5 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#include "common/template_string.h"
|
|
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
namespace Carbon {
|
|
namespace {
|
|
|
|
using ::testing::StrEq;
|
|
|
|
template <TemplateString S>
|
|
constexpr auto FromTemplate() -> llvm::StringRef {
|
|
return S;
|
|
}
|
|
|
|
template <TemplateString S>
|
|
constexpr auto CStrFromTemplate() -> const char* {
|
|
return S.c_str();
|
|
}
|
|
|
|
// An overload that will be active when it is passed a valid `TemplateString`.
|
|
// Returns a true type to allow detection of a valid `TemplateString` argument.
|
|
template <TemplateString /*Unused*/>
|
|
constexpr auto IsValidTemplateString(int /*unused*/) -> std::true_type {
|
|
return {};
|
|
}
|
|
|
|
// A struct that can be used as a template parameter for any template argument.
|
|
struct AnythingAsTemplateArg {
|
|
// An implicit constructor that can accept any argument and discards it.
|
|
template <typename T>
|
|
// NOLINTNEXTLINE(google-explicit-constructor,bugprone-forwarding-reference-overload)
|
|
constexpr AnythingAsTemplateArg(T&& /*unused*/) {}
|
|
};
|
|
|
|
// An overload that will be active for any template argument. Returns a false
|
|
// type and is used to detect when a template argument cannot correctly match a
|
|
// `TemplateString`.
|
|
template <AnythingAsTemplateArg /*Unused*/>
|
|
constexpr auto IsValidTemplateString(...) -> std::false_type {
|
|
return {};
|
|
}
|
|
|
|
// Compile time tests with `static_assert`
|
|
static_assert(FromTemplate<"test">().size() == 4,
|
|
"Not usable in a `constexpr` context.");
|
|
static_assert(__builtin_strlen(CStrFromTemplate<"test">()) == 4,
|
|
"Not usable in a `constexpr` context.");
|
|
|
|
// The string must not contain embedded nulls.
|
|
static_assert(IsValidTemplateString<"test">(0));
|
|
static_assert(!IsValidTemplateString<"test\0test">(0));
|
|
|
|
// The string must be null-terminated.
|
|
using FourChars = char[4];
|
|
static_assert(IsValidTemplateString<FourChars{'t', 'e', 's', 0}>(0));
|
|
static_assert(!IsValidTemplateString<FourChars{'t', 'e', 's', 't'}>(0));
|
|
|
|
TEST(TemplateStringTest, Test) {
|
|
EXPECT_THAT(FromTemplate<"test">(), StrEq("test"));
|
|
EXPECT_THAT(CStrFromTemplate<"test">(), StrEq("test"));
|
|
|
|
constexpr char GoodStr[5] = {'t', 'e', 's', 't', '\0'};
|
|
static_assert(IsValidTemplateString<GoodStr>(0));
|
|
EXPECT_THAT(FromTemplate<GoodStr>(), StrEq("test"));
|
|
|
|
constexpr char BadStr[4] = {'t', 'e', 's', 't'};
|
|
static_assert(!IsValidTemplateString<BadStr>(0));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace Carbon
|