protos: Collapse ClearMessage template

We introduce Ptr removal so that our helper functions can be agnostically passed in a Ptr<T> or a T*.

We utilize SFINAE to determine if PtrOrRaw. If the target is const, or not in {T, T*, Ptr<T>}, the template will not match and be discarded (but still compile successfully).

PiperOrigin-RevId: 640198851
pull/16939/head
Hong Shin 8 months ago committed by Copybara-Service
parent a1c99afd98
commit b57c374146
  1. 32
      protos/protos.h
  2. 50
      protos_generator/tests/test_generated.cc

@ -242,6 +242,26 @@ absl::Status SetExtension(upb_Message* message, upb_Arena* message_arena,
const upb_MiniTableExtension* ext, const upb_MiniTableExtension* ext,
const upb_Message* extension); const upb_Message* extension);
template <typename T>
struct RemovePtr;
template <typename T>
struct RemovePtr<Ptr<T>> {
using type = T;
};
template <typename T>
struct RemovePtr<T*> {
using type = T;
};
template <typename T>
using RemovePtrT = typename RemovePtr<T>::type;
template <typename T, typename U = RemovePtrT<T>,
typename = std::enable_if_t<!std::is_const_v<U>>>
using PtrOrRaw = T;
} // namespace internal } // namespace internal
template <typename T> template <typename T>
@ -280,14 +300,10 @@ void DeepCopy(const T* source_message, T* target_message) {
} }
template <typename T> template <typename T>
void ClearMessage(Ptr<T> message) { void ClearMessage(internal::PtrOrRaw<T> message) {
static_assert(!std::is_const_v<T>, ""); auto ptr = Ptr(message);
upb_Message_Clear(internal::GetInternalMsg(message), T::minitable()); auto minitable = internal::GetMiniTable(ptr);
} upb_Message_Clear(internal::GetInternalMsg(ptr), minitable);
template <typename T>
void ClearMessage(T* message) {
ClearMessage(protos::Ptr(message));
} }
class ExtensionRegistry { class ExtensionRegistry {

@ -1157,6 +1157,44 @@ TEST(CppGeneratedCode, ClearMessage) {
EXPECT_FALSE(::protos::HasExtension(&model, theme)); EXPECT_FALSE(::protos::HasExtension(&model, theme));
} }
TEST(CppGeneratedCode, CanInvokeClearMessageWithPtr) {
// Fill model.
TestModel model;
model.set_int64(5);
auto new_child = model.add_child_models();
// Clear using Ptr<T>
auto ptr = ::protos::Ptr<TestModel>(&model);
::protos::ClearMessage(ptr);
// Successful clear
EXPECT_FALSE(model.has_int64());
}
TEST(CppGeneratedCode, CanInvokeClearMessageWithRawPtr) {
// Fill model.
TestModel model;
model.set_int64(5);
auto new_child = model.add_child_models();
// Clear using T*
::protos::ClearMessage(&model);
// Successful clear
EXPECT_FALSE(model.has_int64());
}
template <typename T>
bool CanCallClearMessage() {
return Requires<T>([](auto x) -> decltype(::protos::ClearMessage(x)) {});
}
TEST(CppGeneratedCode, CannotInvokeClearMessageWithConstPtr) {
EXPECT_TRUE(CanCallClearMessage<::protos::Ptr<TestModel>>());
EXPECT_FALSE(CanCallClearMessage<::protos::Ptr<const TestModel>>());
}
TEST(CppGeneratedCode, CannotInvokeClearMessageWithConstRawPtr) {
EXPECT_TRUE(CanCallClearMessage<TestModel*>());
EXPECT_FALSE(CanCallClearMessage<const TestModel*>());
}
TEST(CppGeneratedCode, DeepCopy) { TEST(CppGeneratedCode, DeepCopy) {
// Fill model. // Fill model.
TestModel model; TestModel model;
@ -1203,16 +1241,10 @@ TEST(CppGeneratedCode, FieldNumberConstants) {
EXPECT_EQ(225, TestModel::kChildMapFieldNumber); EXPECT_EQ(225, TestModel::kChildMapFieldNumber);
} }
// TODO : Add BUILD rule to test failures below. TEST(CppGeneratedCode, ClearConstMessageShouldFailForConstChild) {
#ifdef TEST_CLEAR_MESSAGE_FAILURE
TEST(CppGeneratedCode, ClearConstMessageShouldFail) {
// Fill model.
TestModel model; TestModel model;
model.set_int64(5); EXPECT_FALSE(CanCallClearMessage<decltype(model.child_model_1())>());
model.set_str2("Hello"); EXPECT_TRUE(CanCallClearMessage<decltype(model.mutable_child_model_1())>());
// Only mutable_ can be cleared not Ptr<const T>.
::protos::ClearMessage(model.child_model_1());
} }
#endif
} // namespace } // namespace

Loading…
Cancel
Save