mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 00:32:11 +00:00
Bug 1584256 - Add IPDLParamTraits for Variant. r=nika,jwalden
Differential Revision: https://phabricator.services.mozilla.com/D47607 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
183f92d2ca
commit
22e4870bda
@ -992,12 +992,10 @@ struct ParamTraits<mozilla::Variant<Ts...>> {
|
||||
if (tag == N - 1) {
|
||||
// Recall, even though the template parameter is N, we are
|
||||
// actually interested in the N - 1 tag.
|
||||
typename mozilla::detail::Nth<N - 1, Ts...>::Type val;
|
||||
if (ReadParam(msg, iter, &val)) {
|
||||
*result = mozilla::AsVariant(val);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
// Default construct our field within the result outparameter and
|
||||
// directly deserialize into the variant. Note that this means that
|
||||
// every type in Ts needs to be default constructible
|
||||
return ReadParam(msg, iter, &result->template emplace<N - 1>());
|
||||
} else {
|
||||
return Next::Read(msg, iter, tag, result);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "chrome/common/ipc_message_utils.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Variant.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
@ -350,6 +351,75 @@ struct IPDLParamTraits<Tuple<Ts...>> {
|
||||
}
|
||||
};
|
||||
|
||||
template <class... Ts>
|
||||
struct IPDLParamTraits<mozilla::Variant<Ts...>> {
|
||||
typedef mozilla::Variant<Ts...> paramType;
|
||||
using Tag = typename mozilla::detail::VariantTag<Ts...>::Type;
|
||||
|
||||
static void Write(IPC::Message* aMsg, IProtocol* aActor,
|
||||
const paramType& aParam) {
|
||||
WriteIPDLParam(aMsg, aActor, aParam.tag);
|
||||
aParam.match(
|
||||
[aMsg, aActor](const auto& t) { WriteIPDLParam(aMsg, aActor, t); });
|
||||
}
|
||||
|
||||
static void Write(IPC::Message* aMsg, IProtocol* aActor, paramType&& aParam) {
|
||||
WriteIPDLParam(aMsg, aActor, aParam.tag);
|
||||
aParam.match([aMsg, aActor](auto& t) {
|
||||
WriteIPDLParam(aMsg, aActor, std::move(t));
|
||||
});
|
||||
}
|
||||
|
||||
// Because VariantReader is a nested struct, we need the dummy template
|
||||
// parameter to avoid making VariantReader<0> an explicit specialization,
|
||||
// which is not allowed for a nested class template
|
||||
template <size_t N, typename dummy = void>
|
||||
struct VariantReader {
|
||||
using Next = VariantReader<N - 1>;
|
||||
|
||||
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
||||
IProtocol* aActor, Tag aTag, paramType* aResult) {
|
||||
// Since the VariantReader specializations start at N , we need to
|
||||
// subtract one to look at N - 1, the first valid tag. This means our
|
||||
// comparisons are off by 1. If we get to N = 0 then we have failed to
|
||||
// find a match to the tag.
|
||||
if (aTag == N - 1) {
|
||||
// Recall, even though the template parameter is N, we are
|
||||
// actually interested in the N - 1 tag.
|
||||
// Default construct our field within the result outparameter and
|
||||
// directly deserialize into the variant. Note that this means that
|
||||
// every type in Ts needs to be default constructible.
|
||||
return ReadIPDLParam(aMsg, aIter, aActor,
|
||||
&aResult->template emplace<N - 1>());
|
||||
}
|
||||
return Next::Read(aMsg, aIter, aActor, aTag, aResult);
|
||||
}
|
||||
|
||||
}; // VariantReader<N>
|
||||
|
||||
// Since we are conditioning on tag = N - 1 in the preceding specialization,
|
||||
// if we get to `VariantReader<0, dummy>` we have failed to find
|
||||
// a matching tag.
|
||||
template <typename dummy>
|
||||
struct VariantReader<0, dummy> {
|
||||
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
||||
IProtocol* aActor, Tag aTag, paramType* aResult) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
||||
IProtocol* aActor, paramType* aResult) {
|
||||
Tag tag;
|
||||
if (!ReadIPDLParam(aMsg, aIter, aActor, &tag)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return VariantReader<sizeof...(Ts)>::Read(aMsg, aIter, aActor, tag,
|
||||
aResult);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -27,6 +27,11 @@ struct ParamTraits;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace ipc {
|
||||
template <typename T>
|
||||
struct IPDLParamTraits;
|
||||
} // namespace ipc
|
||||
|
||||
template <typename... Ts>
|
||||
class Variant;
|
||||
|
||||
@ -505,6 +510,7 @@ struct VariantIndex {
|
||||
template <typename... Ts>
|
||||
class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant {
|
||||
friend struct IPC::ParamTraits<mozilla::Variant<Ts...>>;
|
||||
friend struct mozilla::ipc::IPDLParamTraits<mozilla::Variant<Ts...>>;
|
||||
|
||||
using Tag = typename detail::VariantTag<Ts...>::Type;
|
||||
using Impl = detail::VariantImplementation<Tag, 0, Ts...>;
|
||||
@ -622,6 +628,23 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant {
|
||||
|
||||
~Variant() { Impl::destroy(*this); }
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T& emplace(Args&&... aTs) {
|
||||
Impl::destroy(*this);
|
||||
tag = Impl::template tag<T>();
|
||||
::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...);
|
||||
return as<T>();
|
||||
}
|
||||
|
||||
template <size_t N, typename... Args>
|
||||
typename detail::Nth<N, Ts...>::Type& emplace(Args&&... aTs) {
|
||||
using T = typename detail::Nth<N, Ts...>::Type;
|
||||
Impl::destroy(*this);
|
||||
tag = N;
|
||||
::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...);
|
||||
return as<N>();
|
||||
}
|
||||
|
||||
/** Check which variant type is currently contained. */
|
||||
template <typename T>
|
||||
bool is() const {
|
||||
|
@ -281,6 +281,52 @@ static void testConstructionWithVariantIndex() {
|
||||
MOZ_RELEASE_ASSERT(v.extract<2>() == 2);
|
||||
}
|
||||
|
||||
static void testEmplaceWithType() {
|
||||
printf("testEmplaceWithType\n");
|
||||
Variant<uint32_t, uint64_t, uint32_t> v1(mozilla::VariantIndex<0>{}, 0);
|
||||
v1.emplace<uint64_t>(3);
|
||||
MOZ_RELEASE_ASSERT(v1.is<uint64_t>());
|
||||
MOZ_RELEASE_ASSERT(v1.as<uint64_t>() == 3);
|
||||
|
||||
Variant<UniquePtr<int>, char> v2('a');
|
||||
v2.emplace<UniquePtr<int>>();
|
||||
MOZ_RELEASE_ASSERT(v2.is<UniquePtr<int>>());
|
||||
MOZ_RELEASE_ASSERT(!v2.as<UniquePtr<int>>().get());
|
||||
|
||||
Variant<UniquePtr<int>, char> v3('a');
|
||||
v3.emplace<UniquePtr<int>>(MakeUnique<int>(4));
|
||||
MOZ_RELEASE_ASSERT(v3.is<UniquePtr<int>>());
|
||||
MOZ_RELEASE_ASSERT(*v3.as<UniquePtr<int>>().get() == 4);
|
||||
}
|
||||
|
||||
static void testEmplaceWithIndex() {
|
||||
printf("testEmplaceWithIndex\n");
|
||||
Variant<uint32_t, uint64_t, uint32_t> v1(mozilla::VariantIndex<1>{}, 0);
|
||||
v1.emplace<2>(2);
|
||||
MOZ_RELEASE_ASSERT(!v1.is<uint64_t>());
|
||||
MOZ_RELEASE_ASSERT(!v1.is<1>());
|
||||
MOZ_RELEASE_ASSERT(!v1.is<0>());
|
||||
MOZ_RELEASE_ASSERT(v1.is<2>());
|
||||
MOZ_RELEASE_ASSERT(v1.as<2>() == 2);
|
||||
MOZ_RELEASE_ASSERT(v1.extract<2>() == 2);
|
||||
|
||||
Variant<UniquePtr<int>, char> v2('a');
|
||||
v2.emplace<0>();
|
||||
MOZ_RELEASE_ASSERT(v2.is<UniquePtr<int>>());
|
||||
MOZ_RELEASE_ASSERT(!v2.is<1>());
|
||||
MOZ_RELEASE_ASSERT(v2.is<0>());
|
||||
MOZ_RELEASE_ASSERT(!v2.as<0>().get());
|
||||
MOZ_RELEASE_ASSERT(!v2.extract<0>().get());
|
||||
|
||||
Variant<UniquePtr<int>, char> v3('a');
|
||||
v3.emplace<0>(MakeUnique<int>(4));
|
||||
MOZ_RELEASE_ASSERT(v3.is<UniquePtr<int>>());
|
||||
MOZ_RELEASE_ASSERT(!v3.is<1>());
|
||||
MOZ_RELEASE_ASSERT(v3.is<0>());
|
||||
MOZ_RELEASE_ASSERT(*v3.as<0>().get() == 4);
|
||||
MOZ_RELEASE_ASSERT(*v3.extract<0>().get() == 4);
|
||||
}
|
||||
|
||||
static void testCopy() {
|
||||
printf("testCopy\n");
|
||||
Variant<uint32_t, uint64_t> v1(uint64_t(1));
|
||||
@ -328,15 +374,26 @@ static void testDestructor() {
|
||||
Destroyer d;
|
||||
|
||||
{
|
||||
Variant<char, UniquePtr<char[]>, Destroyer> v(d);
|
||||
Variant<char, UniquePtr<char[]>, Destroyer> v1(d);
|
||||
MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 0); // None detroyed yet.
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(Destroyer::destroyedCount ==
|
||||
1); // v's copy of d is destroyed.
|
||||
1); // v1's copy of d is destroyed.
|
||||
|
||||
{
|
||||
Variant<char, UniquePtr<char[]>, Destroyer> v2(
|
||||
mozilla::VariantIndex<2>{});
|
||||
v2.emplace<Destroyer>(d);
|
||||
MOZ_RELEASE_ASSERT(Destroyer::destroyedCount ==
|
||||
2); // v2's initial value is destroyed.
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(Destroyer::destroyedCount ==
|
||||
3); // v2's second value is destroyed.
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 2); // d is destroyed.
|
||||
MOZ_RELEASE_ASSERT(Destroyer::destroyedCount == 4); // d is destroyed.
|
||||
}
|
||||
|
||||
static void testEquality() {
|
||||
@ -510,6 +567,8 @@ int main() {
|
||||
testDuplicate();
|
||||
testConstructionWithVariantType();
|
||||
testConstructionWithVariantIndex();
|
||||
testEmplaceWithType();
|
||||
testEmplaceWithIndex();
|
||||
testCopy();
|
||||
testMove();
|
||||
testDestructor();
|
||||
|
Loading…
Reference in New Issue
Block a user