blob: 08471a78e0513b3e21c959da0754a9ea52fb4775 [file] [log] [blame]
// Copyright 2023 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "iree/io/stream.h"
// This is arbitrary - we should allow dynamic block sizes and such but keeping
// this small only requires a reasonable fixed size stack alloc.
#define IREE_IO_STREAM_COPY_BLOCK_SIZE (32 * 1024)
//===----------------------------------------------------------------------===//
// Stream utilities
//===----------------------------------------------------------------------===//
static const char* iree_io_stream_seek_mode_string(
iree_io_stream_seek_mode_t seek_mode) {
switch (seek_mode) {
case IREE_IO_STREAM_SEEK_SET:
return "set";
case IREE_IO_STREAM_SEEK_FROM_CURRENT:
return "from-current";
case IREE_IO_STREAM_SEEK_FROM_END:
return "from-end";
default:
return "?";
}
}
static iree_string_view_t iree_io_stream_mode_format(
iree_io_stream_mode_t value, iree_bitfield_string_temp_t* out_temp) {
static const iree_bitfield_string_mapping_t mappings[] = {
{IREE_IO_STREAM_MODE_READABLE, IREE_SVL("READABLE")},
{IREE_IO_STREAM_MODE_WRITABLE, IREE_SVL("WRITABLE")},
{IREE_IO_STREAM_MODE_RESIZABLE, IREE_SVL("RESIZABLE")},
{IREE_IO_STREAM_MODE_SEEKABLE, IREE_SVL("SEEKABLE")},
{IREE_IO_STREAM_MODE_MAPPABLE, IREE_SVL("MAPPABLE")},
};
return iree_bitfield_format_inline(value, IREE_ARRAYSIZE(mappings), mappings,
out_temp);
}
// Validates that all bits in |required_mode| are available in |allowed_mode|.
static iree_status_t iree_io_stream_validate_mode(
iree_io_stream_mode_t allowed_mode, iree_io_stream_mode_t required_mode) {
if (!iree_all_bits_set(allowed_mode, required_mode)) {
#if IREE_STATUS_MODE
iree_bitfield_string_temp_t temp0, temp1;
iree_string_view_t required_mode_str =
iree_io_stream_mode_format(required_mode, &temp0);
iree_string_view_t allowed_mode_str =
iree_io_stream_mode_format(allowed_mode, &temp1);
return iree_make_status(
IREE_STATUS_PERMISSION_DENIED,
"operation requires mode '%.*s' but stream was opened with '%.*s'",
(int)required_mode_str.size, required_mode_str.data,
(int)allowed_mode_str.size, allowed_mode_str.data);
#else
return iree_status_from_code(IREE_STATUS_PERMISSION_DENIED);
#endif // IREE_STATUS_MODE
}
return iree_ok_status();
}
// Validates that at least |access_length| bytes are available at the current
// stream offset. If the optional |out_available_length| is provided the
// available length will be returned matching the requested |access_length| or
// the maximum remaining length to the caller with an OK status even if the full
// |access_length| is not available and otherwise an error is returned.
static iree_status_t iree_io_stream_validate_fixed_range(
iree_io_stream_pos_t stream_offset, iree_io_stream_pos_t stream_length,
iree_io_stream_pos_t access_length,
iree_io_stream_pos_t* out_available_length) {
if (out_available_length) *out_available_length = 0;
iree_io_stream_pos_t remaining_length = stream_length - stream_offset;
if (access_length > remaining_length) {
// Access exceeds remaining length.
if (out_available_length) {
// Let caller know how much is available and return OK so they can use it.
*out_available_length = remaining_length;
return iree_ok_status();
}
return iree_make_status(IREE_STATUS_OUT_OF_RANGE,
"access to range [%" PRIu64 ", %" PRIu64
") (%" PRIu64
" bytes) out of range; stream offset %" PRIu64
" and length %" PRIu64 " insufficient",
stream_offset, stream_offset + access_length,
access_length, stream_offset, stream_length);
}
if (out_available_length) *out_available_length = access_length;
return iree_ok_status();
}
// Applies a seek operation with |seek_mode| and |seek_offset| against a stream.
// |out_stream_offset| will contain the position after the seek or an error will
// be returned if the seek could not be completed.
static iree_status_t iree_io_stream_apply_fixed_seek(
iree_io_stream_pos_t stream_offset, iree_io_stream_pos_t stream_length,
iree_io_stream_seek_mode_t seek_mode, iree_io_stream_pos_t seek_offset,
iree_io_stream_pos_t* out_stream_offset) {
*out_stream_offset = stream_offset;
iree_io_stream_pos_t new_offset = stream_offset;
switch (seek_mode) {
case IREE_IO_STREAM_SEEK_SET:
new_offset = seek_offset;
break;
case IREE_IO_STREAM_SEEK_FROM_CURRENT:
new_offset = stream_offset + seek_offset;
break;
case IREE_IO_STREAM_SEEK_FROM_END:
new_offset = stream_length + seek_offset;
break;
default:
return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
"unrecognized seek mode %u", (uint32_t)seek_mode);
}
if (new_offset < 0 || new_offset > stream_length) {
return iree_make_status(IREE_STATUS_OUT_OF_RANGE,
"seek %s offset %" PRIi64
" out of stream bounds; expected 0 <= %" PRIi64
" < %" PRIi64,
iree_io_stream_seek_mode_string(seek_mode),
seek_offset, new_offset, stream_length);
}
*out_stream_offset = new_offset;
return iree_ok_status();
}
//===----------------------------------------------------------------------===//
// iree_io_stream_t
//===----------------------------------------------------------------------===//
IREE_API_EXPORT void iree_io_stream_retain(iree_io_stream_t* stream) {
if (IREE_LIKELY(stream)) {
iree_atomic_ref_count_inc(&stream->ref_count);
}
}
IREE_API_EXPORT void iree_io_stream_release(iree_io_stream_t* stream) {
if (IREE_LIKELY(stream) &&
iree_atomic_ref_count_dec(&stream->ref_count) == 1) {
IREE_TRACE_ZONE_BEGIN_NAMED(z0, "iree_io_stream_destroy");
stream->vtable->destroy(stream);
IREE_TRACE_ZONE_END(z0);
}
}
IREE_API_EXPORT iree_io_stream_mode_t
iree_io_stream_mode(const iree_io_stream_t* stream) {
IREE_ASSERT_ARGUMENT(stream);
return stream->mode;
}
IREE_API_EXPORT iree_io_stream_pos_t
iree_io_stream_offset(iree_io_stream_t* stream) {
IREE_ASSERT_ARGUMENT(stream);
return stream->vtable->offset(stream);
}
IREE_API_EXPORT iree_io_stream_pos_t
iree_io_stream_length(iree_io_stream_t* stream) {
IREE_ASSERT_ARGUMENT(stream);
return stream->vtable->length(stream);
}
IREE_API_EXPORT bool iree_io_stream_is_eos(iree_io_stream_t* stream) {
IREE_ASSERT_ARGUMENT(stream);
return stream->vtable->offset(stream) == stream->vtable->length(stream);
}
IREE_API_EXPORT iree_status_t iree_io_stream_seek(
iree_io_stream_t* stream, iree_io_stream_seek_mode_t seek_mode,
iree_io_stream_pos_t offset) {
IREE_ASSERT_ARGUMENT(stream);
IREE_TRACE_ZONE_BEGIN(z0);
IREE_TRACE_ZONE_APPEND_TEXT(z0, iree_io_stream_seek_mode_string(seek_mode));
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, (int64_t)offset);
iree_status_t status = stream->vtable->seek(stream, seek_mode, offset);
IREE_TRACE_ZONE_END(z0);
return status;
}
IREE_API_EXPORT iree_status_t iree_io_stream_seek_to_alignment(
iree_io_stream_t* stream, iree_io_stream_pos_t alignment) {
IREE_ASSERT_ARGUMENT(stream);
if (alignment == 0) return iree_ok_status();
if (!iree_is_power_of_two_uint64(alignment)) {
return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
"alignment %" PRIu64 " not a power of two",
alignment);
}
IREE_TRACE_ZONE_BEGIN(z0);
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, (int64_t)alignment);
iree_io_stream_pos_t current_offset = iree_io_stream_offset(stream);
iree_io_stream_pos_t aligned_offset =
iree_align_uint64(current_offset, alignment);
iree_status_t status = iree_ok_status();
if (current_offset != aligned_offset) {
status =
iree_io_stream_seek(stream, IREE_IO_STREAM_SEEK_SET, aligned_offset);
}
IREE_TRACE_ZONE_END(z0);
return status;
}
IREE_API_EXPORT iree_status_t
iree_io_stream_read(iree_io_stream_t* stream, iree_host_size_t buffer_capacity,
void* buffer, iree_host_size_t* out_buffer_length) {
IREE_ASSERT_ARGUMENT(stream);
IREE_ASSERT_ARGUMENT(!buffer_capacity || buffer);
if (out_buffer_length) *out_buffer_length = 0;
IREE_RETURN_IF_ERROR(
iree_io_stream_validate_mode(iree_io_stream_mode(stream),
IREE_IO_STREAM_MODE_READABLE),
"reading from the stream");
if (buffer_capacity == 0) return iree_ok_status();
IREE_TRACE_ZONE_BEGIN(z0);
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, (int64_t)buffer_capacity);
iree_status_t status =
stream->vtable->read(stream, buffer_capacity, buffer, out_buffer_length);
if (out_buffer_length) {
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, (int64_t)*out_buffer_length);
}
IREE_TRACE_ZONE_END(z0);
return status;
}
IREE_API_EXPORT iree_status_t
iree_io_stream_write(iree_io_stream_t* stream, iree_host_size_t buffer_length,
const void* buffer) {
IREE_ASSERT_ARGUMENT(stream);
IREE_ASSERT_ARGUMENT(!buffer_length || buffer);
IREE_RETURN_IF_ERROR(
iree_io_stream_validate_mode(iree_io_stream_mode(stream),
IREE_IO_STREAM_MODE_WRITABLE),
"writing to the stream");
if (!buffer_length) return iree_ok_status();
IREE_TRACE_ZONE_BEGIN(z0);
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, (int64_t)buffer_length);
iree_status_t status = stream->vtable->write(stream, buffer_length, buffer);
IREE_TRACE_ZONE_END(z0);
return status;
}
IREE_API_EXPORT iree_status_t
iree_io_stream_fill(iree_io_stream_t* stream, iree_io_stream_pos_t count,
const void* pattern, iree_host_size_t pattern_length) {
IREE_ASSERT_ARGUMENT(stream);
IREE_ASSERT_ARGUMENT(!pattern_length || pattern);
IREE_RETURN_IF_ERROR(
iree_io_stream_validate_mode(iree_io_stream_mode(stream),
IREE_IO_STREAM_MODE_WRITABLE),
"writing to the stream");
switch (pattern_length) {
case 1:
case 2:
case 4:
case 8:
break;
default:
return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
"unsupported fill pattern length: %" PRIhsz,
pattern_length);
}
if (!count || !pattern_length) return iree_ok_status();
IREE_TRACE_ZONE_BEGIN(z0);
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, (int64_t)count);
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, (int64_t)pattern_length);
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, (int64_t)(count * pattern_length));
iree_status_t status =
stream->vtable->fill(stream, count, pattern, pattern_length);
IREE_TRACE_ZONE_END(z0);
return status;
}
IREE_API_EXPORT iree_status_t
iree_io_stream_map_read(iree_io_stream_t* stream, iree_host_size_t length,
iree_const_byte_span_t* out_span) {
IREE_ASSERT_ARGUMENT(stream);
IREE_ASSERT_ARGUMENT(out_span);
*out_span = iree_const_byte_span_empty();
IREE_RETURN_IF_ERROR(
iree_io_stream_validate_mode(
iree_io_stream_mode(stream),
IREE_IO_STREAM_MODE_READABLE | IREE_IO_STREAM_MODE_MAPPABLE),
"mapping the stream for reading");
IREE_TRACE_ZONE_BEGIN(z0);
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, (int64_t)length);
iree_status_t status = stream->vtable->map_read(stream, length, out_span);
IREE_TRACE_ZONE_END(z0);
return status;
}
IREE_API_EXPORT iree_status_t
iree_io_stream_map_write(iree_io_stream_t* stream, iree_host_size_t length,
iree_byte_span_t* out_span) {
IREE_ASSERT_ARGUMENT(stream);
IREE_ASSERT_ARGUMENT(out_span);
*out_span = iree_byte_span_empty();
IREE_RETURN_IF_ERROR(
iree_io_stream_validate_mode(
iree_io_stream_mode(stream),
IREE_IO_STREAM_MODE_WRITABLE | IREE_IO_STREAM_MODE_MAPPABLE),
"mapping the stream for writing");
IREE_TRACE_ZONE_BEGIN(z0);
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, (int64_t)length);
iree_status_t status = stream->vtable->map_write(stream, length, out_span);
IREE_TRACE_ZONE_END(z0);
return status;
}
IREE_API_EXPORT iree_status_t iree_io_stream_copy(
iree_io_stream_t* source_stream, iree_io_stream_t* target_stream,
iree_io_stream_pos_t length) {
IREE_ASSERT_ARGUMENT(source_stream);
IREE_ASSERT_ARGUMENT(target_stream);
if (!length) return iree_ok_status();
IREE_TRACE_ZONE_BEGIN(z0);
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, (int64_t)length);
iree_status_t status = iree_ok_status();
uint8_t buffer[IREE_IO_STREAM_COPY_BLOCK_SIZE];
iree_io_stream_pos_t remaining_length = length;
while (remaining_length) {
iree_host_size_t block_length = iree_min(sizeof(buffer), remaining_length);
iree_host_size_t read_length = 0;
status =
iree_io_stream_read(source_stream, block_length, buffer, &read_length);
if (!iree_status_is_ok(status)) break;
if (read_length != block_length) {
status = iree_make_status(
IREE_STATUS_OUT_OF_RANGE,
"source stream read underflow, expected to read a block of %" PRIhsz
" but stream only provided %" PRIhsz " bytes",
block_length, read_length);
break;
}
status = iree_io_stream_write(target_stream, read_length, buffer);
if (!iree_status_is_ok(status)) break;
remaining_length -= read_length;
}
IREE_TRACE_ZONE_END(z0);
return status;
}
//===----------------------------------------------------------------------===//
// iree_io_memory_stream_t
//===----------------------------------------------------------------------===//
typedef struct iree_io_memory_stream_t {
iree_io_stream_t base;
iree_allocator_t host_allocator;
iree_io_memory_stream_release_callback_t release_callback;
iree_io_stream_pos_t offset;
iree_io_stream_pos_t length;
uint8_t* contents;
} iree_io_memory_stream_t;
static const iree_io_stream_vtable_t iree_io_memory_stream_vtable;
static iree_io_memory_stream_t* iree_io_memory_stream_cast(
iree_io_stream_t* IREE_RESTRICT base_stream) {
return (iree_io_memory_stream_t*)base_stream;
}
IREE_API_EXPORT iree_status_t iree_io_memory_stream_wrap(
iree_io_stream_mode_t mode, iree_byte_span_t contents,
iree_io_memory_stream_release_callback_t release_callback,
iree_allocator_t host_allocator, iree_io_stream_t** out_stream) {
IREE_ASSERT_ARGUMENT(out_stream);
*out_stream = NULL;
IREE_TRACE_ZONE_BEGIN(z0);
IREE_TRACE_ZONE_APPEND_VALUE_I64(z0, (int64_t)contents.data_length);
iree_io_memory_stream_t* stream = NULL;
IREE_RETURN_AND_END_ZONE_IF_ERROR(
z0,
iree_allocator_malloc(host_allocator, sizeof(*stream), (void**)&stream));
iree_atomic_ref_count_init(&stream->base.ref_count);
stream->base.vtable = &iree_io_memory_stream_vtable;
stream->base.mode = mode;
stream->host_allocator = host_allocator;
stream->release_callback = release_callback;
stream->offset = 0;
stream->length = contents.data_length;
stream->contents = contents.data;
*out_stream = &stream->base;
IREE_TRACE_ZONE_END(z0);
return iree_ok_status();
}
static void iree_io_memory_stream_destroy(
iree_io_stream_t* IREE_RESTRICT base_stream) {
iree_io_memory_stream_t* stream = iree_io_memory_stream_cast(base_stream);
iree_allocator_t host_allocator = stream->host_allocator;
IREE_TRACE_ZONE_BEGIN(z0);
if (stream->release_callback.fn) {
stream->release_callback.fn(stream->release_callback.user_data,
base_stream);
}
iree_allocator_free(host_allocator, stream);
IREE_TRACE_ZONE_END(z0);
}
static iree_io_stream_pos_t iree_io_memory_stream_offset(
iree_io_stream_t* base_stream) {
IREE_ASSERT_ARGUMENT(base_stream);
iree_io_memory_stream_t* stream = iree_io_memory_stream_cast(base_stream);
return stream->offset;
}
static iree_io_stream_pos_t iree_io_memory_stream_length(
iree_io_stream_t* base_stream) {
IREE_ASSERT_ARGUMENT(base_stream);
iree_io_memory_stream_t* stream = iree_io_memory_stream_cast(base_stream);
return stream->length;
}
static iree_status_t iree_io_memory_stream_seek(
iree_io_stream_t* base_stream, iree_io_stream_seek_mode_t seek_mode,
iree_io_stream_pos_t offset) {
IREE_ASSERT_ARGUMENT(base_stream);
iree_io_memory_stream_t* stream = iree_io_memory_stream_cast(base_stream);
IREE_TRACE_ZONE_BEGIN(z0);
iree_status_t status = iree_io_stream_apply_fixed_seek(
stream->offset, stream->length, seek_mode, offset, &stream->offset);
IREE_TRACE_ZONE_END(z0);
return status;
}
static iree_status_t iree_io_memory_stream_read(
iree_io_stream_t* base_stream, iree_host_size_t buffer_capacity,
void* buffer, iree_host_size_t* out_buffer_length) {
IREE_ASSERT_ARGUMENT(base_stream);
IREE_ASSERT_ARGUMENT(buffer);
if (out_buffer_length) *out_buffer_length = 0;
iree_io_memory_stream_t* stream = iree_io_memory_stream_cast(base_stream);
IREE_TRACE_ZONE_BEGIN(z0);
iree_io_stream_pos_t read_length = 0;
IREE_RETURN_AND_END_ZONE_IF_ERROR(
z0, iree_io_stream_validate_fixed_range(stream->offset, stream->length,
buffer_capacity, &read_length));
if (!out_buffer_length && read_length != buffer_capacity) {
IREE_RETURN_AND_END_ZONE_IF_ERROR(
z0,
iree_make_status(IREE_STATUS_OUT_OF_RANGE,
"read of range [%" PRIu64 ", %" PRIu64 ") (%" PRIu64
" bytes) out of range; stream offset %" PRIu64
" and length %" PRIu64 " insufficient",
stream->offset, stream->offset + buffer_capacity,
(iree_io_stream_pos_t)buffer_capacity, stream->offset,
stream->length));
}
memcpy(buffer, stream->contents + stream->offset,
(iree_host_size_t)read_length);
stream->offset += read_length;
if (out_buffer_length) *out_buffer_length = (iree_host_size_t)read_length;
IREE_TRACE_ZONE_END(z0);
return iree_ok_status();
}
static iree_status_t iree_io_memory_stream_write(iree_io_stream_t* base_stream,
iree_host_size_t buffer_length,
const void* buffer) {
IREE_ASSERT_ARGUMENT(base_stream);
IREE_ASSERT_ARGUMENT(buffer);
iree_io_memory_stream_t* stream = iree_io_memory_stream_cast(base_stream);
IREE_TRACE_ZONE_BEGIN(z0);
IREE_RETURN_AND_END_ZONE_IF_ERROR(
z0, iree_io_stream_validate_fixed_range(stream->offset, stream->length,
buffer_length, NULL));
memcpy(stream->contents + stream->offset, buffer, buffer_length);
stream->offset += buffer_length;
IREE_TRACE_ZONE_END(z0);
return iree_ok_status();
}
static iree_status_t iree_io_memory_stream_fill(
iree_io_stream_t* base_stream, iree_io_stream_pos_t count,
const void* pattern, iree_host_size_t pattern_length) {
IREE_ASSERT_ARGUMENT(base_stream);
IREE_ASSERT_ARGUMENT(pattern);
iree_io_memory_stream_t* stream = iree_io_memory_stream_cast(base_stream);
IREE_TRACE_ZONE_BEGIN(z0);
iree_io_stream_pos_t access_length = count * pattern_length;
IREE_RETURN_AND_END_ZONE_IF_ERROR(
z0, iree_io_stream_validate_fixed_range(stream->offset, stream->length,
access_length, NULL));
iree_status_t status = iree_ok_status();
uint8_t* data_ptr = stream->contents + stream->offset;
switch (pattern_length) {
case 1: {
uint8_t* data = (uint8_t*)data_ptr;
uint8_t value_bits = *(const uint8_t*)(pattern);
memset(data, value_bits, count);
break;
}
case 2: {
uint16_t* data = (uint16_t*)data_ptr;
uint16_t value_bits = *(const uint16_t*)(pattern);
for (iree_device_size_t i = 0; i < count; ++i) {
iree_unaligned_store(&data[i], value_bits);
}
break;
}
case 4: {
uint32_t* data = (uint32_t*)data_ptr;
uint32_t value_bits = *(const uint32_t*)(pattern);
for (iree_device_size_t i = 0; i < count; ++i) {
iree_unaligned_store(&data[i], value_bits);
}
break;
}
case 8: {
uint64_t* data = (uint64_t*)data_ptr;
uint64_t value_bits = *(const uint64_t*)(pattern);
for (iree_device_size_t i = 0; i < count; ++i) {
iree_unaligned_store(&data[i], value_bits);
}
break;
}
default:
IREE_ASSERT_UNREACHABLE("verified in iree_io_stream_fill");
break;
}
if (iree_status_is_ok(status)) {
stream->offset += access_length;
}
IREE_TRACE_ZONE_END(z0);
return status;
}
static iree_status_t iree_io_memory_stream_map_read(
iree_io_stream_t* base_stream, iree_host_size_t length,
iree_const_byte_span_t* out_span) {
IREE_ASSERT_ARGUMENT(base_stream);
IREE_ASSERT_ARGUMENT(out_span);
*out_span = iree_const_byte_span_empty();
iree_io_memory_stream_t* stream = iree_io_memory_stream_cast(base_stream);
IREE_TRACE_ZONE_BEGIN(z0);
IREE_RETURN_AND_END_ZONE_IF_ERROR(
z0, iree_io_stream_validate_fixed_range(stream->offset, stream->length,
length, NULL));
*out_span =
iree_make_const_byte_span(stream->contents + stream->offset, length);
stream->offset += length;
IREE_TRACE_ZONE_END(z0);
return iree_ok_status();
}
static iree_status_t iree_io_memory_stream_map_write(
iree_io_stream_t* base_stream, iree_host_size_t length,
iree_byte_span_t* out_span) {
IREE_ASSERT_ARGUMENT(base_stream);
IREE_ASSERT_ARGUMENT(out_span);
*out_span = iree_byte_span_empty();
iree_io_memory_stream_t* stream = iree_io_memory_stream_cast(base_stream);
IREE_TRACE_ZONE_BEGIN(z0);
IREE_RETURN_AND_END_ZONE_IF_ERROR(
z0, iree_io_stream_validate_fixed_range(stream->offset, stream->length,
length, NULL));
*out_span = iree_make_byte_span(stream->contents + stream->offset, length);
stream->offset += length;
IREE_TRACE_ZONE_END(z0);
return iree_ok_status();
}
static const iree_io_stream_vtable_t iree_io_memory_stream_vtable = {
.destroy = iree_io_memory_stream_destroy,
.offset = iree_io_memory_stream_offset,
.length = iree_io_memory_stream_length,
.seek = iree_io_memory_stream_seek,
.read = iree_io_memory_stream_read,
.write = iree_io_memory_stream_write,
.fill = iree_io_memory_stream_fill,
.map_read = iree_io_memory_stream_map_read,
.map_write = iree_io_memory_stream_map_write,
};