ipc: Allow all trivially copyable objects to be passed directly into WriteBuffer (#4465)
* ipc: Allow all trivially copyable objects to be passed directly into WriteBuffer With the support of C++20, we can use concepts to deduce if a type is an STL container or not. * More agressive concept for stl containers * Add -fconcepts * Move to common namespace * Add Common::IsBaseOf
This commit is contained in:
parent
6c7292de33
commit
9b75481755
12 changed files with 64 additions and 30 deletions
|
@ -60,6 +60,7 @@ else()
|
||||||
-Wmissing-declarations
|
-Wmissing-declarations
|
||||||
-Wno-attributes
|
-Wno-attributes
|
||||||
-Wno-unused-parameter
|
-Wno-unused-parameter
|
||||||
|
-fconcepts
|
||||||
)
|
)
|
||||||
|
|
||||||
if (ARCHITECTURE_x86_64)
|
if (ARCHITECTURE_x86_64)
|
||||||
|
|
|
@ -110,6 +110,7 @@ add_library(common STATIC
|
||||||
common_funcs.h
|
common_funcs.h
|
||||||
common_paths.h
|
common_paths.h
|
||||||
common_types.h
|
common_types.h
|
||||||
|
concepts.h
|
||||||
dynamic_library.cpp
|
dynamic_library.cpp
|
||||||
dynamic_library.h
|
dynamic_library.h
|
||||||
fiber.cpp
|
fiber.cpp
|
||||||
|
|
32
src/common/concepts.h
Normal file
32
src/common/concepts.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2020 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
// Check if type is like an STL container
|
||||||
|
template <typename T>
|
||||||
|
concept IsSTLContainer = requires(T t) {
|
||||||
|
typename T::value_type;
|
||||||
|
typename T::iterator;
|
||||||
|
typename T::const_iterator;
|
||||||
|
// TODO(ogniK): Replace below is std::same_as<void> when MSVC supports it.
|
||||||
|
t.begin();
|
||||||
|
t.end();
|
||||||
|
t.cbegin();
|
||||||
|
t.cend();
|
||||||
|
t.data();
|
||||||
|
t.size();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if type T is derived from T2
|
||||||
|
template <typename T, typename T2>
|
||||||
|
concept IsBaseOf = requires {
|
||||||
|
std::is_base_of_v<T, T2>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Common
|
|
@ -13,6 +13,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/container/small_vector.hpp>
|
#include <boost/container/small_vector.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/concepts.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/hle/ipc.h"
|
#include "core/hle/ipc.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
|
@ -193,23 +194,24 @@ public:
|
||||||
|
|
||||||
/* Helper function to write a buffer using the appropriate buffer descriptor
|
/* Helper function to write a buffer using the appropriate buffer descriptor
|
||||||
*
|
*
|
||||||
* @tparam ContiguousContainer an arbitrary container that satisfies the
|
* @tparam T an arbitrary container that satisfies the
|
||||||
* ContiguousContainer concept in the C++ standard library.
|
* ContiguousContainer concept in the C++ standard library or a trivially copyable type.
|
||||||
*
|
*
|
||||||
* @param container The container to write the data of into a buffer.
|
* @param data The container/data to write into a buffer.
|
||||||
* @param buffer_index The buffer in particular to write to.
|
* @param buffer_index The buffer in particular to write to.
|
||||||
*/
|
*/
|
||||||
template <typename ContiguousContainer,
|
template <typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>>
|
||||||
typename = std::enable_if_t<!std::is_pointer_v<ContiguousContainer>>>
|
std::size_t WriteBuffer(const T& data, std::size_t buffer_index = 0) const {
|
||||||
std::size_t WriteBuffer(const ContiguousContainer& container,
|
if constexpr (Common::IsSTLContainer<T>) {
|
||||||
std::size_t buffer_index = 0) const {
|
using ContiguousType = typename T::value_type;
|
||||||
using ContiguousType = typename ContiguousContainer::value_type;
|
static_assert(std::is_trivially_copyable_v<ContiguousType>,
|
||||||
|
"Container to WriteBuffer must contain trivially copyable objects");
|
||||||
static_assert(std::is_trivially_copyable_v<ContiguousType>,
|
return WriteBuffer(std::data(data), std::size(data) * sizeof(ContiguousType),
|
||||||
"Container to WriteBuffer must contain trivially copyable objects");
|
buffer_index);
|
||||||
|
} else {
|
||||||
return WriteBuffer(std::data(container), std::size(container) * sizeof(ContiguousType),
|
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
|
||||||
buffer_index);
|
return WriteBuffer(&data, sizeof(T), buffer_index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to get the size of the input buffer
|
/// Helper function to get the size of the input buffer
|
||||||
|
|
|
@ -286,9 +286,7 @@ protected:
|
||||||
ProfileBase profile_base{};
|
ProfileBase profile_base{};
|
||||||
ProfileData data{};
|
ProfileData data{};
|
||||||
if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
|
if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
|
||||||
std::array<u8, sizeof(ProfileData)> raw_data;
|
ctx.WriteBuffer(data);
|
||||||
std::memcpy(raw_data.data(), &data, sizeof(ProfileData));
|
|
||||||
ctx.WriteBuffer(raw_data);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 16};
|
IPC::ResponseBuilder rb{ctx, 16};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushRaw(profile_base);
|
rb.PushRaw(profile_base);
|
||||||
|
@ -333,7 +331,7 @@ protected:
|
||||||
std::vector<u8> buffer(size);
|
std::vector<u8> buffer(size);
|
||||||
image.ReadBytes(buffer.data(), buffer.size());
|
image.ReadBytes(buffer.data(), buffer.size());
|
||||||
|
|
||||||
ctx.WriteBuffer(buffer.data(), buffer.size());
|
ctx.WriteBuffer(buffer);
|
||||||
rb.Push<u32>(size);
|
rb.Push<u32>(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ private:
|
||||||
if (performance) {
|
if (performance) {
|
||||||
rb.Push<u64>(*performance);
|
rb.Push<u64>(*performance);
|
||||||
}
|
}
|
||||||
ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16));
|
ctx.WriteBuffer(samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector<u8>& input,
|
bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector<u8>& input,
|
||||||
|
|
|
@ -112,7 +112,7 @@ private:
|
||||||
void GetImpl(Kernel::HLERequestContext& ctx) {
|
void GetImpl(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_BCAT, "called");
|
LOG_DEBUG(Service_BCAT, "called");
|
||||||
|
|
||||||
ctx.WriteBuffer(&impl, sizeof(DeliveryCacheProgressImpl));
|
ctx.WriteBuffer(impl);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
|
@ -160,7 +160,7 @@ private:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.WriteBuffer(key.data(), key.size());
|
ctx.WriteBuffer(key);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
|
@ -127,7 +127,7 @@ private:
|
||||||
const u32 array_size = rp.Pop<u32>();
|
const u32 array_size = rp.Pop<u32>();
|
||||||
LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
|
LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
|
||||||
|
|
||||||
ctx.WriteBuffer(&device_handle, sizeof(device_handle));
|
ctx.WriteBuffer(device_handle);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
@ -220,7 +220,7 @@ private:
|
||||||
|
|
||||||
tag_info.protocol = 1; // TODO(ogniK): Figure out actual values
|
tag_info.protocol = 1; // TODO(ogniK): Figure out actual values
|
||||||
tag_info.tag_type = 2;
|
tag_info.tag_type = 2;
|
||||||
ctx.WriteBuffer(&tag_info, sizeof(TagInfo));
|
ctx.WriteBuffer(tag_info);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ private:
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
auto amiibo = nfp_interface.GetAmiiboBuffer();
|
auto amiibo = nfp_interface.GetAmiiboBuffer();
|
||||||
ctx.WriteBuffer(&amiibo.model_info, sizeof(amiibo.model_info));
|
ctx.WriteBuffer(amiibo.model_info);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +283,7 @@ private:
|
||||||
|
|
||||||
CommonInfo common_info{};
|
CommonInfo common_info{};
|
||||||
common_info.application_area_size = 0;
|
common_info.application_area_size = 0;
|
||||||
ctx.WriteBuffer(&common_info, sizeof(CommonInfo));
|
ctx.WriteBuffer(common_info);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
|
@ -106,7 +106,7 @@ void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
ctx.WriteBuffer(&layout, sizeof(KeyboardLayout));
|
ctx.WriteBuffer(layout);
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
|
|
@ -290,7 +290,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot));
|
ctx.WriteBuffer(clock_snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -313,7 +313,7 @@ void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLEReques
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot));
|
ctx.WriteBuffer(clock_snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
|
void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
|
||||||
|
|
|
@ -142,7 +142,7 @@ void ITimeZoneService::ToPosixTime(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushRaw<u32>(1); // Number of times we're returning
|
rb.PushRaw<u32>(1); // Number of times we're returning
|
||||||
ctx.WriteBuffer(&posix_time, sizeof(s64));
|
ctx.WriteBuffer(posix_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ITimeZoneService::ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
|
void ITimeZoneService::ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -164,7 +164,7 @@ void ITimeZoneService::ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushRaw<u32>(1); // Number of times we're returning
|
rb.PushRaw<u32>(1); // Number of times we're returning
|
||||||
ctx.WriteBuffer(&posix_time, sizeof(s64));
|
ctx.WriteBuffer(posix_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Time
|
} // namespace Service::Time
|
||||||
|
|
Loading…
Reference in a new issue