[libcxx-commits] [libcxx] [libc++] Optimize filebuf::seekoff (PR #211788)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jul 27 07:20:36 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Nikolas Klauser (philnik777)
<details>
<summary>Changes</summary>
In some cases it is possible to avoid synchronizing with the underlying stream, and instead just move the cursor inside the buffer. This can significantly improve performance, since it avoids making potentially expensive syscalls.
---
Patch is 20.67 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/211788.diff
4 Files Affected:
- (modified) libcxx/include/fstream (+71-15)
- (modified) libcxx/test/benchmarks/streams/fstream.bench.cpp (+56-2)
- (added) libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/seekoff.dat (+1)
- (modified) libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/seekoff.pass.cpp (+296-44)
``````````diff
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 4b276251aa917..453fd8bfcba45 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -387,7 +387,7 @@ private:
void __write_mode();
_LIBCPP_HIDE_FROM_ABI static int __fseek(FILE* __file, pos_type __offset, int __whence);
- _LIBCPP_HIDE_FROM_ABI static pos_type __ftell(FILE* __file);
+ _LIBCPP_HIDE_FROM_ABI static off_type __ftell(FILE* __file);
_LIBCPP_EXPORTED_FROM_ABI friend FILE* __get_ostream_file(ostream&);
@@ -995,24 +995,80 @@ basic_filebuf<_CharT, _Traits>::seekoff(off_type __off, ios_base::seekdir __way,
std::__throw_bad_cast();
int __width = __cv_->encoding();
- if (__file_ == nullptr || (__width <= 0 && __off != 0) || sync())
+ if (__file_ == nullptr || (__width <= 0 && __off != 0))
return pos_type(off_type(-1));
- // __width > 0 || __off == 0
- int __whence;
+
+ auto __byte_off = __width <= 0 ? 0 : __width * __off;
+
+ int __whence = 0;
switch (__way) {
- case ios_base::beg:
- __whence = SEEK_SET;
- break;
- case ios_base::cur:
+ case ios::beg: {
+ if (__off < 0)
+ return pos_type(off_type(-1));
+
+ pos_type __success_pos = __off;
+ __success_pos.state(__st_);
+
+ if (__always_noconv_ && __cm_ & ios::in) {
+ off_type __file_pos = __ftell(__file_);
+ auto __buffer_base_pos = __file_pos - (this->egptr() - this->eback());
+
+ // If the new position is within the buffer we can just move the current read pointer
+ if (__off >= __buffer_base_pos && __off <= __file_pos) {
+ this->setg(this->eback(), this->eback() + (__off - __buffer_base_pos), this->egptr());
+ return __success_pos;
+ } else {
+ // Otherwise drop the buffer and seek to the requested position
+ this->setg(nullptr, nullptr, nullptr);
+ __cm_ = 0;
+ if (__fseek(__file_, __byte_off, SEEK_SET))
+ return pos_type(off_type(-1));
+ return __success_pos;
+ }
+ }
+
+ if (sync() || __fseek(__file_, __byte_off, SEEK_SET))
+ return pos_type(off_type(-1));
+ return __success_pos;
+ }
+ case ios::cur: {
+ // If the new position is within the buffer we can just move the current read pointer
+ if (__always_noconv_ && (__cm_ & ios::in)) {
+ if (__off < 0 ? this->gptr() - this->eback() <= __off : this->egptr() - this->gptr() >= __off) {
+ this->setg(this->eback(), this->gptr() + __off, this->egptr());
+
+ pos_type __ret = __ftell(__file_) - (this->egptr() - this->gptr());
+ __ret.state(__st_);
+ return __ret;
+ } else {
+ if (__fseek(__file_, __byte_off - (this->egptr() - this->gptr()), SEEK_CUR))
+ return pos_type(off_type(-1));
+ this->setg(nullptr, nullptr, nullptr);
+ __cm_ = 0;
+ pos_type __ret = __ftell(__file_);
+ __ret.state(__st_);
+ return __ret;
+ }
+ }
+
__whence = SEEK_CUR;
- break;
- case ios_base::end:
+ } break;
+ case ios::end: {
+ if (__always_noconv_ && (__cm_ & ios::in)) {
+ this->setg(nullptr, nullptr, nullptr);
+ __cm_ = 0;
+ if (__fseek(__file_, __byte_off, SEEK_END))
+ return pos_type(off_type(-1));
+ pos_type __ret = __ftell(__file_);
+ __ret.state(__st_);
+ return __ret;
+ }
+
__whence = SEEK_END;
- break;
- default:
- return pos_type(off_type(-1));
+ } break;
}
- if (__fseek(__file_, __width > 0 ? __width * __off : 0, __whence))
+
+ if (sync() || __fseek(__file_, __byte_off, __whence))
return pos_type(off_type(-1));
pos_type __r = __ftell(__file_);
__r.state(__st_);
@@ -1031,7 +1087,7 @@ int basic_filebuf<_CharT, _Traits>::__fseek(FILE* __file, pos_type __offset, int
}
template <class _CharT, class _Traits>
-typename basic_filebuf<_CharT, _Traits>::pos_type basic_filebuf<_CharT, _Traits>::__ftell(FILE* __file) {
+typename basic_filebuf<_CharT, _Traits>::off_type basic_filebuf<_CharT, _Traits>::__ftell(FILE* __file) {
# if defined(_LIBCPP_MSVCRT_LIKE)
return _ftelli64(__file);
# elif _LIBCPP_LIBC_NEWLIB
diff --git a/libcxx/test/benchmarks/streams/fstream.bench.cpp b/libcxx/test/benchmarks/streams/fstream.bench.cpp
index 2e16ae58749e6..5b23f16614f49 100644
--- a/libcxx/test/benchmarks/streams/fstream.bench.cpp
+++ b/libcxx/test/benchmarks/streams/fstream.bench.cpp
@@ -28,8 +28,10 @@ static void bm_ifstream_read(benchmark::State& state) {
std::vector<char> buffer;
buffer.resize(16384);
- std::ofstream gen_testfile("testfile");
- gen_testfile.write(buffer.data(), buffer.size());
+ {
+ std::ofstream gen_testfile("testfile");
+ gen_testfile.write(buffer.data(), buffer.size());
+ }
std::ifstream stream("testfile");
assert(stream);
@@ -42,4 +44,56 @@ static void bm_ifstream_read(benchmark::State& state) {
}
BENCHMARK(bm_ifstream_read)->Name("std::ifstream::read(char*, size)");
+void run_sizes(benchmark::Benchmark* benchmark) { benchmark->Arg(0)->Arg(100)->Arg(4000)->Arg(10000); }
+
+template <bool prime>
+static void bm_seekoff_cur(benchmark::State& state) {
+ std::vector<char> buffer;
+ buffer.resize(16384);
+
+ {
+ std::ofstream gen_testfile("testfile");
+ gen_testfile.write(buffer.data(), buffer.size());
+ }
+
+ std::ifstream stream("testfile");
+ assert(stream);
+
+ auto val = state.range();
+
+ for (auto _ : state) {
+ if constexpr (prime)
+ benchmark::DoNotOptimize(stream.rdbuf()->sgetc());
+ benchmark::DoNotOptimize(stream.seekg(val, std::ios::cur));
+ val = -val;
+ }
+}
+BENCHMARK(bm_seekoff_cur<true>)->Name("std::ifstream::seekg(N, std::ios::cur) (primed buffer)")->Apply(run_sizes);
+BENCHMARK(bm_seekoff_cur<false>)->Name("std::ifstream::seekg(N, std::ios::cur) (unprimed buffer)")->Apply(run_sizes);
+
+template <bool prime>
+static void bm_seekoff_beg(benchmark::State& state) {
+ std::vector<char> buffer;
+ buffer.resize(16384);
+
+ {
+ std::ofstream gen_testfile("testfile");
+ gen_testfile.write(buffer.data(), buffer.size());
+ }
+
+ std::ifstream stream("testfile");
+ assert(stream);
+
+ auto val = state.range();
+
+ for (auto _ : state) {
+ if constexpr (prime)
+ benchmark::DoNotOptimize(stream.rdbuf()->sgetc());
+ benchmark::DoNotOptimize(stream.seekg(val, std::ios::beg));
+ benchmark::DoNotOptimize(stream.seekg(0, std::ios::beg));
+ }
+}
+BENCHMARK(bm_seekoff_beg<true>)->Name("std::ifstream::seekg(N, std::ios::beg) (primed buffer)")->Apply(run_sizes);
+BENCHMARK(bm_seekoff_beg<false>)->Name("std::ifstream::seekg(N, std::ios::beg) (unprimed buffer)")->Apply(run_sizes);
+
BENCHMARK_MAIN();
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/seekoff.dat b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/seekoff.dat
new file mode 100644
index 0000000000000..6a537b5b36788
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/seekoff.dat
@@ -0,0 +1 @@
+1234567890
\ No newline at end of file
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/seekoff.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/seekoff.pass.cpp
index f6378e7998ee9..68e0988a28c27 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/seekoff.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/seekoff.pass.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+// FILE_DEPENDENCIES: seekoff.dat
+
// <fstream>
// pos_type seekoff(off_type off, ios_base::seekdir way,
@@ -13,57 +15,307 @@
// pos_type seekpos(pos_type sp,
// ios_base::openmode which = ios_base::in | ios_base::out);
-#include <fstream>
#include <cassert>
+#include <fstream>
+#include "make_string.h"
#include "test_macros.h"
-int main(int, char**)
-{
- {
- char buf[10];
- typedef std::filebuf::pos_type pos_type;
- std::filebuf f;
- f.pubsetbuf(buf, sizeof(buf));
- assert(f.open("seekoff.dat", std::ios_base::in | std::ios_base::out
- | std::ios_base::trunc) != 0);
- assert(f.is_open());
- f.sputn("abcdefghijklmnopqrstuvwxyz", 26);
- pos_type p = f.pubseekoff(-15, std::ios_base::cur);
- assert(p == 11);
- assert(f.sgetc() == 'l');
- f.pubseekoff(0, std::ios_base::beg);
- assert(f.sgetc() == 'a');
- f.pubseekoff(-1, std::ios_base::end);
- assert(f.sgetc() == 'z');
- assert(f.pubseekpos(p) == p);
- assert(f.sgetc() == 'l');
- }
- std::remove("seekoff.dat");
+template <class CharT>
+void reopen(std::basic_filebuf<CharT>& fb) {
+ fb.close();
+ fb.open("seekoff.dat", std::ios::in);
+}
+
+template <class CharT>
+void test() {
+ using filebuf = std::basic_filebuf<CharT>;
+
+ { // seek with file closed
+ filebuf fb;
+ assert(fb.pubseekoff(0, std::ios::beg) == -1);
+ }
+
+ { // seek stream from begin
+ { // unbuffered
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in));
+ // negative offsets
+ assert(fb.pubseekoff(-1, std::ios::beg) == -1);
+ assert(fb.pubseekoff(-2, std::ios::beg) == -1);
+ assert(fb.pubseekoff(std::numeric_limits<typename filebuf::off_type>::min(), std::ios::beg) == -1);
+ // zero offset
+ assert(fb.pubseekoff(0, std::ios::beg) == 0);
+ assert(fb.sgetc() == '1');
+
+ reopen(fb);
+ assert(fb.pubseekoff(1, std::ios::beg) == 1);
+ assert(fb.sgetc() == '2');
+
+ reopen(fb);
+ assert(fb.pubseekoff(10, std::ios::beg) == 10);
+ assert(fb.sgetc() == std::char_traits<CharT>::eof());
+ }
+ { // buffered
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in));
+
+ assert(fb.sgetc() == '1'); // prime the buffer
+
+ // negative offsets
+ assert(fb.pubseekoff(-1, std::ios::beg) == -1);
+ assert(fb.pubseekoff(-2, std::ios::beg) == -1);
+ assert(fb.pubseekoff(std::numeric_limits<typename filebuf::off_type>::min(), std::ios::beg) == -1);
+ // zero offset
+ assert(fb.pubseekoff(0, std::ios::beg) == 0);
+ assert(fb.sgetc() == CharT('1'));
+ assert(fb.pubseekoff(1, std::ios::beg) == 1);
+ assert(fb.sgetc() == CharT('2'));
+ assert(fb.pubseekoff(10, std::ios::beg) == 10);
+ assert(fb.sgetc() == std::char_traits<CharT>::eof());
+ }
+ { // buffered, tiny buffer
+ filebuf fb;
+ CharT buffer[5];
+ fb.pubsetbuf(buffer, 5);
+ assert(fb.open("seekoff.dat", std::ios::in));
+ assert(fb.sgetc() == '1');
+ // negative offsets
+ assert(fb.pubseekoff(-1, std::ios::beg) == -1);
+ assert(fb.pubseekoff(-2, std::ios::beg) == -1);
+ assert(fb.pubseekoff(std::numeric_limits<typename filebuf::off_type>::min(), std::ios::beg) == -1);
+ // zero offset
+ assert(fb.pubseekoff(0, std::ios::beg) == 0);
+ assert(fb.sgetc() == CharT('1'));
+ assert(fb.pubseekoff(1, std::ios::beg) == 1);
+ assert(fb.sgetc() == CharT('2'));
+ assert(fb.pubseekoff(8, std::ios::beg) == 8);
+ assert(fb.sgetc() == CharT('9'));
+ assert(fb.pubseekoff(10, std::ios::beg) == 10);
+ assert(fb.sgetc() == std::char_traits<CharT>::eof());
+ }
+ { // input/output stream, neither read from nor written to
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in | std::ios::out));
+ // negative offsets
+ assert(fb.pubseekoff(-1, std::ios::beg) == -1);
+ assert(fb.pubseekoff(-2, std::ios::beg) == -1);
+ assert(fb.pubseekoff(std::numeric_limits<typename filebuf::off_type>::min(), std::ios::beg) == -1);
+ // zero offset
+ assert(fb.pubseekoff(0, std::ios::beg) == 0);
+ assert(fb.pubseekoff(1, std::ios::beg) == 1);
+ assert(fb.pubseekoff(10, std::ios::beg) == 10);
+ }
+ { // input/output stream, written to
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in | std::ios::out | std::ios::trunc));
+ fb.sputn(MAKE_CSTRING(CharT, "1234567890"), 10);
+ // negative offsets
+ assert(fb.pubseekoff(-1, std::ios::beg) == -1);
+ assert(fb.pubseekoff(-2, std::ios::beg) == -1);
+ assert(fb.pubseekoff(std::numeric_limits<typename filebuf::off_type>::min(), std::ios::beg) == -1);
+ // zero offset
+ assert(fb.pubseekoff(0, std::ios::beg) == 0);
+ assert(fb.pubseekoff(1, std::ios::beg) == 1);
+ assert(fb.pubseekoff(10, std::ios::beg) == 10);
+ }
+ { // input/output stream, read from
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in | std::ios::out));
+
+ assert(fb.pubseekoff(0, std::ios::beg) == 0); // Go to the start, so we can read something
+
+ CharT buffer[11];
+ buffer[10] = '\0';
+ assert(fb.sgetn(buffer, 10) == 10);
+ assert(buffer == MAKE_STRING(CharT, "1234567890"));
+ // negative offsets
+ assert(fb.pubseekoff(-1, std::ios::beg) == -1);
+ assert(fb.pubseekoff(-2, std::ios::beg) == -1);
+ assert(fb.pubseekoff(std::numeric_limits<typename filebuf::off_type>::min(), std::ios::beg) == -1);
+ // zero offset
+ assert(fb.pubseekoff(0, std::ios::beg) == 0);
+ assert(fb.pubseekoff(1, std::ios::beg) == 1);
+ assert(fb.pubseekoff(10, std::ios::beg) == 10);
+ }
+ }
+ { // seek stream from current position
+ { // unbuffered
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in));
+ // negative offsets, from begin
+ assert(fb.pubseekoff(-1, std::ios::cur) == -1);
+ assert(fb.pubseekoff(-2, std::ios::cur) == -1);
+ assert(fb.pubseekoff(std::numeric_limits<typename filebuf::off_type>::min(), std::ios::cur) == -1);
+
+ // zero offset
+ assert(fb.pubseekoff(0, std::ios::cur) == 0);
+ assert(fb.pubseekoff(1, std::ios::cur) == 1);
+
+ // negative offset, from 1 character into the stream
+ assert(fb.pubseekoff(-1, std::ios::cur) == 0);
+
+ assert(fb.pubseekoff(10, std::ios::cur) == 10);
+ assert(fb.sgetc() == std::char_traits<CharT>::eof());
+ }
+ { // buffered
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in));
+ assert(fb.sgetc() == '1');
+
+ // negative offsets, from begin
+ assert(fb.pubseekoff(-1, std::ios::cur) == -1);
+ assert(fb.pubseekoff(-2, std::ios::cur) == -1);
+ assert(fb.pubseekoff(std::numeric_limits<typename filebuf::off_type>::min(), std::ios::cur) == -1);
+
+ // zero offset
+ assert(fb.pubseekoff(0, std::ios::cur) == 0);
+ assert(fb.pubseekoff(1, std::ios::cur) == 1);
+
+ // negative offset, from 1 character into the stream
+ assert(fb.pubseekoff(-1, std::ios::cur) == 0);
+
+ assert(fb.pubseekoff(10, std::ios::cur) == 10);
+ assert(fb.sgetc() == std::char_traits<CharT>::eof());
+ }
+ { // buffered, tiny buffer
+ filebuf fb;
+ CharT buffer[5];
+ fb.pubsetbuf(buffer, 5);
+ assert(fb.open("seekoff.dat", std::ios::in));
+ assert(fb.sgetc() == '1');
+
+ // negative offsets, from begin
+ assert(fb.pubseekoff(-1, std::ios::cur) == -1);
+ assert(fb.pubseekoff(-2, std::ios::cur) == -1);
+ assert(fb.pubseekoff(std::numeric_limits<typename filebuf::off_type>::min(), std::ios::cur) == -1);
+
+ // zero offset
+ assert(fb.pubseekoff(0, std::ios::cur) == 0);
+ assert(fb.pubseekoff(1, std::ios::cur) == 1);
+
+ // negative offset, from 1 character into the stream
+ assert(fb.pubseekoff(-1, std::ios::cur) == 0);
+
+ assert(fb.pubseekoff(10, std::ios::cur) == 10);
+ assert(fb.sgetc() == std::char_traits<CharT>::eof());
+ }
+ { // input/output stream, neither read from nor written to
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in | std::ios::out));
+
+ // negative offsets
+ assert(fb.pubseekoff(-1, std::ios::cur) == -1);
+ assert(fb.pubseekoff(-2, std::ios::cur) == -1);
+ assert(fb.pubseekoff(std::numeric_limits<typename filebuf::off_type>::min(), std::ios::cur) == -1);
+ // zero offset
+ assert(fb.pubseekoff(0, std::ios::cur) == 0);
+ assert(fb.pubseekoff(1, std::ios::cur) == 1);
+
+ // negative offset, from 1 character into the stream
+ assert(fb.pubseekoff(-1, std::ios::cur) == 0);
+ assert(fb.pubseekoff(10, std::ios::cur) == 10);
+ }
+ { // input/output stream, written to
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in | std::ios::out | std::ios::trunc));
+ fb.sputn(MAKE_CSTRING(CharT, "1234567890"), 10);
+
+ // negative offsets; we've written and the cursor is at the end of the file, so these succeed
+ assert(fb.pubseekoff(-1, std::ios::cur) == 9);
+ assert(fb.pubseekoff(-2, std::ios::cur) == 7);
+
+ // except this one, we didn't write this much
+ assert(fb.pubseekoff(std::numeric_limits<typename filebuf::off_type>::min(), std::ios::cur) == -1);
+
+ // zero offset
+ assert(fb.pubseekoff(0, std::ios::cur) == 7);
+ assert(fb.pubseekoff(1, std::ios::cur) == 8);
+ assert(fb.pubseekoff(10, std::ios::cur) == 18);
+ }
+ { // input/output stream, read from
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in | std::ios::out));
+
+ assert(fb.pubseekoff(0, std::ios::beg) == 0); // Go to the start, so we can read something
+
+ CharT buffer[11];
+ buffer[10] = '\0';
+ assert(fb.sgetn(buffer, 10) == 10);
+ assert(buffer == MAKE_STRING(CharT, "1234567890"));
+ // negative offsets; we've read and the cursor is at the end of the file, so these succeed
+ assert(fb.pubseekoff(-1, std::ios::cur) == 9);
+ assert(fb.pubseekoff(-2, std::ios::cur) == 7);
+
+ // except this one, we didn't read this much
+ assert(fb.pubseekoff(std::numeric_limits<typename filebuf::off_type>::min(), std::ios::cur) == -1);
+
+ // zero offset
+ assert(fb.pubseekoff(0, std::ios::cur) == 7);
+ assert(fb.pubseekoff(1, std::ios::cur) == 8);
+ assert(fb.pubseekoff(10, std::ios::cur) == 18);
+ }
+ }
+ { // seek stream end
+ { // unbuffered
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in));
+ assert(fb.pubseekoff(0, std::ios::end) == 10);
+ assert(fb.sgetc() == std::char_traits<CharT>::eof());
+ }
+ { // buffered
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in));
+ assert(fb.sgetc() == '1');
+ assert(fb.pubseekoff(0, std::ios::end) == 10);
+ assert(fb.sgetc() == std::char_traits<CharT>::eof());
+ }
+ { // buffered, tiny buffer
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in));
+ CharT buffer[5];
+ fb.pubsetbuf(buffer, 5);
+ assert(fb.sgetc() == '1');
+ assert(fb.pubseekoff(0, std::ios::end) == 10);
+ assert(fb.sgetc() == std::char_traits<CharT>::eof());
+ }
+ { // input/output stream, neither read from nor written to
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in | std::ios::out));
+ assert(fb.pubseekoff(0, std::ios::end) == 10);
+ assert(fb.sgetc() == std::char_traits<CharT>::eof());
+ }
+ { // input/output stream, written to
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in | std::ios::out | std::ios::trunc));
+ fb.sputn(MAKE_CSTRING(CharT, "1234567890"), 10);
+ assert(fb.pubseekoff(0, std::ios::end) == 10);
+ assert(fb.sgetc() == std::char_traits<CharT>::eof());
+ }
+ { // input/output stream, read from
+ filebuf fb;
+ assert(fb.open("seekoff.dat", std::ios::in | std::ios::out));
+
+ assert(fb.pubseekoff(0, std::ios::beg) == 0); // Go to the start, so we can read something
+
+ CharT buffer[11];
+ buffer[10] = '\0';
+ assert(fb.sgetn(buffer, 10) == 10);
+ assert(buffer == MAKE_STRING(CharT, "1234567890"));
+ assert(fb.pubseekoff(0, std::ios::end) == 10);
+ assert(fb.sgetc() == std::char_traits<CharT>::eof());
+ }
+ }
+}
+
+int main(int, char**) {
+ test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- {
- wchar_t buf[10];
- typedef std::filebuf::pos_type pos_type;
- std::wfilebuf f;
- f.pubsetbuf(buf, sizeof(buf)/sizeof(buf[0]));
- assert(f.open("seekoff.dat", std::ios_base::in | std::ios_base::out
- | std::ios_base::tr...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/211788
More information about the libcxx-commits
mailing list