#pragma once #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(usz)> m_allocator{}; mutable usz m_allocation_size = 0u; public: io_buffer() = default; template io_buffer(const T& container) { m_ptr = const_cast(reinterpret_cast(container.data())); m_size = container.size_bytes(); } io_buffer(std::function(usz)> 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) {} void reserve(usz size) const { m_allocation_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(m_allocation_size); } 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) }; } bool empty() const { return m_size == 0; } }; }