feat: memory_istream seek support

This commit is contained in:
MihailRis 2026-06-11 00:17:31 +03:00
parent 07702f9e57
commit ce0f90d21e
2 changed files with 62 additions and 1 deletions

View file

@ -15,8 +15,33 @@ public:
memory_streambuf(const memory_streambuf&) = delete; memory_streambuf(const memory_streambuf&) = delete;
memory_streambuf& operator=(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: protected:
int_type underflow() override { int_type underflow() override {
if (gptr() < egptr()) {
return traits_type::to_int_type(*gptr());
}
return traits_type::eof(); return traits_type::eof();
} }
@ -36,7 +61,7 @@ private:
class memory_view_streambuf : public std::streambuf { class memory_view_streambuf : public std::streambuf {
public: public:
explicit memory_view_streambuf(const util::Buffer<char>& buffer) explicit memory_view_streambuf(const util::Buffer<char>& buffer)
: buffer(std::move(buffer)) { : buffer(buffer) {
char* base = const_cast<char*>(this->buffer.data()); char* base = const_cast<char*>(this->buffer.data());
char* end = base + this->buffer.size(); char* end = base + this->buffer.size();
setg(base, base, end); setg(base, base, end);
@ -45,8 +70,33 @@ public:
memory_view_streambuf(const memory_view_streambuf&) = delete; memory_view_streambuf(const memory_view_streambuf&) = delete;
memory_view_streambuf& operator=(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: protected:
int_type underflow() override { int_type underflow() override {
if (gptr() < egptr()) {
return traits_type::to_int_type(*gptr());
}
return traits_type::eof(); return traits_type::eof();
} }

View file

@ -16,4 +16,15 @@ TEST(io, memory_istream) {
ASSERT_EQ(text, std::string(data)); ASSERT_EQ(text, std::string(data));
stream.read(text.data(), 1); stream.read(text.data(), 1);
ASSERT_TRUE(stream.eof()); 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!");
} }