From ce0f90d21e6e8ba2da491e6e9ad18f7d7b679eb9 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 11 Jun 2026 00:17:31 +0300 Subject: [PATCH] feat: memory_istream seek support --- src/io/memory_istream.hpp | 52 +++++++++++++++++++++++++++++++++++++- test/io/memory_istream.cpp | 11 ++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/io/memory_istream.hpp b/src/io/memory_istream.hpp index 7c0aded64..84a0c703f 100644 --- a/src/io/memory_istream.hpp +++ b/src/io/memory_istream.hpp @@ -15,8 +15,33 @@ public: memory_streambuf(const memory_streambuf&) = delete; memory_streambuf& operator=(const memory_streambuf&) = delete; + pos_type seekoff(off_type off, std::ios_base::seekdir way, + std::ios_base::openmode mode = std::ios_base::in) override { + if (!(mode & std::ios_base::in)) return pos_type(off_type(-1)); + char* base = eback(); + char* end = egptr(); + if (!base || !end) return pos_type(off_type(-1)); + + std::ptrdiff_t current = gptr() - base; + std::ptrdiff_t newpos; + if (way == std::ios_base::beg) newpos = off; + else if (way == std::ios_base::cur) newpos = current + off; + else if (way == std::ios_base::end) newpos = (end - base) + off; + else return pos_type(off_type(-1)); + + if (newpos < 0 || base + newpos > end) return pos_type(off_type(-1)); + setg(base, base + newpos, end); + return pos_type(off_type(newpos)); + } + + pos_type seekpos(pos_type sp, std::ios_base::openmode mode = std::ios_base::in) override { + return seekoff(off_type(sp), std::ios_base::beg, mode); + } protected: int_type underflow() override { + if (gptr() < egptr()) { + return traits_type::to_int_type(*gptr()); + } return traits_type::eof(); } @@ -36,7 +61,7 @@ private: class memory_view_streambuf : public std::streambuf { public: explicit memory_view_streambuf(const util::Buffer& buffer) - : buffer(std::move(buffer)) { + : buffer(buffer) { char* base = const_cast(this->buffer.data()); char* end = base + this->buffer.size(); setg(base, base, end); @@ -45,8 +70,33 @@ public: memory_view_streambuf(const memory_view_streambuf&) = delete; memory_view_streambuf& operator=(const memory_view_streambuf&) = delete; + pos_type seekoff(off_type off, std::ios_base::seekdir way, + std::ios_base::openmode mode = std::ios_base::in) override { + if (!(mode & std::ios_base::in)) return pos_type(off_type(-1)); + char* base = eback(); + char* end = egptr(); + if (!base || !end) return pos_type(off_type(-1)); + + std::ptrdiff_t current = gptr() - base; + std::ptrdiff_t newpos; + if (way == std::ios_base::beg) newpos = off; + else if (way == std::ios_base::cur) newpos = current + off; + else if (way == std::ios_base::end) newpos = (end - base) + off; + else return pos_type(off_type(-1)); + + if (newpos < 0 || base + newpos > end) return pos_type(off_type(-1)); + setg(base, base + newpos, end); + return pos_type(off_type(newpos)); + } + + pos_type seekpos(pos_type sp, std::ios_base::openmode mode = std::ios_base::in) override { + return seekoff(off_type(sp), std::ios_base::beg, mode); + } protected: int_type underflow() override { + if (gptr() < egptr()) { + return traits_type::to_int_type(*gptr()); + } return traits_type::eof(); } diff --git a/test/io/memory_istream.cpp b/test/io/memory_istream.cpp index faabd23cd..674d250fd 100644 --- a/test/io/memory_istream.cpp +++ b/test/io/memory_istream.cpp @@ -16,4 +16,15 @@ TEST(io, memory_istream) { ASSERT_EQ(text, std::string(data)); stream.read(text.data(), 1); ASSERT_TRUE(stream.eof()); + + // seek + stream.clear(); + stream.seekg(0); + ASSERT_TRUE(stream.good()); + stream.read(text.data(), n); + ASSERT_EQ(text, std::string(data)); + stream.seekg(-6, std::ios_base::cur); + ASSERT_TRUE(stream.good()); + stream.read(text.data(), 6); + ASSERT_EQ(text.substr(0, 6), "world!"); }