Commit 603fdafb authored by Matthias Vallentin's avatar Matthias Vallentin

Support arraybuf repositioning

parent ef98684b
...@@ -55,14 +55,15 @@ public: ...@@ -55,14 +55,15 @@ public:
&& detail::has_size_member<Container>::value && detail::has_size_member<Container>::value
>::type >::type
> >
arraybuf(Container& c) : arraybuf(const_cast<CharT*>(c.data()), c.size()) { arraybuf(Container& c)
: arraybuf(const_cast<char_type*>(c.data()), c.size()) {
// nop // nop
} }
/// Constructs an array streambuffer from a raw character sequence. /// Constructs an array streambuffer from a raw character sequence.
/// @param data A pointer to the first character. /// @param data A pointer to the first character.
/// @param size The length of the character sequence. /// @param size The length of the character sequence.
arraybuf(CharT* data, size_t size) { arraybuf(char_type* data, size_t size) {
setbuf(data, static_cast<std::streamsize>(size)); setbuf(data, static_cast<std::streamsize>(size));
} }
...@@ -87,13 +88,75 @@ public: ...@@ -87,13 +88,75 @@ public:
} }
protected: protected:
std::basic_streambuf<CharT, Traits>* // -- positioning ----------------------------------------------------------
setbuf(CharT* s, std::streamsize n) override {
std::basic_streambuf<char_type, Traits>*
setbuf(char_type* s, std::streamsize n) override {
this->setg(s, s, s + n); this->setg(s, s, s + n);
this->setp(s, s + n); this->setp(s, s + n);
return this; return this;
} }
pos_type seekpos(pos_type pos,
std::ios_base::openmode which
= std::ios_base::in | std::ios_base::out) override {
auto get = (which & std::ios_base::in) == std::ios_base::in;
auto put = (which & std::ios_base::out) == std::ios_base::out;
if (!(get || put))
return pos_type(off_type(-1)); // nothing to do
if (get)
this->setg(this->eback(), this->eback() + pos, this->egptr());
if (put) {
this->setp(this->pbase(), this->epptr());
this->pbump(pos);
}
return pos;
}
pos_type seekoff(off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which) override {
auto new_off = pos_type(off_type(-1));
auto get = (which & std::ios_base::in) == std::ios_base::in;
auto put = (which & std::ios_base::out) == std::ios_base::out;
if (!(get || put))
return new_off; // nothing to do
if (get) {
switch (dir) {
case std::ios_base::beg:
new_off = 0;
break;
case std::ios_base::cur:
new_off = this->gptr() - this->eback();
break;
case std::ios_base::end:
new_off = this->egptr() - this->eback();
break;
}
new_off += off;
this->setg(this->eback(), this->eback() + new_off, this->egptr());
}
if (put) {
switch (dir) {
case std::ios_base::beg:
new_off = 0;
break;
case std::ios_base::cur:
new_off = this->pptr() - this->pbase();
break;
case std::ios_base::end:
new_off = this->egptr() - this->pbase();
break;
}
new_off += off;
this->setp(this->pbase(), this->epptr());
this->pbump(new_off);
}
return new_off;
}
// -- put area -------------------------------------------------------------
std::streamsize xsputn(const char_type* s, std::streamsize n) override { std::streamsize xsputn(const char_type* s, std::streamsize n) override {
auto available = this->epptr() - this->pptr(); auto available = this->epptr() - this->pptr();
auto actual = std::min(n, static_cast<std::streamsize>(available)); auto actual = std::min(n, static_cast<std::streamsize>(available));
...@@ -103,6 +166,8 @@ protected: ...@@ -103,6 +166,8 @@ protected:
return actual; return actual;
} }
// -- get area -------------------------------------------------------------
std::streamsize xsgetn(char_type* s, std::streamsize n) override { std::streamsize xsgetn(char_type* s, std::streamsize n) override {
auto available = this->egptr() - this->gptr(); auto available = this->egptr() - this->gptr();
auto actual = std::min(n, static_cast<std::streamsize>(available)); auto actual = std::min(n, static_cast<std::streamsize>(available));
......
...@@ -56,13 +56,28 @@ CAF_TEST(signed_arraybuf) { ...@@ -56,13 +56,28 @@ CAF_TEST(signed_arraybuf) {
} }
CAF_TEST(unsigned_arraybuf) { CAF_TEST(unsigned_arraybuf) {
std::vector<uint8_t> data = {1, 2, 3, 4}; std::vector<uint8_t> data = {0x0a, 0x0b, 0x0c, 0x0d};
arraybuf<uint8_t> ab{data}; arraybuf<uint8_t> ab{data};
decltype(data) buf; decltype(data) buf;
std::copy(std::istreambuf_iterator<uint8_t>{&ab}, std::copy(std::istreambuf_iterator<uint8_t>{&ab},
std::istreambuf_iterator<uint8_t>{}, std::istreambuf_iterator<uint8_t>{},
std::back_inserter(buf)); std::back_inserter(buf));
CAF_CHECK_EQUAL(data, buf); CAF_CHECK_EQUAL(data, buf);
// Relative positioning.
CAF_CHECK_EQUAL(ab.pubseekoff(2, std::ios::beg, std::ios::in), 2);
CAF_CHECK_EQUAL(ab.sbumpc(), 0x0c);
CAF_CHECK_EQUAL(ab.sgetc(), 0x0d);
CAF_CHECK_EQUAL(ab.pubseekoff(0, std::ios::cur, std::ios::in), 3);
CAF_CHECK_EQUAL(ab.pubseekoff(-2, std::ios::cur, std::ios::in), 1);
CAF_CHECK_EQUAL(ab.sgetc(), 0x0b);
CAF_CHECK_EQUAL(ab.pubseekoff(-4, std::ios::end, std::ios::in), 0);
CAF_CHECK_EQUAL(ab.sgetc(), 0x0a);
// Absolute positioning.
CAF_CHECK_EQUAL(ab.pubseekpos(1, std::ios::in), 1);
CAF_CHECK_EQUAL(ab.sgetc(), 0x0b);
CAF_CHECK_EQUAL(ab.pubseekpos(3, std::ios::in), 3);
CAF_CHECK_EQUAL(ab.sbumpc(), 0x0d);
CAF_CHECK_EQUAL(ab.in_avail(), 0);
} }
CAF_TEST(containerbuf) { CAF_TEST(containerbuf) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment