[libcxx-commits] [libcxx] [libc++] Optimize filebuf::seekoff (PR #211788)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jul 24 06:27:30 PDT 2026


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/211788

None

>From 4f9e1ea36203a96afaff87a0f962f5116f726b73 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                        |  57 +++-
 .../test/benchmarks/streams/fstream.bench.cpp |  58 +++-
 .../fstreams/filebuf.virtuals/seekoff.dat     |   1 +
 .../filebuf.virtuals/seekoff.pass.cpp         | 320 +++++++++++++++---
 4 files changed, 376 insertions(+), 60 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..099c025e16e18 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,53 @@ 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;
   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 (__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;
+      }
+    }
+
+    if (sync() || __fseek(__file_, __width <= 0 ? 0 : __width * __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 ((__cm_ & ios::in) &&
+        (__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;
+    }
+
     __whence = SEEK_CUR;
-    break;
-  case ios_base::end:
+  } break;
+  case ios::end: {
     __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_, __width > 0 ? __width * __off : 0, __whence))
     return pos_type(off_type(-1));
   pos_type __r = __ftell(__file_);
   __r.state(__st_);
@@ -1031,7 +1060,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..908670c753fbd 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,287 @@
 // 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 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.pubseekoff(1, std::ios::beg) == 1);
+      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');
+      // 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);
+      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.pubseekoff(1, std::ios::beg) == 1);
+      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