-
Notifications
You must be signed in to change notification settings - Fork 613
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
1 parent
a0aa1db
commit 7db5a06
Showing
2 changed files
with
136 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <string> | ||
#include <type_traits> | ||
#include <typeinfo> | ||
#include <utility> | ||
|
||
#include <folly/Traits.h> | ||
#include <folly/lang/SafeAssert.h> | ||
|
||
namespace apache::thrift::util { | ||
|
||
/** | ||
* A type-safe type-erased const reference to an object. | ||
* | ||
* Unlike TypeErasedValue, the referred-to object is not owned by this class. | ||
* The user must ensure that the aforementioned object outlives any access | ||
* through an object of this class. | ||
* | ||
* Access is provided through the templated value<T>() method which checks that | ||
* the referred-to object is indeed of type T. This is the main difference | ||
* between TypeErasedRef and const void* — the latter has no safety checks. | ||
* | ||
* TypeErasedRef is copyable. The copy points to the same object as the | ||
* original. | ||
*/ | ||
class TypeErasedRef { | ||
public: | ||
const std::type_info& type() const noexcept { return *typeInfo_; } | ||
const void* ptr() const noexcept { return ptr_; } | ||
|
||
template <class T> | ||
bool holds_alternative() const noexcept { | ||
return type() == typeid(T); | ||
} | ||
|
||
template <class T> | ||
const folly::remove_cvref_t<T>& value() const { | ||
if (!holds_alternative<T>()) { | ||
throw std::bad_cast(); | ||
} | ||
return value_unchecked<T>(); | ||
} | ||
|
||
template <class T> | ||
const folly::remove_cvref_t<T>& value_unchecked() const noexcept { | ||
FOLLY_SAFE_DCHECK( | ||
holds_alternative<T>(), | ||
"Tried to call value_unchecked() on TypeErasedRef with incompatible type"); | ||
return *reinterpret_cast<const folly::remove_cvref_t<T>*>(ptr_); | ||
} | ||
|
||
TypeErasedRef(const TypeErasedRef& other) noexcept = default; | ||
TypeErasedRef& operator=(const TypeErasedRef& other) noexcept = default; | ||
|
||
template <class T> | ||
static TypeErasedRef of(folly::remove_cvref_t<T>&&) = delete; | ||
|
||
template <class T> | ||
static TypeErasedRef of(const folly::remove_cvref_t<T>& object) noexcept { | ||
return fromTypeInfoUnchecked( | ||
static_cast<const void*>(std::addressof(object)), typeid(T)); | ||
} | ||
|
||
static TypeErasedRef fromTypeInfoUnchecked( | ||
const void* ptr, const std::type_info& typeInfo) noexcept { | ||
return TypeErasedRef(ptr, typeInfo); | ||
} | ||
|
||
private: | ||
TypeErasedRef(const void* ptr, const std::type_info& typeInfo) noexcept | ||
: ptr_(ptr), typeInfo_(&typeInfo) {} | ||
|
||
const void* ptr_; | ||
const std::type_info* typeInfo_; | ||
}; | ||
|
||
} // namespace apache::thrift::util |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#include <folly/portability/GTest.h> | ||
|
||
#include <thrift/lib/cpp2/util/TypeErasedRef.h> | ||
|
||
using apache::thrift::util::TypeErasedRef; | ||
|
||
TEST(TypeErasedRefTest, Basic) { | ||
std::string str = "hello"; | ||
auto ref1 = TypeErasedRef::of<std::string>(str); | ||
auto ref1Copy = ref1; | ||
|
||
std::string str2 = "world"; | ||
auto ref2 = TypeErasedRef::of<std::string>(str2); | ||
EXPECT_EQ(ref2.value<std::string>(), str2); | ||
ref2 = ref1; | ||
|
||
for (auto& ref : {ref1, ref1Copy, ref2}) { | ||
EXPECT_EQ(std::uintptr_t(ref.ptr()), std::uintptr_t(&str)); | ||
EXPECT_EQ(ref.type(), typeid(std::string)); | ||
EXPECT_TRUE(ref.holds_alternative<std::string>()); | ||
EXPECT_FALSE(ref.holds_alternative<int>()); | ||
EXPECT_EQ(ref.value<std::string>(), str); | ||
EXPECT_EQ(ref.value<const std::string&>(), str); | ||
EXPECT_THROW(ref.value<int>(), std::bad_cast); | ||
} | ||
} |