Skip to content

Commit 7db5a06

Browse files
praihanfacebook-github-bot
authored andcommitted
TypeErasedRef
Summary: The doc block explains it well. It's essentially a `void*` with an accompanying `std::type_info` which provides some basic runtime type safety. Reviewed By: sethdelliott Differential Revision: D58217404 fbshipit-source-id: 609414a0e21fe59c514d8d1340a6bc5c95a34a89
1 parent a0aa1db commit 7db5a06

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed

thrift/lib/cpp2/util/TypeErasedRef.h

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include <string>
20+
#include <type_traits>
21+
#include <typeinfo>
22+
#include <utility>
23+
24+
#include <folly/Traits.h>
25+
#include <folly/lang/SafeAssert.h>
26+
27+
namespace apache::thrift::util {
28+
29+
/**
30+
* A type-safe type-erased const reference to an object.
31+
*
32+
* Unlike TypeErasedValue, the referred-to object is not owned by this class.
33+
* The user must ensure that the aforementioned object outlives any access
34+
* through an object of this class.
35+
*
36+
* Access is provided through the templated value<T>() method which checks that
37+
* the referred-to object is indeed of type T. This is the main difference
38+
* between TypeErasedRef and const void* — the latter has no safety checks.
39+
*
40+
* TypeErasedRef is copyable. The copy points to the same object as the
41+
* original.
42+
*/
43+
class TypeErasedRef {
44+
public:
45+
const std::type_info& type() const noexcept { return *typeInfo_; }
46+
const void* ptr() const noexcept { return ptr_; }
47+
48+
template <class T>
49+
bool holds_alternative() const noexcept {
50+
return type() == typeid(T);
51+
}
52+
53+
template <class T>
54+
const folly::remove_cvref_t<T>& value() const {
55+
if (!holds_alternative<T>()) {
56+
throw std::bad_cast();
57+
}
58+
return value_unchecked<T>();
59+
}
60+
61+
template <class T>
62+
const folly::remove_cvref_t<T>& value_unchecked() const noexcept {
63+
FOLLY_SAFE_DCHECK(
64+
holds_alternative<T>(),
65+
"Tried to call value_unchecked() on TypeErasedRef with incompatible type");
66+
return *reinterpret_cast<const folly::remove_cvref_t<T>*>(ptr_);
67+
}
68+
69+
TypeErasedRef(const TypeErasedRef& other) noexcept = default;
70+
TypeErasedRef& operator=(const TypeErasedRef& other) noexcept = default;
71+
72+
template <class T>
73+
static TypeErasedRef of(folly::remove_cvref_t<T>&&) = delete;
74+
75+
template <class T>
76+
static TypeErasedRef of(const folly::remove_cvref_t<T>& object) noexcept {
77+
return fromTypeInfoUnchecked(
78+
static_cast<const void*>(std::addressof(object)), typeid(T));
79+
}
80+
81+
static TypeErasedRef fromTypeInfoUnchecked(
82+
const void* ptr, const std::type_info& typeInfo) noexcept {
83+
return TypeErasedRef(ptr, typeInfo);
84+
}
85+
86+
private:
87+
TypeErasedRef(const void* ptr, const std::type_info& typeInfo) noexcept
88+
: ptr_(ptr), typeInfo_(&typeInfo) {}
89+
90+
const void* ptr_;
91+
const std::type_info* typeInfo_;
92+
};
93+
94+
} // namespace apache::thrift::util
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <folly/portability/GTest.h>
18+
19+
#include <thrift/lib/cpp2/util/TypeErasedRef.h>
20+
21+
using apache::thrift::util::TypeErasedRef;
22+
23+
TEST(TypeErasedRefTest, Basic) {
24+
std::string str = "hello";
25+
auto ref1 = TypeErasedRef::of<std::string>(str);
26+
auto ref1Copy = ref1;
27+
28+
std::string str2 = "world";
29+
auto ref2 = TypeErasedRef::of<std::string>(str2);
30+
EXPECT_EQ(ref2.value<std::string>(), str2);
31+
ref2 = ref1;
32+
33+
for (auto& ref : {ref1, ref1Copy, ref2}) {
34+
EXPECT_EQ(std::uintptr_t(ref.ptr()), std::uintptr_t(&str));
35+
EXPECT_EQ(ref.type(), typeid(std::string));
36+
EXPECT_TRUE(ref.holds_alternative<std::string>());
37+
EXPECT_FALSE(ref.holds_alternative<int>());
38+
EXPECT_EQ(ref.value<std::string>(), str);
39+
EXPECT_EQ(ref.value<const std::string&>(), str);
40+
EXPECT_THROW(ref.value<int>(), std::bad_cast);
41+
}
42+
}

0 commit comments

Comments
 (0)