[libcxx-commits] [libcxx] [libc++] Optimize filebuf::seekoff (PR #211788)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jul 27 06:32:57 PDT 2026
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/211788
>From 6b2aadf6e348f60efe4615cf6600875529a71e67 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Fri, 24 Jul 2026 14:21:07 +0200
Subject: [PATCH] [libc++] Optimize filebuf::seekoff
---
libcxx/include/fstream | 86 ++++-
.../test/benchmarks/streams/fstream.bench.cpp | 58 ++-
.../fstreams/filebuf.virtuals/seekoff.dat | 1 +
.../filebuf.virtuals/seekoff.pass.cpp | 340 +++++++++++++++---
4 files changed, 424 insertions(+), 61 deletions(-)
create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/seekoff.dat
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::trunc) != 0);
- assert(f.is_open());
- f.sputn(L"abcdefghijklmnopqrstuvwxyz", 26);
- LIBCPP_ASSERT(buf[0] == L'v');
- pos_type p = f.pubseekoff(-15, std::ios_base::cur);
- assert(p == 11);
- assert(f.sgetc() == L'l');
- f.pubseekoff(0, std::ios_base::beg);
- assert(f.sgetc() == L'a');
- f.pubseekoff(-1, std::ios_base::end);
- assert(f.sgetc() == L'z');
- assert(f.pubseekpos(p) == p);
- assert(f.sgetc() == L'l');
- }
- std::remove("seekoff.dat");
+ test<wchar_t>();
#endif
+ // TODO: test with different codecvt facets (e.g. where always_noconv() is false, encoding() == 0/-1)
+
return 0;
}
More information about the libcxx-commits
mailing list