8000 Replace `std::any` with a custom solution. (#20251) · protocolbuffers/protobuf@6250d09 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6250d09

Browse files
Replace std::any with a custom solution. (#20251)
`std::any` leads to compiler errors in some versions of gcc during constructibility trait checks. Now that we can guarantee it, return by reference to avoid extra costs in copies. PiperOrigin-RevId: 723478744 Co-authored-by: Protobuf Team Bot <protobuf-github-bot@google.com>
1 parent d9ac521 commit 6250d09

File tree

2 files changed

+35
-12
lines changed

2 files changed

+35
-12
lines changed

src/google/protobuf/descriptor.h

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__
3232
#define GOOGLE_PROTOBUF_DESCRIPTOR_H__
3333

34-
#include <any>
3534
#include <atomic>
3635
#include <cstdint>
3736
#include <iterator>
@@ -2455,11 +2454,20 @@ class PROTOBUF_EXPORT DescriptorPool {
24552454
friend class google::protobuf::descriptor_unittest::ValidationErrorTest;
24562455
friend class ::google::protobuf::compiler::CommandLineInterface;
24572456
friend class TextFormat;
2457+
2458+
struct MemoBase {
2459+
virtual ~MemoBase() = default;
2460+
};
2461+
template <typename T>
2462+
struct MemoData : MemoBase {
2463+
T value;
2464+
};
2465+
24582466
// Memoize a projection of a field. This is used to cache the results of
24592467
// calling a function on a field, used for expensive descriptor calculations.
24602468
template <typename Func>
2461-
auto MemoizeProjection(const FieldDescriptor* field, Func func) const {
2462-
using ResultT = decltype(func(field));
2469+
const auto& MemoizeProjection(const FieldDescriptor* field, Func func) const {
2470+
using ResultT = std::decay_t<decltype(func(field))>;
24632471
ABSL_DCHECK(field->file()->pool() == this);
24642472
static_assert(std::is_empty_v<Func>);
24652473
// This static bool is unique per-Func, so its address can be used as a key.
@@ -2469,15 +2477,21 @@ class PROTOBUF_EXPORT DescriptorPool {
24692477
absl::ReaderMutexLock lock(&field_memo_table_mutex_);
24702478
auto it = field_memo_table_.find(key);
24712479
if (it != field_memo_table_.end()) {
2472-
return std::any_cast<ResultT>(it->second);
2480+
return internal::DownCast<const MemoData<ResultT>&>(*it->second).value;
24732481
}
24742482
}
2475-
ResultT result = func(field);
2483+
auto result = std::make_unique<MemoData<ResultT>>();
2484+
result->value = func(field);
24762485
{
24772486
absl::MutexLock lock(&field_memo_table_mutex_);
2478-
field_memo_table_[key] = result;
2487+
auto& res = field_memo_table_[key];
2488+
// Only initialize the first time. We don't want to invalidate old
2489+
// references.
2490+
if (res == nullptr) {
2491+
res = std::move(result);
2492+
}
2493+
return internal::DownCast<const MemoData<ResultT>&>(*res).value;
24792494
}
2480-
return result;
24812495
}
24822496
// Return true if the given name is a sub-symbol of any non-package
24832497
// descriptor that already exists in the descriptor pool. (The full
@@ -2537,9 +2551,12 @@ class PROTOBUF_EXPORT DescriptorPool {
25372551
Symbol NewPlaceholderWithMutexHeld(absl::string_view name,
25382552
PlaceholderType placeholder_type) const;
25392553

2554+
#ifndef SWIG
25402555
mutable absl::Mutex field_memo_table_mutex_;
2541-
mutable absl::flat_hash_map<std::pair<const void*, const void*>, std::any>
2556+
mutable absl::flat_hash_map<std::pair<const void*, const void*>,
2557+
std::unique_ptr<MemoBase>>
25422558
field_memo_table_ ABSL_GUARDED_BY(field_memo_table_mutex_);
2559+
#endif // SWIG
25432560

25442561
// If fallback_database_ is nullptr, this is nullptr. Otherwise, this is a
25452562
// mutex which must be locked while accessing tables_.

src/google/protobuf/descriptor_unittest.cc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <string>
2828
#include <thread> // NOLINT
2929
#include <tuple>
30+
#include <type_traits>
3031
#include <utility>
3132
#include <vector>
3233

@@ -11819,8 +11820,8 @@ TEST_F(DescriptorPoolFeaturesTest, ResolvesFeaturesFor) {
1181911820
class DescriptorPoolMemoizationTest : public ::testing::Test {
1182011821
protected:
1182111822
template <typename Func>
11822-
auto MemoizeProjection(const DescriptorPool* pool,
11823-
const FieldDescriptor* field, Func func) {
11823+
const auto& MemoizeProjection(const DescriptorPool* pool,
11824+
const FieldDescriptor* field, Func func) {
1182411825
return pool->MemoizeProjection(field, func);
1182511826
};
1182611827
};
@@ -11834,15 +11835,20 @@ TEST_F(DescriptorPoolMemoizationTest, MemoizeProjectionBasic) {
1183411835
proto2_unittest::TestAllTypes message;
1183511836
const Descriptor* descriptor = message.GetDescriptor();
1183611837

11837-
auto name = DescriptorPoolMemoizationTest::MemoizeProjection(
11838+
const auto& name = DescriptorPoolMemoizationTest::MemoizeProjection(
1183811839
descriptor->file()->pool(), descriptor->field(0), name_lambda);
11839-
auto dupe_name = DescriptorPoolMemoizationTest::MemoizeProjection(
11840+
const auto& dupe_name = DescriptorPoolMemoizationTest::MemoizeProjection(
1184011841
descriptor->file()->pool(), descriptor->field(0), name_lambda);
1184111842

1184211843
ASSERT_EQ(counter, 1);
1184311844
ASSERT_EQ(name, "proto2_unittest.TestAllTypes.optional_int32");
1184411845
ASSERT_EQ(dupe_name, "proto2_unittest.TestAllTypes.optional_int32");
1184511846

11847+
// Check that they are references aliasing the same object.
11848+
EXPECT_TRUE(
11849+
(std::is_same_v<decltype(name), const decltype(descriptor->name()) &>));
11850+
EXPECT_EQ(&name, &dupe_name);
11851+
1184611852
auto other_name = DescriptorPoolMemoizationTest::MemoizeProjection(
1184711853
descriptor->file()->pool(), descriptor->field(1), name_lambda);
1184811854

0 commit comments

Comments
 (0)
0