diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst index 37aa972d22ea3..1852351cedc4e 100644 --- a/libcxx/docs/ReleaseNotes/23.rst +++ b/libcxx/docs/ReleaseNotes/23.rst @@ -69,6 +69,8 @@ Improvements and New Features ``"std::visit: variant is valueless"``, ``"std::get: variant is valueless"``, or ``"std::get: wrong alternative for variant"``. The standard only requires ``what()`` to return an unspecified non-null string, so user code that does not match on the exact message remains correct. +- ``ifstream::read`` has been optimized to pass through large reads to system calls directly instead of copying them in + chunks. Deprecations and Removals ------------------------- diff --git a/libcxx/include/fstream b/libcxx/include/fstream index 0c34c9149de0d..7b84bf6609086 100644 --- a/libcxx/include/fstream +++ b/libcxx/include/fstream @@ -309,6 +309,25 @@ protected: return basic_streambuf<_CharT, _Traits>::xsputn(__str, __len); } + _LIBCPP_HIDE_FROM_ABI_VIRTUAL streamsize xsgetn(char_type* __str, streamsize __len) override { + if (__file_ && __always_noconv_) { + const streamsize __n = std::min(this->egptr() - this->gptr(), __len); + if (__n != 0) { + traits_type::copy(__str, this->gptr(), __n); + this->__gbump_ptrdiff(__n); + } + const streamsize __remainder = __len - __n; + const streamsize __buffer_space = this->egptr() - this->eback(); + + if (__remainder >= __buffer_space) + return std::fread(__str + __n, sizeof(char_type), __remainder, __file_) + __n; + else if (__remainder > 0) + return basic_streambuf<_CharT, _Traits>::xsgetn(__str + __n, __remainder) + __n; + return __n; + } + return basic_streambuf<_CharT, _Traits>::xsgetn(__str, __len); + } + private: char* __extbuf_; const char* __extbufnext_; diff --git a/libcxx/test/benchmarks/streams/ofstream.bench.cpp b/libcxx/test/benchmarks/streams/fstream.bench.cpp similarity index 52% rename from libcxx/test/benchmarks/streams/ofstream.bench.cpp rename to libcxx/test/benchmarks/streams/fstream.bench.cpp index 80827d59cdf01..2e16ae58749e6 100644 --- a/libcxx/test/benchmarks/streams/ofstream.bench.cpp +++ b/libcxx/test/benchmarks/streams/fstream.bench.cpp @@ -13,7 +13,7 @@ #include -static void bm_write(benchmark::State& state) { +static void bm_ofstream_write(benchmark::State& state) { std::vector buffer; buffer.resize(16384); @@ -22,6 +22,24 @@ static void bm_write(benchmark::State& state) { for (auto _ : state) stream.write(buffer.data(), buffer.size()); } -BENCHMARK(bm_write)->Name("std::ofstream::write(char*, size)"); +BENCHMARK(bm_ofstream_write)->Name("std::ofstream::write(char*, size)"); + +static void bm_ifstream_read(benchmark::State& state) { + std::vector buffer; + buffer.resize(16384); + + std::ofstream gen_testfile("testfile"); + gen_testfile.write(buffer.data(), buffer.size()); + + std::ifstream stream("testfile"); + assert(stream); + + for (auto _ : state) { + stream.read(buffer.data(), buffer.size()); + benchmark::DoNotOptimize(buffer); + stream.seekg(0); + } +} +BENCHMARK(bm_ifstream_read)->Name("std::ifstream::read(char*, size)"); BENCHMARK_MAIN(); diff --git a/libcxx/test/libcxx/input.output/file.streams/fstreams/filebuf/traits_mismatch.verify.cpp b/libcxx/test/libcxx/input.output/file.streams/fstreams/filebuf/traits_mismatch.verify.cpp index 283adbc057d1e..30e7b66d42325 100644 --- a/libcxx/test/libcxx/input.output/file.streams/fstreams/filebuf/traits_mismatch.verify.cpp +++ b/libcxx/test/libcxx/input.output/file.streams/fstreams/filebuf/traits_mismatch.verify.cpp @@ -19,4 +19,4 @@ std::basic_filebuf > f; // expected-error-re@*:* {{static assertion failed{{.*}}traits_type::char_type must be the same type as CharT}} -// expected-error@*:* 10 {{only virtual member functions can be marked 'override'}} +// expected-error@*:* 11 {{only virtual member functions can be marked 'override'}} diff --git a/libcxx/test/libcxx/input.output/file.streams/fstreams/traits_mismatch.verify.cpp b/libcxx/test/libcxx/input.output/file.streams/fstreams/traits_mismatch.verify.cpp index ba6f3c31d3e34..daafb36f9151a 100644 --- a/libcxx/test/libcxx/input.output/file.streams/fstreams/traits_mismatch.verify.cpp +++ b/libcxx/test/libcxx/input.output/file.streams/fstreams/traits_mismatch.verify.cpp @@ -21,7 +21,7 @@ std::basic_fstream > f; // expected-error-re@*:* {{static assertion failed{{.*}}traits_type::char_type must be the same type as CharT}} // expected-error-re@*:* {{static assertion failed{{.*}}traits_type::char_type must be the same type as CharT}} -// expected-error@*:* 12 {{only virtual member functions can be marked 'override'}} +// expected-error@*:* 13 {{only virtual member functions can be marked 'override'}} // FIXME: As of commit r324062 Clang incorrectly generates a diagnostic about mismatching // exception specifications for types which are already invalid for one reason or another. diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp index de17cd4d8e9d3..d9ccc2fe62914 100644 --- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp +++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp @@ -68,6 +68,16 @@ int main(int, char**) { test_buffer.resize(24); assert(std::string(test_buffer.data(), 24) == "to test buffer behaviour"); } + { // Ensure that the read fails gracefully with an unopened ifstream + // See https://llvm.org/PR168628 + char buf[10]; + std::ifstream ifs; + std::filebuf* filebuf = ifs.rdbuf(); + + assert(!filebuf->is_open()); + assert(filebuf->sgetn(buf, sizeof(buf)) == 0); + assert(!filebuf->is_open()); + } return 0; }