Skip to content

Commit

Permalink
Fix Efficient access to streambuf buffer (#2361)
Browse files Browse the repository at this point in the history
  • Loading branch information
miscco authored Dec 17, 2021
1 parent 2ff8149 commit 7c78a42
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 17 deletions.
31 changes: 15 additions & 16 deletions stl/inc/sstream
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ public:
_Mystate &= ~_Allocated;
}
}

_Tidy();
return _Result;
}
Expand Down Expand Up @@ -457,29 +458,27 @@ protected:

#if _HAS_CXX20
void _Init_string_inplace(_Mystr&& _Str, int _State) {
_State |= _From_rvalue;
if ((_State & _Noread) && (_State & _Constant)) { // Cannot read / write buffer, do nothing
_Seekhigh = nullptr;
_Mystate = _State | _From_rvalue;
return;
}

// finite buffer that can be read or written, set it up
auto [_Ptr, _Size, _Res] = _Str._Release_to_buffer(_Al);
_Elem* const _Pnew = _Unfancy(_Ptr);
if (_Res != 0 && (_State & (_Noread | _Constant)) != (_Noread | _Constant)) {
// finite buffer that can be read or written, set it up
_Seekhigh = _Pnew + _Size;
auto _End_buffer = _Pnew + _Res;
_Seekhigh = _Pnew + _Size;
auto _Next = (_State & (_Atend | _Append)) ? _Seekhigh : _Pnew;
auto _End_buffer = _Pnew + _Res;

_Mysb::setp(_Pnew, (_State & (_Atend | _Append)) ? _Seekhigh : _Pnew, _End_buffer);

if (_State & _Noread) { // maintain "_Allocated == eback() points to buffer base" invariant
_Mysb::setg(_Pnew, nullptr, _Pnew);
} else {
_Mysb::setg(_Pnew, _Pnew, _Seekhigh);
}

_State |= _Allocated;
_Mysb::setp(_Pnew, _Next, _End_buffer);
if (_State & _Noread) { // maintain "_Allocated == eback() points to buffer base" invariant
_Mysb::setg(_Pnew, nullptr, _Pnew);
} else {
_Seekhigh = nullptr;
_Mysb::setg(_Pnew, _Pnew, _Seekhigh);
}

_Mystate = _State;
_Mystate = _State | _Allocated | _From_rvalue;
}
#endif // _HAS_CXX20

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,25 @@ constexpr char large_string[] =
template <typename Stream>
struct test_rvalue {
void operator()(const string& init_value) {
test(init_value, ios_base::in);
test(init_value, ios_base::out);
test(init_value, ios_base::app);
test(init_value, ios_base::ate);
}

void test(const string& init_value, const ios_base::openmode mode) {
string buffer{init_value};
size_t res = buffer.capacity();
Stream stream{move(buffer)};
Stream stream{move(buffer), mode};

// If the stream cannot be written or read we do nothing
const auto buffer_view = stream.rdbuf()->_Get_buffer_view();
if (!buffer_view._Ptr) {
assert(!(mode & ios_base::in) && !(mode & ios_base::out));
assert(buffer == init_value);
return;
}

assert(stream.view() == init_value);
assert(stream.str() == init_value);
assert(stream.view() == init_value);
Expand Down

0 comments on commit 7c78a42

Please sign in to comment.