#pragma once #include #include #include #include #include namespace rsx { template concept SpanLike = requires(T t) { { t.data() } -> std::convertible_to; { t.size_bytes() } -> std::convertible_to; }; template concept Integral = std::is_integral_v || std::is_same_v; class io_buffer { mutable void* m_ptr = nullptr; mutable usz m_size = 0; std::function()> m_allocator{}; public: io_buffer() = default; io_buffer(const io_buffer& that) { m_ptr = that.m_ptr; m_size = that.m_size; m_allocator = that.m_allocator; } template io_buffer(const T& container) { m_ptr = const_cast(reinterpret_cast(container.data())); m_size = container.size_bytes(); } io_buffer(std::function ()> allocator) { ensure(allocator); m_allocator = allocator; } template io_buffer(void* ptr, T size) : m_ptr(ptr), m_size(size) {} template io_buffer(const void* ptr, T size) : m_ptr(const_cast(ptr)), m_size(size) {} std::pair raw() const { return { m_ptr, m_size }; } template T* data() const { if (!m_ptr && m_allocator) { std::tie(m_ptr, m_size) = m_allocator(); } return static_cast(m_ptr); } usz size() const { return m_size; } template std::span as_span() const { auto bytes = data(); return { utils::bless(bytes), m_size / sizeof(T) }; } }; }