[XAM] Enumerator improvements.
- [Kernel] XEnumerator::WriteItems no longer cares about provided buffer size, since we know the size when the XEnumerator was created. - [Kernel] Added XStaticEnumerator template. Previous XStaticEnumerator renamed to XStaticUntypedEnumerator. - [XAM] Deferred xeXamEnumerate.
This commit is contained in:
parent
b18f73b949
commit
e8fda5878c
|
@ -57,8 +57,7 @@ X_HRESULT XamApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
|
||||||
std::memset(buffer, 0, data->buffer_size);
|
std::memset(buffer, 0, data->buffer_size);
|
||||||
}
|
}
|
||||||
uint32_t item_count = 0;
|
uint32_t item_count = 0;
|
||||||
auto result = e->WriteItems(data->buffer_ptr, buffer, data->buffer_size,
|
auto result = e->WriteItems(data->buffer_ptr, buffer, &item_count);
|
||||||
&item_count);
|
|
||||||
|
|
||||||
if (result == X_ERROR_SUCCESS && item_count >= 1) {
|
if (result == X_ERROR_SUCCESS && item_count >= 1) {
|
||||||
if (data->length_ptr) {
|
if (data->length_ptr) {
|
||||||
|
|
|
@ -86,8 +86,8 @@ dword_result_t XamContentCreateEnumerator(dword_t user_index, dword_t device_id,
|
||||||
*buffer_size_ptr = sizeof(XCONTENT_DATA) * items_per_enumerate;
|
*buffer_size_ptr = sizeof(XCONTENT_DATA) * items_per_enumerate;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto e = object_ref<XStaticEnumerator>(new XStaticEnumerator(
|
auto e = make_object<XStaticEnumerator<XCONTENT_DATA>>(kernel_state(),
|
||||||
kernel_state(), items_per_enumerate, sizeof(XCONTENT_DATA)));
|
items_per_enumerate);
|
||||||
auto result = e->Initialize(0xFF, 0xFE, 0x20005, 0x20007, 0);
|
auto result = e->Initialize(0xFF, 0xFE, 0x20005, 0x20007, 0);
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -99,8 +99,7 @@ dword_result_t XamContentCreateEnumerator(dword_t user_index, dword_t device_id,
|
||||||
static_cast<uint32_t>(DummyDeviceId::HDD),
|
static_cast<uint32_t>(DummyDeviceId::HDD),
|
||||||
XContentType(uint32_t(content_type)));
|
XContentType(uint32_t(content_type)));
|
||||||
for (const auto& content_data : content_datas) {
|
for (const auto& content_data : content_datas) {
|
||||||
auto item = reinterpret_cast<XCONTENT_DATA*>(e->AppendItem());
|
auto item = e->AppendItem();
|
||||||
assert_not_null(item);
|
|
||||||
*item = content_data;
|
*item = content_data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace xam {
|
namespace xam {
|
||||||
|
|
||||||
void AddODDContentTest(object_ref<XStaticEnumerator> e,
|
void AddODDContentTest(object_ref<XStaticEnumerator<XCONTENT_AGGREGATE_DATA>> e,
|
||||||
XContentType content_type) {
|
XContentType content_type) {
|
||||||
auto root_entry = kernel_state()->file_system()->ResolvePath(
|
auto root_entry = kernel_state()->file_system()->ResolvePath(
|
||||||
"game:\\Content\\0000000000000000");
|
"game:\\Content\\0000000000000000");
|
||||||
|
@ -62,8 +62,9 @@ void AddODDContentTest(object_ref<XStaticEnumerator> e,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto item = reinterpret_cast<XCONTENT_AGGREGATE_DATA*>(e->AppendItem());
|
auto item = e->AppendItem();
|
||||||
assert_not_null(item);
|
assert_not_null(item);
|
||||||
|
if (item) {
|
||||||
item->device_id = static_cast<uint32_t>(DummyDeviceId::ODD);
|
item->device_id = static_cast<uint32_t>(DummyDeviceId::ODD);
|
||||||
item->content_type = content_type;
|
item->content_type = content_type;
|
||||||
item->set_display_name(to_utf16(content_entry->name()));
|
item->set_display_name(to_utf16(content_entry->name()));
|
||||||
|
@ -73,6 +74,7 @@ void AddODDContentTest(object_ref<XStaticEnumerator> e,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dword_result_t XamContentAggregateCreateEnumerator(qword_t xuid,
|
dword_result_t XamContentAggregateCreateEnumerator(qword_t xuid,
|
||||||
dword_t device_id,
|
dword_t device_id,
|
||||||
|
@ -86,8 +88,8 @@ dword_result_t XamContentAggregateCreateEnumerator(qword_t xuid,
|
||||||
return X_E_INVALIDARG;
|
return X_E_INVALIDARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto e = object_ref<XStaticEnumerator>(new XStaticEnumerator(
|
auto e = make_object<XStaticEnumerator<XCONTENT_AGGREGATE_DATA>>(
|
||||||
kernel_state(), 1, sizeof(XCONTENT_AGGREGATE_DATA)));
|
kernel_state(), 1);
|
||||||
X_KENUMERATOR_CONTENT_AGGREGATE* extra;
|
X_KENUMERATOR_CONTENT_AGGREGATE* extra;
|
||||||
auto result = e->Initialize(0xFF, 0xFE, 0x2000E, 0x20010, 0, &extra);
|
auto result = e->Initialize(0xFF, 0xFE, 0x2000E, 0x20010, 0, &extra);
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
|
@ -116,12 +118,14 @@ dword_result_t XamContentAggregateCreateEnumerator(qword_t xuid,
|
||||||
static_cast<uint32_t>(DummyDeviceId::HDD), content_type_enum,
|
static_cast<uint32_t>(DummyDeviceId::HDD), content_type_enum,
|
||||||
title_id);
|
title_id);
|
||||||
for (const auto& content_data : content_datas) {
|
for (const auto& content_data : content_datas) {
|
||||||
auto item = reinterpret_cast<XCONTENT_AGGREGATE_DATA*>(e->AppendItem());
|
auto item = e->AppendItem();
|
||||||
assert_not_null(item);
|
assert_not_null(item);
|
||||||
|
if (item) {
|
||||||
*item = content_data;
|
*item = content_data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!device_info || device_info->device_type == DeviceType::ODD) {
|
if (!device_info || device_info->device_type == DeviceType::ODD) {
|
||||||
AddODDContentTest(e, content_type_enum);
|
AddODDContentTest(e, content_type_enum);
|
||||||
|
|
|
@ -139,8 +139,8 @@ dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type,
|
||||||
*buffer_size_ptr = sizeof(X_CONTENT_DEVICE_DATA) * max_count;
|
*buffer_size_ptr = sizeof(X_CONTENT_DEVICE_DATA) * max_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto e = object_ref<XStaticEnumerator>(new XStaticEnumerator(
|
auto e = make_object<XStaticEnumerator<X_CONTENT_DEVICE_DATA>>(kernel_state(),
|
||||||
kernel_state(), max_count, sizeof(X_CONTENT_DEVICE_DATA)));
|
max_count);
|
||||||
auto result = e->Initialize(0xFE, 0xFE, 0x2000A, 0x20009, 0);
|
auto result = e->Initialize(0xFE, 0xFE, 0x2000A, 0x20009, 0);
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -148,7 +148,8 @@ dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type,
|
||||||
|
|
||||||
for (const auto& device_info : dummy_device_infos_) {
|
for (const auto& device_info : dummy_device_infos_) {
|
||||||
// Copy our dummy device into the enumerator
|
// Copy our dummy device into the enumerator
|
||||||
auto device_data = (X_CONTENT_DEVICE_DATA*)e->AppendItem();
|
auto device_data = e->AppendItem();
|
||||||
|
assert_not_null(device_data);
|
||||||
if (device_data) {
|
if (device_data) {
|
||||||
device_data->device_id = static_cast<uint32_t>(device_info->device_id);
|
device_data->device_id = static_cast<uint32_t>(device_info->device_id);
|
||||||
device_data->device_type =
|
device_data->device_type =
|
||||||
|
|
|
@ -32,49 +32,37 @@ uint32_t xeXamEnumerate(uint32_t handle, uint32_t flags, lpvoid_t buffer_ptr,
|
||||||
uint32_t overlapped_ptr) {
|
uint32_t overlapped_ptr) {
|
||||||
assert_true(flags == 0);
|
assert_true(flags == 0);
|
||||||
|
|
||||||
X_RESULT result;
|
|
||||||
uint32_t item_count = 0;
|
|
||||||
|
|
||||||
auto e = kernel_state()->object_table()->LookupObject<XEnumerator>(handle);
|
auto e = kernel_state()->object_table()->LookupObject<XEnumerator>(handle);
|
||||||
if (!e) {
|
if (!e) {
|
||||||
result = X_ERROR_INVALID_HANDLE;
|
return X_ERROR_INVALID_HANDLE;
|
||||||
} else if (!buffer_ptr) {
|
}
|
||||||
|
|
||||||
|
auto run = [e, buffer_ptr](uint32_t& extended_error,
|
||||||
|
uint32_t& length) -> X_RESULT {
|
||||||
|
X_RESULT result;
|
||||||
|
uint32_t item_count;
|
||||||
|
if (!buffer_ptr) {
|
||||||
result = X_ERROR_INVALID_PARAMETER;
|
result = X_ERROR_INVALID_PARAMETER;
|
||||||
|
item_count = 0;
|
||||||
} else {
|
} else {
|
||||||
size_t needed_buffer_size = e->item_size() * e->items_per_enumerate();
|
result = e->WriteItems(buffer_ptr.guest_address(),
|
||||||
|
buffer_ptr.as<uint8_t*>(), &item_count);
|
||||||
uint32_t actual_buffer_size = buffer_size;
|
|
||||||
if (buffer_size == e->items_per_enumerate()) {
|
|
||||||
actual_buffer_size = static_cast<uint32_t>(needed_buffer_size);
|
|
||||||
// Known culprits:
|
|
||||||
// Final Fight: Double Impact (saves)
|
|
||||||
XELOGW(
|
|
||||||
"Broken usage of XamEnumerate! buffer size={:X} vs actual "
|
|
||||||
"size={:X} (item size={:X}, items per enumerate={})",
|
|
||||||
buffer_size, actual_buffer_size, e->item_size(),
|
|
||||||
e->items_per_enumerate());
|
|
||||||
}
|
|
||||||
|
|
||||||
result = X_ERROR_INSUFFICIENT_BUFFER;
|
|
||||||
if (actual_buffer_size >= needed_buffer_size) {
|
|
||||||
buffer_ptr.Zero(actual_buffer_size);
|
|
||||||
result =
|
|
||||||
e->WriteItems(buffer_ptr.guest_address(), buffer_ptr.as<uint8_t*>(),
|
|
||||||
actual_buffer_size, &item_count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
extended_error = X_HRESULT_FROM_WIN32(result);
|
||||||
|
length = item_count;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
if (items_returned) {
|
if (items_returned) {
|
||||||
assert_true(!overlapped_ptr);
|
assert_true(!overlapped_ptr);
|
||||||
|
uint32_t extended_error;
|
||||||
|
uint32_t item_count;
|
||||||
|
X_RESULT result = run(extended_error, item_count);
|
||||||
*items_returned = result == X_ERROR_SUCCESS ? item_count : 0;
|
*items_returned = result == X_ERROR_SUCCESS ? item_count : 0;
|
||||||
return result;
|
return result;
|
||||||
} else if (overlapped_ptr) {
|
} else if (overlapped_ptr) {
|
||||||
assert_true(!items_returned);
|
assert_true(!items_returned);
|
||||||
kernel_state()->CompleteOverlappedImmediateEx(
|
kernel_state()->CompleteOverlappedDeferredEx(run, overlapped_ptr);
|
||||||
overlapped_ptr,
|
|
||||||
result == X_ERROR_SUCCESS ? X_ERROR_SUCCESS : X_ERROR_FUNCTION_FAILED,
|
|
||||||
X_HRESULT_FROM_WIN32(result),
|
|
||||||
result == X_ERROR_SUCCESS ? item_count : 0);
|
|
||||||
return X_ERROR_IO_PENDING;
|
return X_ERROR_IO_PENDING;
|
||||||
} else {
|
} else {
|
||||||
assert_always();
|
assert_always();
|
||||||
|
|
|
@ -608,7 +608,7 @@ class XStaticAchievementEnumerator : public XEnumerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
|
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
|
||||||
uint32_t buffer_size, uint32_t* written_count) override {
|
uint32_t* written_count) override {
|
||||||
size_t count =
|
size_t count =
|
||||||
std::min(items_.size() - current_item_, items_per_enumerate());
|
std::min(items_.size() - current_item_, items_per_enumerate());
|
||||||
if (!count) {
|
if (!count) {
|
||||||
|
@ -616,9 +616,6 @@ class XStaticAchievementEnumerator : public XEnumerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size = count * item_size();
|
size_t size = count * item_size();
|
||||||
if (size > buffer_size) {
|
|
||||||
return X_ERROR_INSUFFICIENT_BUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto details = reinterpret_cast<X_ACHIEVEMENT_DETAILS*>(buffer_data);
|
auto details = reinterpret_cast<X_ACHIEVEMENT_DETAILS*>(buffer_data);
|
||||||
size_t string_offset =
|
size_t string_offset =
|
||||||
|
|
|
@ -21,7 +21,7 @@ XEnumerator::XEnumerator(KernelState* kernel_state, size_t items_per_enumerate,
|
||||||
XEnumerator::~XEnumerator() = default;
|
XEnumerator::~XEnumerator() = default;
|
||||||
|
|
||||||
X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id,
|
X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id,
|
||||||
uint32_t message, uint32_t message2,
|
uint32_t open_message, uint32_t close_message,
|
||||||
uint32_t flags, uint32_t extra_size,
|
uint32_t flags, uint32_t extra_size,
|
||||||
void** extra_buffer) {
|
void** extra_buffer) {
|
||||||
auto native_object = CreateNative(sizeof(X_KENUMERATOR) + extra_size);
|
auto native_object = CreateNative(sizeof(X_KENUMERATOR) + extra_size);
|
||||||
|
@ -30,8 +30,8 @@ X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id,
|
||||||
}
|
}
|
||||||
auto guest_object = reinterpret_cast<X_KENUMERATOR*>(native_object);
|
auto guest_object = reinterpret_cast<X_KENUMERATOR*>(native_object);
|
||||||
guest_object->app_id = app_id;
|
guest_object->app_id = app_id;
|
||||||
guest_object->message = message;
|
guest_object->open_message = open_message;
|
||||||
guest_object->message2 = message2;
|
guest_object->close_message = close_message;
|
||||||
guest_object->user_index = user_index;
|
guest_object->user_index = user_index;
|
||||||
guest_object->items_per_enumerate =
|
guest_object->items_per_enumerate =
|
||||||
static_cast<uint32_t>(items_per_enumerate_);
|
static_cast<uint32_t>(items_per_enumerate_);
|
||||||
|
@ -44,21 +44,20 @@ X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id,
|
X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id,
|
||||||
uint32_t message, uint32_t message2,
|
uint32_t open_message, uint32_t close_message,
|
||||||
uint32_t flags) {
|
uint32_t flags) {
|
||||||
return Initialize(user_index, app_id, message, message2, flags, 0, nullptr);
|
return Initialize(user_index, app_id, open_message, close_message, flags, 0,
|
||||||
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* XStaticEnumerator::AppendItem() {
|
uint8_t* XStaticUntypedEnumerator::AppendItem() {
|
||||||
buffer_.resize(++item_count_ * item_size());
|
size_t offset = buffer_.size();
|
||||||
auto ptr =
|
buffer_.resize(offset + item_size());
|
||||||
const_cast<uint8_t*>(buffer_.data() + (item_count_ - 1) * item_size());
|
return const_cast<uint8_t*>(&buffer_.data()[offset]);
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t XStaticEnumerator::WriteItems(uint32_t buffer_ptr,
|
uint32_t XStaticUntypedEnumerator::WriteItems(uint32_t buffer_ptr,
|
||||||
uint8_t* buffer_data,
|
uint8_t* buffer_data,
|
||||||
uint32_t buffer_size,
|
|
||||||
uint32_t* written_count) {
|
uint32_t* written_count) {
|
||||||
size_t count = std::min(item_count_ - current_item_, items_per_enumerate());
|
size_t count = std::min(item_count_ - current_item_, items_per_enumerate());
|
||||||
if (!count) {
|
if (!count) {
|
||||||
|
@ -66,10 +65,6 @@ uint32_t XStaticEnumerator::WriteItems(uint32_t buffer_ptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size = count * item_size();
|
size_t size = count * item_size();
|
||||||
if (size > buffer_size) {
|
|
||||||
return X_ERROR_INSUFFICIENT_BUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t offset = current_item_ * item_size();
|
size_t offset = current_item_ * item_size();
|
||||||
std::memcpy(buffer_data, buffer_.data() + offset, size);
|
std::memcpy(buffer_data, buffer_.data() + offset, size);
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@ namespace kernel {
|
||||||
|
|
||||||
struct X_KENUMERATOR {
|
struct X_KENUMERATOR {
|
||||||
be<uint32_t> app_id;
|
be<uint32_t> app_id;
|
||||||
be<uint32_t> message;
|
be<uint32_t> open_message;
|
||||||
be<uint32_t> message2;
|
be<uint32_t> close_message;
|
||||||
be<uint32_t> user_index;
|
be<uint32_t> user_index;
|
||||||
be<uint32_t> items_per_enumerate;
|
be<uint32_t> items_per_enumerate;
|
||||||
be<uint32_t> flags;
|
be<uint32_t> flags;
|
||||||
|
@ -43,19 +43,21 @@ class XEnumerator : public XObject {
|
||||||
size_t item_size);
|
size_t item_size);
|
||||||
virtual ~XEnumerator();
|
virtual ~XEnumerator();
|
||||||
|
|
||||||
X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message,
|
X_STATUS Initialize(uint32_t user_index, uint32_t app_id,
|
||||||
uint32_t message2, uint32_t flags, uint32_t extra_size,
|
uint32_t open_message, uint32_t close_message,
|
||||||
void** extra_buffer);
|
uint32_t flags, uint32_t extra_size, void** extra_buffer);
|
||||||
|
|
||||||
X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message,
|
X_STATUS Initialize(uint32_t user_index, uint32_t app_id,
|
||||||
uint32_t message2, uint32_t flags);
|
uint32_t open_message, uint32_t close_message,
|
||||||
|
uint32_t flags);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message,
|
X_STATUS Initialize(uint32_t user_index, uint32_t app_id,
|
||||||
uint32_t message2, uint32_t flags, T** extra) {
|
uint32_t open_message, uint32_t close_message,
|
||||||
|
uint32_t flags, T** extra) {
|
||||||
void* dummy;
|
void* dummy;
|
||||||
auto result = Initialize(user_index, app_id, message, message2, flags,
|
auto result = Initialize(user_index, app_id, open_message, close_message,
|
||||||
static_cast<uint32_t>(sizeof(T)), &dummy);
|
flags, static_cast<uint32_t>(sizeof(T)), &dummy);
|
||||||
if (extra) {
|
if (extra) {
|
||||||
*extra = XFAILED(result) ? nullptr : static_cast<T*>(dummy);
|
*extra = XFAILED(result) ? nullptr : static_cast<T*>(dummy);
|
||||||
}
|
}
|
||||||
|
@ -63,7 +65,6 @@ class XEnumerator : public XObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
|
virtual uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
|
||||||
uint32_t buffer_size,
|
|
||||||
uint32_t* written_count) = 0;
|
uint32_t* written_count) = 0;
|
||||||
|
|
||||||
size_t item_size() const { return item_size_; }
|
size_t item_size() const { return item_size_; }
|
||||||
|
@ -74,10 +75,10 @@ class XEnumerator : public XObject {
|
||||||
size_t item_size_;
|
size_t item_size_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class XStaticEnumerator : public XEnumerator {
|
class XStaticUntypedEnumerator : public XEnumerator {
|
||||||
public:
|
public:
|
||||||
XStaticEnumerator(KernelState* kernel_state, size_t items_per_enumerate,
|
XStaticUntypedEnumerator(KernelState* kernel_state,
|
||||||
size_t item_size)
|
size_t items_per_enumerate, size_t item_size)
|
||||||
: XEnumerator(kernel_state, items_per_enumerate, item_size),
|
: XEnumerator(kernel_state, items_per_enumerate, item_size),
|
||||||
item_count_(0),
|
item_count_(0),
|
||||||
current_item_(0) {}
|
current_item_(0) {}
|
||||||
|
@ -87,7 +88,7 @@ class XStaticEnumerator : public XEnumerator {
|
||||||
uint8_t* AppendItem();
|
uint8_t* AppendItem();
|
||||||
|
|
||||||
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
|
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
|
||||||
uint32_t buffer_size, uint32_t* written_count) override;
|
uint32_t* written_count) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t item_count_;
|
size_t item_count_;
|
||||||
|
@ -95,6 +96,23 @@ class XStaticEnumerator : public XEnumerator {
|
||||||
std::vector<uint8_t> buffer_;
|
std::vector<uint8_t> buffer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class XStaticEnumerator : public XStaticUntypedEnumerator {
|
||||||
|
public:
|
||||||
|
XStaticEnumerator(KernelState* kernel_state, size_t items_per_enumerate)
|
||||||
|
: XStaticUntypedEnumerator(kernel_state, items_per_enumerate, sizeof(T)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
T* AppendItem() {
|
||||||
|
return reinterpret_cast<T*>(XStaticUntypedEnumerator::AppendItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppendItem(const T& item) {
|
||||||
|
auto ptr = AppendItem();
|
||||||
|
item.Write(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue