[flang-commits] [clang] [lld] [llvm] [flang] [libcxx] [libc++][streams] P1759R6: Native handles and file streams (PR #76632)
Hristo Hristov via flang-commits
flang-commits at lists.llvm.org
Sun Dec 31 23:19:29 PST 2023
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/76632
>From 1165b11477ab59122a4db35221fcefe3c9505387 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sat, 30 Dec 2023 17:34:56 +0200
Subject: [PATCH 1/7] [libc++][streams] P1759R6: Native handles and file
streams
Implements: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p1759r6.html
- https://eel.is/c++draft/filebuf
- https://eel.is/c++draft/ifstream
- https://eel.is/c++draft/ofstream
- https://eel.is/c++draft/fstream
---
libcxx/docs/FeatureTestMacroTable.rst | 2 +-
libcxx/docs/ReleaseNotes/18.rst | 1 +
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
libcxx/include/fstream | 59 +++++++++++++++++++
libcxx/include/version | 2 +-
libcxx/src/CMakeLists.txt | 1 +
libcxx/src/fstream.cpp | 33 +++++++++++
.../fstream.version.compile.pass.cpp | 16 ++---
.../version.version.compile.pass.cpp | 16 ++---
.../generate_feature_test_macro_components.py | 1 -
10 files changed, 107 insertions(+), 26 deletions(-)
create mode 100644 libcxx/src/fstream.cpp
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index ad12b109023154..0427615a9636fd 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -418,7 +418,7 @@ Status
--------------------------------------------------- -----------------
``__cpp_lib_freestanding_variant`` *unimplemented*
--------------------------------------------------- -----------------
- ``__cpp_lib_fstream_native_handle`` *unimplemented*
+ ``__cpp_lib_fstream_native_handle`` ``202306L``
--------------------------------------------------- -----------------
``__cpp_lib_function_ref`` *unimplemented*
--------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index fa60a581652d6a..e6f1adf4d5529b 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -58,6 +58,7 @@ Implemented Papers
- P2870R3 - Remove basic_string::reserve()
- P2909R4 - Fix formatting of code units as integers (Dude, where’s my ``char``?)
- P0521R0 - Proposed Resolution for CA 14 (shared_ptr use_count/unique)
+- P1759R6 - Native handles and file streams
Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index ff83648aa76830..1d7807a4291a99 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -19,7 +19,7 @@
"`P2757R3 <https://wg21.link/P2757R3>`__","LWG","Type-checking format args","Varna June 2023","","","|format|"
"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","","","|format|"
"`P2641R4 <https://wg21.link/P2641R4>`__","CWG, LWG","Checking if a ``union`` alternative is active","Varna June 2023","","",""
-"`P1759R6 <https://wg21.link/P1759R6>`__","LWG","Native handles and file streams","Varna June 2023","","",""
+"`P1759R6 <https://wg21.link/P1759R6>`__","LWG","Native handles and file streams","Varna June 2023","|Complete|","18.0",""
"`P2697R1 <https://wg21.link/P2697R1>`__","LWG","Interfacing ``bitset`` with ``string_view``","Varna June 2023","|Complete|","18.0",""
"`P1383R2 <https://wg21.link/P1383R2>`__","LWG","More ``constexpr`` for ``<cmath>`` and ``<complex>``","Varna June 2023","","",""
"`P2734R0 <https://wg21.link/P2734R0>`__","LWG","Adding the new SI prefixes","Varna June 2023","|Complete|","17.0",""
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 7a4e15b55d56fe..9609ff420220fa 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -73,6 +73,7 @@ public:
typedef typename traits_type::int_type int_type;
typedef typename traits_type::pos_type pos_type;
typedef typename traits_type::off_type off_type;
+ using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type; // Since C++26
basic_ifstream();
explicit basic_ifstream(const char* s, ios_base::openmode mode = ios_base::in);
@@ -85,6 +86,7 @@ public:
void swap(basic_ifstream& rhs);
basic_filebuf<char_type, traits_type>* rdbuf() const;
+ native_handle_type native_handle() const noexcept; // Since C++26
bool is_open() const;
void open(const char* s, ios_base::openmode mode = ios_base::in);
void open(const string& s, ios_base::openmode mode = ios_base::in);
@@ -110,6 +112,7 @@ public:
typedef typename traits_type::int_type int_type;
typedef typename traits_type::pos_type pos_type;
typedef typename traits_type::off_type off_type;
+ using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type; // Since C++26
basic_ofstream();
explicit basic_ofstream(const char* s, ios_base::openmode mode = ios_base::out);
@@ -122,6 +125,8 @@ public:
void swap(basic_ofstream& rhs);
basic_filebuf<char_type, traits_type>* rdbuf() const;
+ native_handle_type native_handle() const noexcept; // Since C++26
+
bool is_open() const;
void open(const char* s, ios_base::openmode mode = ios_base::out);
void open(const string& s, ios_base::openmode mode = ios_base::out);
@@ -148,6 +153,7 @@ public:
typedef typename traits_type::int_type int_type;
typedef typename traits_type::pos_type pos_type;
typedef typename traits_type::off_type off_type;
+ using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type; // Since C++26
basic_fstream();
explicit basic_fstream(const char* s, ios_base::openmode mode = ios_base::in|ios_base::out);
@@ -160,6 +166,7 @@ public:
void swap(basic_fstream& rhs);
basic_filebuf<char_type, traits_type>* rdbuf() const;
+ native_handle_type native_handle() const noexcept; // Since C++26
bool is_open() const;
void open(const char* s, ios_base::openmode mode = ios_base::in|ios_base::out);
void open(const string& s, ios_base::openmode mode = ios_base::in|ios_base::out);
@@ -219,6 +226,13 @@ public:
typedef typename traits_type::pos_type pos_type;
typedef typename traits_type::off_type off_type;
typedef typename traits_type::state_type state_type;
+# if _LIBCPP_STD_VER >= 26
+# if defined(_LIBCPP_WIN32API)
+ using native_handle_type = void*; // HANDLE
+# else
+ using native_handle_type = int; // POSIX file descriptor
+# endif
+# endif
// 27.9.1.2 Constructors/destructor:
basic_filebuf();
@@ -245,6 +259,9 @@ public:
# endif
_LIBCPP_HIDE_FROM_ABI basic_filebuf* __open(int __fd, ios_base::openmode __mode);
basic_filebuf* close();
+# if _LIBCPP_STD_VER >= 26
+ _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle();
+# endif
_LIBCPP_HIDE_FROM_ABI inline static const char* __make_mdstring(ios_base::openmode __mode) _NOEXCEPT;
@@ -1024,6 +1041,9 @@ public:
typedef typename traits_type::int_type int_type;
typedef typename traits_type::pos_type pos_type;
typedef typename traits_type::off_type off_type;
+# if _LIBCPP_STD_VER >= 26
+ using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type;
+# endif
_LIBCPP_HIDE_FROM_ABI basic_ifstream();
_LIBCPP_HIDE_FROM_ABI explicit basic_ifstream(const char* __s, ios_base::openmode __mode = ios_base::in);
@@ -1041,6 +1061,9 @@ public:
_LIBCPP_HIDE_FROM_ABI void swap(basic_ifstream& __rhs);
_LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const;
+# if _LIBCPP_STD_VER >= 26
+ _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); }
+# endif
_LIBCPP_HIDE_FROM_ABI bool is_open() const;
void open(const char* __s, ios_base::openmode __mode = ios_base::in);
# ifdef _LIBCPP_HAS_OPEN_WITH_WCHAR
@@ -1116,6 +1139,14 @@ inline basic_filebuf<_CharT, _Traits>* basic_ifstream<_CharT, _Traits>::rdbuf()
return const_cast<basic_filebuf<char_type, traits_type>*>(&__sb_);
}
+// # if _LIBCPP_STD_VER >= 26
+// template <class _CharT, class _Traits>
+// inline basic_filebuf<_CharT, _Traits>::native_handle_type
+// basic_ifstream<_CharT, _Traits>::native_handle() const noexcept {
+// return rdbuf()->native_handle();
+// }
+// # endif
+
template <class _CharT, class _Traits>
inline bool basic_ifstream<_CharT, _Traits>::is_open() const {
return __sb_.is_open();
@@ -1171,6 +1202,9 @@ public:
typedef typename traits_type::int_type int_type;
typedef typename traits_type::pos_type pos_type;
typedef typename traits_type::off_type off_type;
+# if _LIBCPP_STD_VER >= 26
+ using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type;
+# endif
_LIBCPP_HIDE_FROM_ABI basic_ofstream();
_LIBCPP_HIDE_FROM_ABI explicit basic_ofstream(const char* __s, ios_base::openmode __mode = ios_base::out);
@@ -1190,6 +1224,9 @@ public:
_LIBCPP_HIDE_FROM_ABI void swap(basic_ofstream& __rhs);
_LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const;
+# if _LIBCPP_STD_VER >= 26
+ _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); }
+# endif
_LIBCPP_HIDE_FROM_ABI bool is_open() const;
void open(const char* __s, ios_base::openmode __mode = ios_base::out);
# ifdef _LIBCPP_HAS_OPEN_WITH_WCHAR
@@ -1266,6 +1303,14 @@ inline basic_filebuf<_CharT, _Traits>* basic_ofstream<_CharT, _Traits>::rdbuf()
return const_cast<basic_filebuf<char_type, traits_type>*>(&__sb_);
}
+// # if _LIBCPP_STD_VER >= 26
+// template <class _CharT, class _Traits>
+// inline basic_filebuf<_CharT, _Traits>::native_handle_type
+// basic_ofstream<_CharT, _Traits>::native_handle() const noexcept {
+// return rdbuf()->native_handle();
+// }
+// # endif
+
template <class _CharT, class _Traits>
inline bool basic_ofstream<_CharT, _Traits>::is_open() const {
return __sb_.is_open();
@@ -1321,6 +1366,9 @@ public:
typedef typename traits_type::int_type int_type;
typedef typename traits_type::pos_type pos_type;
typedef typename traits_type::off_type off_type;
+# if _LIBCPP_STD_VER >= 26
+ using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type;
+# endif
_LIBCPP_HIDE_FROM_ABI basic_fstream();
_LIBCPP_HIDE_FROM_ABI explicit basic_fstream(const char* __s,
@@ -1345,6 +1393,9 @@ public:
_LIBCPP_HIDE_FROM_ABI void swap(basic_fstream& __rhs);
_LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const;
+# if _LIBCPP_STD_VER >= 26
+ _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); }
+# endif
_LIBCPP_HIDE_FROM_ABI bool is_open() const;
_LIBCPP_HIDE_FROM_ABI void open(const char* __s, ios_base::openmode __mode = ios_base::in | ios_base::out);
# ifdef _LIBCPP_HAS_OPEN_WITH_WCHAR
@@ -1420,6 +1471,14 @@ inline basic_filebuf<_CharT, _Traits>* basic_fstream<_CharT, _Traits>::rdbuf() c
return const_cast<basic_filebuf<char_type, traits_type>*>(&__sb_);
}
+// # if _LIBCPP_STD_VER >= 26
+// template <class _CharT, class _Traits>
+// inline basic_filebuf<_CharT, _Traits>::native_handle_type
+// basic_fstream<_CharT, _Traits>::native_handle() const noexcept {
+// return rdbuf()->native_handle();
+// }
+// # endif
+
template <class _CharT, class _Traits>
inline bool basic_fstream<_CharT, _Traits>::is_open() const {
return __sb_.is_open();
diff --git a/libcxx/include/version b/libcxx/include/version
index 768710ef5c84aa..a2bb11b62a44d3 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -495,7 +495,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
// # define __cpp_lib_freestanding_optional 202311L
// # define __cpp_lib_freestanding_string_view 202311L
// # define __cpp_lib_freestanding_variant 202311L
-// # define __cpp_lib_fstream_native_handle 202306L
+# define __cpp_lib_fstream_native_handle 202306L
// # define __cpp_lib_function_ref 202306L
// # define __cpp_lib_hazard_pointer 202306L
// # define __cpp_lib_linalg 202311L
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index 329964a001363b..b931460ec76297 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -14,6 +14,7 @@ set(LIBCXX_SOURCES
filesystem/filesystem_error.cpp
filesystem/path_parser.h
filesystem/path.cpp
+ fstream.cpp
functional.cpp
hash.cpp
include/apple_availability.h
diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
new file mode 100644
index 00000000000000..c680ff638fe7e5
--- /dev/null
+++ b/libcxx/src/fstream.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <__config>
+#include <cassert>
+#include <cstdio>
+#include <fstream>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 26
+template <class _CharT, class _Traits>
+basic_filebuf<_CharT, _Traits>::native_handle_type basic_filebuf<_CharT, _Traits>::native_handle() {
+ assert(is_open());
+ // __file_ is a FILE*
+# if defined(_LIBCPP_WIN32API)
+ // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
+ intptr_t __handle = _get_osfhandle(::fileno(__file_));
+ if (__handle == -1)
+ return nullptr;
+ return reinterpret_cast<void*>(__handle);
+# else
+ return ::fileno(__file_);
+# endif
+}
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/fstream.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/fstream.version.compile.pass.cpp
index 981f5420ff7e0f..eab0313b2c1ef7 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/fstream.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/fstream.version.compile.pass.cpp
@@ -56,17 +56,11 @@
#elif TEST_STD_VER > 23
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_fstream_native_handle
-# error "__cpp_lib_fstream_native_handle should be defined in c++26"
-# endif
-# if __cpp_lib_fstream_native_handle != 202306L
-# error "__cpp_lib_fstream_native_handle should have the value 202306L in c++26"
-# endif
-# else // _LIBCPP_VERSION
-# ifdef __cpp_lib_fstream_native_handle
-# error "__cpp_lib_fstream_native_handle should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_fstream_native_handle
+# error "__cpp_lib_fstream_native_handle should be defined in c++26"
+# endif
+# if __cpp_lib_fstream_native_handle != 202306L
+# error "__cpp_lib_fstream_native_handle should have the value 202306L in c++26"
# endif
#endif // TEST_STD_VER > 23
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 650a14b019ed87..af7037a1392fbf 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -6490,17 +6490,11 @@
# endif
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_fstream_native_handle
-# error "__cpp_lib_fstream_native_handle should be defined in c++26"
-# endif
-# if __cpp_lib_fstream_native_handle != 202306L
-# error "__cpp_lib_fstream_native_handle should have the value 202306L in c++26"
-# endif
-# else // _LIBCPP_VERSION
-# ifdef __cpp_lib_fstream_native_handle
-# error "__cpp_lib_fstream_native_handle should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_fstream_native_handle
+# error "__cpp_lib_fstream_native_handle should be defined in c++26"
+# endif
+# if __cpp_lib_fstream_native_handle != 202306L
+# error "__cpp_lib_fstream_native_handle should have the value 202306L in c++26"
# endif
# if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 2f506f32f565cb..cb7c532c05251f 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -570,7 +570,6 @@ def add_version_header(tc):
"name": "__cpp_lib_fstream_native_handle",
"values": {"c++26": 202306}, # P1759R6 Native handles and file streams
"headers": ["fstream"],
- "unimplemented": True,
},
{
"name": "__cpp_lib_function_ref",
>From 9d4b10e4739c44e867ae40dc942fc6577212d94e Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sat, 30 Dec 2023 22:28:46 +0200
Subject: [PATCH 2/7] Added tests
---
libcxx/include/fstream | 70 ++++++++++---------
libcxx/src/fstream.cpp | 17 +++--
.../filebuf.members/native_handle.pass.cpp | 52 ++++++++++++++
.../fstream.members/native_handle.pass.cpp | 57 +++++++++++++++
.../ifstream.members/native_handle.pass.cpp | 57 +++++++++++++++
.../ofstream.members/native_handle.pass.cpp | 59 ++++++++++++++++
.../file.streams/fstreams/test_helpers.h | 33 +++++++++
7 files changed, 305 insertions(+), 40 deletions(-)
create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 9609ff420220fa..f0cb5bb50fc9b6 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -215,8 +215,37 @@ _LIBCPP_PUSH_MACROS
#if !defined(_LIBCPP_HAS_NO_FILESYSTEM)
+# if defined(_LIBCPP_WIN32API)
+# define WIN32_LEAN_AND_MEAN
+# define NOMINMAX
+# include <io.h>
+# include <windows.h>
+# endif
+
+#include <fcntl.h>
+
_LIBCPP_BEGIN_NAMESPACE_STD
+# if _LIBCPP_STD_VER >= 26
+# if defined(_LIBCPP_WIN32API)
+using __filebuf_native_handle_type = void*; // HANDLE
+# else
+using __filebuf_native_handle_type = int; // POSIX file descriptor
+# endif
+_LIBCPP_HIDE_FROM_ABI __filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept;
+__filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept {
+# if defined(_LIBCPP_WIN32API)
+ // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
+ intptr_t __handle = _get_osfhandle(::fileno(__file));
+ if (__handle == -1)
+ return nullptr;
+ return reinterpret_cast<void*>(__handle);
+# else
+ return ::fileno(__file);
+# endif
+}
+# endif
+
template <class _CharT, class _Traits>
class _LIBCPP_TEMPLATE_VIS basic_filebuf : public basic_streambuf<_CharT, _Traits> {
public:
@@ -227,11 +256,7 @@ public:
typedef typename traits_type::off_type off_type;
typedef typename traits_type::state_type state_type;
# if _LIBCPP_STD_VER >= 26
-# if defined(_LIBCPP_WIN32API)
- using native_handle_type = void*; // HANDLE
-# else
- using native_handle_type = int; // POSIX file descriptor
-# endif
+ using native_handle_type = __filebuf_native_handle_type;
# endif
// 27.9.1.2 Constructors/destructor:
@@ -260,7 +285,10 @@ public:
_LIBCPP_HIDE_FROM_ABI basic_filebuf* __open(int __fd, ios_base::openmode __mode);
basic_filebuf* close();
# if _LIBCPP_STD_VER >= 26
- _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle();
+ _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept {
+ assert(is_open());
+ return std::__filebuf_native_handle(__file_);
+ }
# endif
_LIBCPP_HIDE_FROM_ABI inline static const char* __make_mdstring(ios_base::openmode __mode) _NOEXCEPT;
@@ -1042,7 +1070,7 @@ public:
typedef typename traits_type::pos_type pos_type;
typedef typename traits_type::off_type off_type;
# if _LIBCPP_STD_VER >= 26
- using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type;
+ using native_handle_type = typename basic_filebuf<_CharT, _Traits>::native_handle_type;
# endif
_LIBCPP_HIDE_FROM_ABI basic_ifstream();
@@ -1139,14 +1167,6 @@ inline basic_filebuf<_CharT, _Traits>* basic_ifstream<_CharT, _Traits>::rdbuf()
return const_cast<basic_filebuf<char_type, traits_type>*>(&__sb_);
}
-// # if _LIBCPP_STD_VER >= 26
-// template <class _CharT, class _Traits>
-// inline basic_filebuf<_CharT, _Traits>::native_handle_type
-// basic_ifstream<_CharT, _Traits>::native_handle() const noexcept {
-// return rdbuf()->native_handle();
-// }
-// # endif
-
template <class _CharT, class _Traits>
inline bool basic_ifstream<_CharT, _Traits>::is_open() const {
return __sb_.is_open();
@@ -1203,7 +1223,7 @@ public:
typedef typename traits_type::pos_type pos_type;
typedef typename traits_type::off_type off_type;
# if _LIBCPP_STD_VER >= 26
- using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type;
+ using native_handle_type = typename basic_filebuf<_CharT, _Traits>::native_handle_type;
# endif
_LIBCPP_HIDE_FROM_ABI basic_ofstream();
@@ -1303,14 +1323,6 @@ inline basic_filebuf<_CharT, _Traits>* basic_ofstream<_CharT, _Traits>::rdbuf()
return const_cast<basic_filebuf<char_type, traits_type>*>(&__sb_);
}
-// # if _LIBCPP_STD_VER >= 26
-// template <class _CharT, class _Traits>
-// inline basic_filebuf<_CharT, _Traits>::native_handle_type
-// basic_ofstream<_CharT, _Traits>::native_handle() const noexcept {
-// return rdbuf()->native_handle();
-// }
-// # endif
-
template <class _CharT, class _Traits>
inline bool basic_ofstream<_CharT, _Traits>::is_open() const {
return __sb_.is_open();
@@ -1367,7 +1379,7 @@ public:
typedef typename traits_type::pos_type pos_type;
typedef typename traits_type::off_type off_type;
# if _LIBCPP_STD_VER >= 26
- using native_handle_type = typename basic_filebuf<charT, traits>::native_handle_type;
+ using native_handle_type = typename basic_filebuf<_CharT, _Traits>::native_handle_type;
# endif
_LIBCPP_HIDE_FROM_ABI basic_fstream();
@@ -1471,14 +1483,6 @@ inline basic_filebuf<_CharT, _Traits>* basic_fstream<_CharT, _Traits>::rdbuf() c
return const_cast<basic_filebuf<char_type, traits_type>*>(&__sb_);
}
-// # if _LIBCPP_STD_VER >= 26
-// template <class _CharT, class _Traits>
-// inline basic_filebuf<_CharT, _Traits>::native_handle_type
-// basic_fstream<_CharT, _Traits>::native_handle() const noexcept {
-// return rdbuf()->native_handle();
-// }
-// # endif
-
template <class _CharT, class _Traits>
inline bool basic_fstream<_CharT, _Traits>::is_open() const {
return __sb_.is_open();
diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
index c680ff638fe7e5..e5611e2d48b0a6 100644
--- a/libcxx/src/fstream.cpp
+++ b/libcxx/src/fstream.cpp
@@ -7,25 +7,28 @@
//===----------------------------------------------------------------------===//
#include <__config>
-#include <cassert>
#include <cstdio>
#include <fstream>
+#if defined(_LIBCPP_WIN32API)
+# define WIN32_LEAN_AND_MEAN
+# define NOMINMAX
+# include <io.h>
+# include <windows.h>
+#endif
+
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 26
-template <class _CharT, class _Traits>
-basic_filebuf<_CharT, _Traits>::native_handle_type basic_filebuf<_CharT, _Traits>::native_handle() {
- assert(is_open());
- // __file_ is a FILE*
+_LIBCPP_EXPORTED_FROM_ABI __filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept {
# if defined(_LIBCPP_WIN32API)
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
- intptr_t __handle = _get_osfhandle(::fileno(__file_));
+ intptr_t __handle = _get_osfhandle(::fileno(__file));
if (__handle == -1)
return nullptr;
return reinterpret_cast<void*>(__handle);
# else
- return ::fileno(__file_);
+ return ::fileno(__file);
# endif
}
#endif
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
new file mode 100644
index 00000000000000..4104aa061e1546
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <fstream>
+
+// class basic_filebuf;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <cassert>
+#include <fstream>
+#include <filesystem>
+#include <utility>
+
+#if defined(_LIBCPP_WIN32API)
+# define WIN32_LEAN_AND_MEAN
+# define NOMINMAX
+# include <io.h>
+# include <windows.h>
+#endif
+
+#include "platform_support.h"
+#include "test_macros.h"
+#include "../test_helpers.h"
+
+template <typename CharT>
+void test() {
+ std::basic_filebuf<CharT> f;
+ assert(!f.is_open());
+ std::filesystem::path p = get_temp_file_name();
+ f.open(p, std::ios_base::in);
+ assert(f.is_open());
+ assert(is_handle_valid(f.native_handle()));
+ assert(is_handle_valid(std::as_const(f).native_handle()));
+ static_assert(noexcept(f.native_handle()));
+}
+
+int main(int, char**) {
+ test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
new file mode 100644
index 00000000000000..44da8bd3e18bad
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <fstream>
+
+// class basic_fstream;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <cassert>
+#include <fstream>
+#include <filesystem>
+#include <utility>
+
+#if defined(_LIBCPP_WIN32API)
+# define WIN32_LEAN_AND_MEAN
+# define NOMINMAX
+# include <io.h>
+# include <windows.h>
+#endif
+
+#include "platform_support.h"
+#include "test_macros.h"
+#include "../test_helpers.h"
+
+template <typename CharT>
+void test() {
+ static_assert(std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type,
+ typename std::basic_fstream<CharT>::native_handle_type>);
+
+ std::basic_fstream<CharT> f;
+ static_assert(noexcept(f.native_handle()));
+ assert(!f.is_open());
+ std::filesystem::path p = get_temp_file_name();
+ f.open(p);
+ assert(f.is_open());
+ assert(f.native_handle() == f.rdbuf()->native_handle());
+ assert(is_handle_valid(f.native_handle()));
+ assert(is_handle_valid(std::as_const(f).native_handle()));
+ static_assert(noexcept(f.native_handle()));
+}
+
+int main(int, char**) {
+ test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
new file mode 100644
index 00000000000000..1345b72b158e28
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <fstream>
+
+// class basic_ifstream;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <cassert>
+#include <fstream>
+#include <filesystem>
+#include <utility>
+
+#if defined(_LIBCPP_WIN32API)
+# define WIN32_LEAN_AND_MEAN
+# define NOMINMAX
+# include <io.h>
+# include <windows.h>
+#endif
+
+#include "platform_support.h"
+#include "test_macros.h"
+#include "../test_helpers.h"
+
+template <typename CharT>
+void test() {
+ static_assert(std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type,
+ typename std::basic_ifstream<CharT>::native_handle_type>);
+
+ std::basic_ifstream<CharT> f;
+ static_assert(noexcept(f.native_handle()));
+ assert(!f.is_open());
+ std::filesystem::path p = get_temp_file_name();
+ f.open(p);
+ assert(f.is_open());
+ assert(f.native_handle() == f.rdbuf()->native_handle());
+ assert(is_handle_valid(f.native_handle()));
+ assert(is_handle_valid(std::as_const(f).native_handle()));
+ static_assert(noexcept(f.native_handle()));
+}
+
+int main(int, char**) {
+ test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
new file mode 100644
index 00000000000000..cd69c8087608df
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+// <fstream>
+
+// class basic_ofstream;
+
+// native_handle_type native_handle() const noexcept;
+
+#include <cassert>
+#include <fstream>
+#include <filesystem>
+#include <utility>
+
+#if defined(_LIBCPP_WIN32API)
+# define WIN32_LEAN_AND_MEAN
+# define NOMINMAX
+# include <io.h>
+# include <windows.h>
+#endif
+
+#include "platform_support.h"
+#include "test_macros.h"
+#include "../test_helpers.h"
+
+template <typename CharT>
+void test() {
+ static_assert(std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type,
+ typename std::basic_ofstream<CharT>::native_handle_type>);
+
+ std::basic_ofstream<CharT> f;
+ static_assert(noexcept(f.native_handle()));
+ assert(!f.is_open());
+ std::filesystem::path p = get_temp_file_name();
+ f.open(p);
+ assert(f.is_open());
+ assert(f.native_handle() == f.rdbuf()->native_handle());
+ assert(f.native_handle());
+ assert(std::as_const(f).native_handle());
+ assert(is_handle_valid(f.native_handle()));
+ assert(is_handle_valid(std::as_const(f).native_handle()));
+ static_assert(noexcept(f.native_handle()));
+}
+
+int main(int, char**) {
+ test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
new file mode 100644
index 00000000000000..06ddbf8287f039
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
+#define TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
+
+#include <cstdio>
+
+#if defined(_LIBCPP_WIN32API)
+# define WIN32_LEAN_AND_MEAN
+# define NOMINMAX
+# include <io.h>
+# include <windows.h>
+#else
+# include <fcntl.h>
+#endif
+
+#if defined(_LIBCPP_WIN32API)
+auto is_handle_valid([[maybe_unused]] HANDLE handle) {
+ // TODO: GetFileInformationByHandle
+ return true;
+};
+#else
+// POSIX
+auto is_handle_valid(int fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
+#endif
+
+#endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
\ No newline at end of file
>From 37a871ace443c45dae2c048a91de712a1c369fe4 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 11:25:48 +0200
Subject: [PATCH 3/7] Added missing include
---
libcxx/include/fstream | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index f0cb5bb50fc9b6..5598943268276d 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -195,6 +195,7 @@ typedef basic_fstream<wchar_t> wfstream;
#include <__utility/move.h>
#include <__utility/swap.h>
#include <__utility/unreachable.h>
+#include <cassert>
#include <cstdio>
#include <filesystem>
#include <istream>
>From 5aeb33918bd80840469cec803ba054f1f4aeec8e Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 14:38:06 +0200
Subject: [PATCH 4/7] WIP: Addressed some comments and simplified/generalized
the tests
---
libcxx/include/fstream | 22 +++-----
libcxx/src/fstream.cpp | 9 +--
.../fstream.members/native_handle.pass.cpp | 34 +-----------
.../ifstream.members/native_handle.pass.cpp | 35 +-----------
.../ofstream.members/native_handle.pass.cpp | 36 +-----------
.../file.streams/fstreams/test_helpers.h | 55 ++++++++++++++-----
6 files changed, 60 insertions(+), 131 deletions(-)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 5598943268276d..ab854cf534e7fb 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -195,7 +195,6 @@ typedef basic_fstream<wchar_t> wfstream;
#include <__utility/move.h>
#include <__utility/swap.h>
#include <__utility/unreachable.h>
-#include <cassert>
#include <cstdio>
#include <filesystem>
#include <istream>
@@ -223,24 +222,21 @@ _LIBCPP_PUSH_MACROS
# include <windows.h>
# endif
-#include <fcntl.h>
+// # include <fcntl.h>
_LIBCPP_BEGIN_NAMESPACE_STD
# if _LIBCPP_STD_VER >= 26
# if defined(_LIBCPP_WIN32API)
-using __filebuf_native_handle_type = void*; // HANDLE
-# else
-using __filebuf_native_handle_type = int; // POSIX file descriptor
+using __filebuf_native_handle_type = HANDLE;
+_LIBCPP_EXPORTED_FROM_ABI __filebuf_native_handle_type __filebuf_windows_native_handle(FILE* __file);
+# else // POSIX
+using __filebuf_native_handle_type = int; // File descriptor
# endif
-_LIBCPP_HIDE_FROM_ABI __filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept;
-__filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept {
+
+_LIBCPP_HIDE_FROM_ABI inline __filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept {
# if defined(_LIBCPP_WIN32API)
- // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
- intptr_t __handle = _get_osfhandle(::fileno(__file));
- if (__handle == -1)
- return nullptr;
- return reinterpret_cast<void*>(__handle);
+ return __filebuf_windows_native_handle(__file);
# else
return ::fileno(__file);
# endif
@@ -287,7 +283,7 @@ public:
basic_filebuf* close();
# if _LIBCPP_STD_VER >= 26
_LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept {
- assert(is_open());
+ _LIBCPP_ASSERT_UNCATEGORIZED(this->is_open(), "File must be opened");
return std::__filebuf_native_handle(__file_);
}
# endif
diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
index e5611e2d48b0a6..814d912e7d22b3 100644
--- a/libcxx/src/fstream.cpp
+++ b/libcxx/src/fstream.cpp
@@ -20,17 +20,14 @@
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 26
-_LIBCPP_EXPORTED_FROM_ABI __filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept {
# if defined(_LIBCPP_WIN32API)
+_LIBCPP_EXPORTED_FROM_ABI __filebuf_native_handle_type __filebuf_windows_native_handle(FILE* __file) noexcept {
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
intptr_t __handle = _get_osfhandle(::fileno(__file));
if (__handle == -1)
return nullptr;
- return reinterpret_cast<void*>(__handle);
-# else
- return ::fileno(__file);
+ return reinterpret_cast<__filebuf_native_handle_type>(__handle);
# endif
-}
#endif
-_LIBCPP_END_NAMESPACE_STD
+ _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
index 44da8bd3e18bad..900475069a1c9b 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/fstream.members/native_handle.pass.cpp
@@ -14,43 +14,13 @@
// native_handle_type native_handle() const noexcept;
-#include <cassert>
-#include <fstream>
-#include <filesystem>
-#include <utility>
-
-#if defined(_LIBCPP_WIN32API)
-# define WIN32_LEAN_AND_MEAN
-# define NOMINMAX
-# include <io.h>
-# include <windows.h>
-#endif
-
-#include "platform_support.h"
#include "test_macros.h"
#include "../test_helpers.h"
-template <typename CharT>
-void test() {
- static_assert(std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type,
- typename std::basic_fstream<CharT>::native_handle_type>);
-
- std::basic_fstream<CharT> f;
- static_assert(noexcept(f.native_handle()));
- assert(!f.is_open());
- std::filesystem::path p = get_temp_file_name();
- f.open(p);
- assert(f.is_open());
- assert(f.native_handle() == f.rdbuf()->native_handle());
- assert(is_handle_valid(f.native_handle()));
- assert(is_handle_valid(std::as_const(f).native_handle()));
- static_assert(noexcept(f.native_handle()));
-}
-
int main(int, char**) {
- test<char>();
+ test_native_handle<char, std::basic_fstream<char>>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- test<wchar_t>();
+ test_native_handle<wchar_t, std::basic_fstream<wchar_t>>();
#endif
return 0;
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
index 1345b72b158e28..ffe5e922225da8 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
@@ -14,44 +14,15 @@
// native_handle_type native_handle() const noexcept;
-#include <cassert>
-#include <fstream>
-#include <filesystem>
-#include <utility>
-
-#if defined(_LIBCPP_WIN32API)
-# define WIN32_LEAN_AND_MEAN
-# define NOMINMAX
-# include <io.h>
-# include <windows.h>
-#endif
-
-#include "platform_support.h"
#include "test_macros.h"
#include "../test_helpers.h"
-template <typename CharT>
-void test() {
- static_assert(std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type,
- typename std::basic_ifstream<CharT>::native_handle_type>);
-
- std::basic_ifstream<CharT> f;
- static_assert(noexcept(f.native_handle()));
- assert(!f.is_open());
- std::filesystem::path p = get_temp_file_name();
- f.open(p);
- assert(f.is_open());
- assert(f.native_handle() == f.rdbuf()->native_handle());
- assert(is_handle_valid(f.native_handle()));
- assert(is_handle_valid(std::as_const(f).native_handle()));
- static_assert(noexcept(f.native_handle()));
-}
-
int main(int, char**) {
- test<char>();
+ test_native_handle<char, std::basic_ifstream<char>>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- test<wchar_t>();
+ test_native_handle<wchar_t, std::basic_ifstream<wchar_t>>();
#endif
return 0;
}
+
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
index cd69c8087608df..45f0841dad18cb 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ofstream.members/native_handle.pass.cpp
@@ -14,45 +14,13 @@
// native_handle_type native_handle() const noexcept;
-#include <cassert>
-#include <fstream>
-#include <filesystem>
-#include <utility>
-
-#if defined(_LIBCPP_WIN32API)
-# define WIN32_LEAN_AND_MEAN
-# define NOMINMAX
-# include <io.h>
-# include <windows.h>
-#endif
-
-#include "platform_support.h"
#include "test_macros.h"
#include "../test_helpers.h"
-template <typename CharT>
-void test() {
- static_assert(std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type,
- typename std::basic_ofstream<CharT>::native_handle_type>);
-
- std::basic_ofstream<CharT> f;
- static_assert(noexcept(f.native_handle()));
- assert(!f.is_open());
- std::filesystem::path p = get_temp_file_name();
- f.open(p);
- assert(f.is_open());
- assert(f.native_handle() == f.rdbuf()->native_handle());
- assert(f.native_handle());
- assert(std::as_const(f).native_handle());
- assert(is_handle_valid(f.native_handle()));
- assert(is_handle_valid(std::as_const(f).native_handle()));
- static_assert(noexcept(f.native_handle()));
-}
-
int main(int, char**) {
- test<char>();
+ test_native_handle<char, std::basic_ofstream<char>>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- test<wchar_t>();
+ test_native_handle<wchar_t, std::basic_ofstream<wchar_t>>();
#endif
return 0;
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index 06ddbf8287f039..7691c04c750448 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -9,25 +9,52 @@
#ifndef TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
#define TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
-#include <cstdio>
-
-#if defined(_LIBCPP_WIN32API)
-# define WIN32_LEAN_AND_MEAN
-# define NOMINMAX
-# include <io.h>
-# include <windows.h>
-#else
-# include <fcntl.h>
-#endif
-
-#if defined(_LIBCPP_WIN32API)
+#if _LIBCPP_STD_VER >= 26
+
+# include <cassert>
+# include <cstdio>
+# include <fstream>
+# include <filesystem>
+# include <utility>
+
+# if defined(_LIBCPP_WIN32API)
+# define WIN32_LEAN_AND_MEAN
+# define NOMINMAX
+# include <io.h>
+# include <windows.h>
+# else
+# include <fcntl.h>
+# endif
+
+# include "platform_support.h"
+
+# if defined(_LIBCPP_WIN32API)
auto is_handle_valid([[maybe_unused]] HANDLE handle) {
// TODO: GetFileInformationByHandle
return true;
};
-#else
+# else
// POSIX
auto is_handle_valid(int fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
-#endif
+# endif
+
+template <typename CharT, typename StreamT>
+void test_native_handle() {
+ static_assert(
+ std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type, typename StreamT::native_handle_type>);
+
+ StreamT f;
+ static_assert(noexcept(f.native_handle()));
+ assert(!f.is_open());
+ std::filesystem::path p = get_temp_file_name();
+ f.open(p);
+ assert(f.is_open());
+ assert(f.native_handle() == f.rdbuf()->native_handle());
+ assert(is_handle_valid(f.native_handle()));
+ assert(is_handle_valid(std::as_const(f).native_handle()));
+ static_assert(noexcept(f.native_handle()));
+}
+
+#endif // _LIBCPP_STD_VER >= 26
#endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
\ No newline at end of file
>From 822633dd56bf65b25a265aafb3c16b7e1f071bb4 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 14:48:56 +0200
Subject: [PATCH 5/7] WIP: Fixed formatting error
---
.../fstreams/filebuf.members/native_handle.pass.cpp | 7 -------
.../fstreams/ifstream.members/native_handle.pass.cpp | 1 -
.../std/input.output/file.streams/fstreams/test_helpers.h | 4 ++--
3 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
index 4104aa061e1546..790cc91effc822 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
@@ -19,13 +19,6 @@
#include <filesystem>
#include <utility>
-#if defined(_LIBCPP_WIN32API)
-# define WIN32_LEAN_AND_MEAN
-# define NOMINMAX
-# include <io.h>
-# include <windows.h>
-#endif
-
#include "platform_support.h"
#include "test_macros.h"
#include "../test_helpers.h"
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
index ffe5e922225da8..95a95cb69560b7 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/native_handle.pass.cpp
@@ -25,4 +25,3 @@ int main(int, char**) {
return 0;
}
-
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index 7691c04c750448..a3069549315611 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -30,7 +30,7 @@
# if defined(_LIBCPP_WIN32API)
auto is_handle_valid([[maybe_unused]] HANDLE handle) {
- // TODO: GetFileInformationByHandle
+ // TODO: Maybe test HANDLE with GetFileInformationByHandle??
return true;
};
# else
@@ -57,4 +57,4 @@ void test_native_handle() {
#endif // _LIBCPP_STD_VER >= 26
-#endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
\ No newline at end of file
+#endif // TEST_STD_INPUT_OUTPUT_FILE_STREAMS_FSTREAMS_TEST_HELPERS_H
>From ecaf77e4da4fa56db9a07b738bcc0b75fa2b7b5a Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Sun, 31 Dec 2023 15:18:13 +0200
Subject: [PATCH 6/7] WIP: Refactored `fstream->native_handle()` implementation
---
libcxx/include/fstream | 38 ++++++++-----------
libcxx/src/fstream.cpp | 4 +-
.../file.streams/fstreams/test_helpers.h | 7 ++--
3 files changed, 20 insertions(+), 29 deletions(-)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index ab854cf534e7fb..6f6e36f259f381 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -215,32 +215,12 @@ _LIBCPP_PUSH_MACROS
#if !defined(_LIBCPP_HAS_NO_FILESYSTEM)
-# if defined(_LIBCPP_WIN32API)
-# define WIN32_LEAN_AND_MEAN
-# define NOMINMAX
-# include <io.h>
-# include <windows.h>
-# endif
-
-// # include <fcntl.h>
-
_LIBCPP_BEGIN_NAMESPACE_STD
# if _LIBCPP_STD_VER >= 26
# if defined(_LIBCPP_WIN32API)
-using __filebuf_native_handle_type = HANDLE;
-_LIBCPP_EXPORTED_FROM_ABI __filebuf_native_handle_type __filebuf_windows_native_handle(FILE* __file);
-# else // POSIX
-using __filebuf_native_handle_type = int; // File descriptor
-# endif
-
-_LIBCPP_HIDE_FROM_ABI inline __filebuf_native_handle_type __filebuf_native_handle(FILE* __file) noexcept {
-# if defined(_LIBCPP_WIN32API)
- return __filebuf_windows_native_handle(__file);
-# else
- return ::fileno(__file);
+_LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file);
# endif
-}
# endif
template <class _CharT, class _Traits>
@@ -253,7 +233,13 @@ public:
typedef typename traits_type::off_type off_type;
typedef typename traits_type::state_type state_type;
# if _LIBCPP_STD_VER >= 26
- using native_handle_type = __filebuf_native_handle_type;
+# if defined(_LIBCPP_WIN32API)
+ using native_handle_type = void*; // HANDLE
+# elif __has_include(<unistd.h>)
+ using native_handle_type = int; // POSIX file descriptor
+# else
+# error "Provide a file native handle!"
+# endif
# endif
// 27.9.1.2 Constructors/destructor:
@@ -284,7 +270,13 @@ public:
# if _LIBCPP_STD_VER >= 26
_LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept {
_LIBCPP_ASSERT_UNCATEGORIZED(this->is_open(), "File must be opened");
- return std::__filebuf_native_handle(__file_);
+# if defined(_LIBCPP_WIN32API)
+ return __filebuf_windows_native_handle(__file_);
+# elif __has_include(<unistd.h>)
+ return ::fileno(__file_);
+# else
+# error "Provide a way to determine the file native handle!
+# endif
}
# endif
diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
index 814d912e7d22b3..27150389627594 100644
--- a/libcxx/src/fstream.cpp
+++ b/libcxx/src/fstream.cpp
@@ -21,12 +21,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 26
# if defined(_LIBCPP_WIN32API)
-_LIBCPP_EXPORTED_FROM_ABI __filebuf_native_handle_type __filebuf_windows_native_handle(FILE* __file) noexcept {
+_LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file) noexcept {
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
intptr_t __handle = _get_osfhandle(::fileno(__file));
if (__handle == -1)
return nullptr;
- return reinterpret_cast<__filebuf_native_handle_type>(__handle);
+ return reinterpret_cast<void*>(__handle);
# endif
#endif
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index a3069549315611..fd6d732638ad32 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -29,13 +29,12 @@
# include "platform_support.h"
# if defined(_LIBCPP_WIN32API)
-auto is_handle_valid([[maybe_unused]] HANDLE handle) {
+bool is_handle_valid([[maybe_unused]] HANDLE handle) {
// TODO: Maybe test HANDLE with GetFileInformationByHandle??
return true;
};
-# else
-// POSIX
-auto is_handle_valid(int fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
+# else // POSIX
+bool is_handle_valid(int fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
# endif
template <typename CharT, typename StreamT>
>From a066b7957ee85e6c208e531c12b6adf96a8ef3f8 Mon Sep 17 00:00:00 2001
From: Zingam <zingam at outlook.com>
Date: Mon, 1 Jan 2024 09:17:09 +0200
Subject: [PATCH 7/7] Addressed comments
---
libcxx/include/fstream | 2 +-
libcxx/src/fstream.cpp | 9 ++++---
.../filebuf.members/native_handle.pass.cpp | 14 ++++++++--
.../file.streams/fstreams/test_helpers.h | 27 ++++++++++++++-----
4 files changed, 40 insertions(+), 12 deletions(-)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 6f6e36f259f381..287c4280f18e99 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -238,7 +238,7 @@ public:
# elif __has_include(<unistd.h>)
using native_handle_type = int; // POSIX file descriptor
# else
-# error "Provide a file native handle!"
+# error "Provide a native file handle!"
# endif
# endif
diff --git a/libcxx/src/fstream.cpp b/libcxx/src/fstream.cpp
index 27150389627594..f063b7020cb373 100644
--- a/libcxx/src/fstream.cpp
+++ b/libcxx/src/fstream.cpp
@@ -19,15 +19,18 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-#if _LIBCPP_STD_VER >= 26
-# if defined(_LIBCPP_WIN32API)
+#if defined(_LIBCPP_WIN32API)
+
+// Confirm that `HANDLE` is `void*`
+static_assert(std::same_as<HANDLE, void*>);
+
_LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file) noexcept {
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170
intptr_t __handle = _get_osfhandle(::fileno(__file));
if (__handle == -1)
return nullptr;
return reinterpret_cast<void*>(__handle);
-# endif
+
#endif
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
index 790cc91effc822..c87bda5382c85e 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.members/native_handle.pass.cpp
@@ -30,9 +30,19 @@ void test() {
std::filesystem::path p = get_temp_file_name();
f.open(p, std::ios_base::in);
assert(f.is_open());
- assert(is_handle_valid(f.native_handle()));
- assert(is_handle_valid(std::as_const(f).native_handle()));
+#if defined(_LIBCPP_WIN32API)
+ using HandleT = void*;
+#elif __has_include(<unistd.h>) // POSIX
+ using HandleT = int;
+#else
+# error "Provide a native file handle!"
+#endif
+ std::same_as<HandleT> decltype(auto) handle = f.native_handle();
+ assert(is_handle_valid(handle));
+ std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
+ assert(is_handle_valid(const_handle));
static_assert(noexcept(f.native_handle()));
+ static_assert(noexcept(std::as_const(f).native_handle()));
}
int main(int, char**) {
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
index fd6d732638ad32..e32c8fb5fc9de3 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
+++ b/libcxx/test/std/input.output/file.streams/fstreams/test_helpers.h
@@ -12,9 +12,11 @@
#if _LIBCPP_STD_VER >= 26
# include <cassert>
+# include <concepts>
# include <cstdio>
# include <fstream>
# include <filesystem>
+# include <type_traits>
# include <utility>
# if defined(_LIBCPP_WIN32API)
@@ -29,12 +31,15 @@
# include "platform_support.h"
# if defined(_LIBCPP_WIN32API)
-bool is_handle_valid([[maybe_unused]] HANDLE handle) {
- // TODO: Maybe test HANDLE with GetFileInformationByHandle??
+bool is_handle_valid([[void* handle) {
+ if (LPBY_HANDLE_FILE_INFORMATION & pFileInformation; !GetFileInformationByHandle(handle, &lpFileInformation))
+ return false;
return true;
};
-# else // POSIX
+# elif __has_include(<unistd.h>) // POSIX
bool is_handle_valid(int fd) { return fcntl(fd, F_GETFL) != -1 || errno != EBADF; };
+# else
+# error "Provide a native file handle!"
# endif
template <typename CharT, typename StreamT>
@@ -43,15 +48,25 @@ void test_native_handle() {
std::is_same_v<typename std::basic_filebuf<CharT>::native_handle_type, typename StreamT::native_handle_type>);
StreamT f;
- static_assert(noexcept(f.native_handle()));
+
assert(!f.is_open());
std::filesystem::path p = get_temp_file_name();
f.open(p);
assert(f.is_open());
assert(f.native_handle() == f.rdbuf()->native_handle());
- assert(is_handle_valid(f.native_handle()));
- assert(is_handle_valid(std::as_const(f).native_handle()));
+# if defined(_LIBCPP_WIN32API)
+ using HandleT = void*;
+# elif __has_include(<unistd.h>) // POSIX
+ using HandleT = int;
+# else
+# error "Provide a native file handle!"
+# endif
+ std::same_as<HandleT> decltype(auto) handle = f.native_handle();
+ assert(is_handle_valid(handle));
+ std::same_as<HandleT> decltype(auto) const_handle = std::as_const(f).native_handle();
+ assert(is_handle_valid(const_handle));
static_assert(noexcept(f.native_handle()));
+ static_assert(noexcept(std::as_const(f).native_handle()));
}
#endif // _LIBCPP_STD_VER >= 26
More information about the flang-commits
mailing list