99#include " ../../../fast_io_dsal/tuple.h"
1010#include " ../../../fast_io_core_impl/allocation/common.h"
1111
12- namespace fast_io ::win32::nt
12+ namespace fast_io
13+ {
14+ namespace win32 ::nt
1315{
1416
1517namespace details
1618{
1719
20+ template <typename Tuple>
1821class nt_thread_start_routine_tuple_allocate_guard
1922{
2023public:
2124 void *ptr_{nullptr };
2225
23- constexpr nt_thread_start_routine_tuple_allocate_guard () = default;
26+ inline constexpr nt_thread_start_routine_tuple_allocate_guard () = default;
2427
25- constexpr nt_thread_start_routine_tuple_allocate_guard (void *ptr) : ptr_{ptr}
28+ inline constexpr nt_thread_start_routine_tuple_allocate_guard (void *ptr)
29+ : ptr_{ptr}
2630 {}
2731
28- constexpr nt_thread_start_routine_tuple_allocate_guard (nt_thread_start_routine_tuple_allocate_guard const &) noexcept = delete;
29- constexpr nt_thread_start_routine_tuple_allocate_guard (nt_thread_start_routine_tuple_allocate_guard &&other) noexcept = default;
32+ inline constexpr nt_thread_start_routine_tuple_allocate_guard (nt_thread_start_routine_tuple_allocate_guard const &) noexcept = delete;
33+ inline constexpr nt_thread_start_routine_tuple_allocate_guard (nt_thread_start_routine_tuple_allocate_guard &&other) noexcept = default;
3034
31- constexpr ~nt_thread_start_routine_tuple_allocate_guard ()
35+ inline constexpr ~nt_thread_start_routine_tuple_allocate_guard ()
3236 {
3337 if (ptr_ != nullptr )
3438 {
39+ ::std::ranges::destroy_at (reinterpret_cast <Tuple *>(this ->ptr_));
3540 ::fast_io::generic_allocator_adapter<::fast_io::nt_rtlallocateheap_allocator>::deallocate (this ->ptr_ );
3641 }
3742 }
3843};
3944
4045template <typename Tuple, ::std::size_t ... Is>
41- constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine (void *args) noexcept (noexcept (
46+ inline constexpr ::std::uint_least32_t FAST_IO_WINSTDCALL thread_start_routine (void *args) noexcept (noexcept (
4247 ::std::invoke (::fast_io::get<Is>(*reinterpret_cast <Tuple *>(args))...)))
4348{
44- [[maybe_unused]] ::fast_io::win32::nt::details::nt_thread_start_routine_tuple_allocate_guard _ (args);
49+ [[maybe_unused]] ::fast_io::win32::nt::details::nt_thread_start_routine_tuple_allocate_guard<Tuple> _ (args);
4550 ::std::invoke (::fast_io::get<Is>(*reinterpret_cast <Tuple *>(args))...);
4651 return 0 ;
4752}
4853
4954template <typename Tuple, ::std::size_t ... Is>
50- constexpr auto get_thread_start_routine (::std::index_sequence<Is...>) noexcept
55+ inline constexpr auto get_thread_start_routine (::std::index_sequence<Is...>) noexcept
5156{
5257 return ::fast_io::win32::nt::details::thread_start_routine<Tuple, Is...>;
5358}
@@ -66,13 +71,13 @@ class nt_thread
6671 native_handle_type handle_{nullptr };
6772
6873public:
69- constexpr nt_thread () noexcept = default;
74+ inline constexpr nt_thread () noexcept = default;
7075
7176 template <typename Func, typename ... Args>
7277 requires (::std::invocable<Func, Args...>)
73- constexpr nt_thread (Func &&func, Args &&...args)
78+ inline constexpr nt_thread (Func &&func, Args &&...args)
7479 {
75- using start_routine_tuple_type = ::fast_io::tuple<decltype (func), decltype (args) ...>;
80+ using start_routine_tuple_type = ::fast_io::tuple<::std:: decay_t <Func>, ::std:: decay_t <Args> ...>;
7681#if __has_cpp_attribute(indeterminate)
7782 ::fast_io::win32::nt::client_id cid [[indeterminate]];
7883#else
@@ -107,11 +112,11 @@ class nt_thread
107112 this ->id_ = cid.UniqueThread ;
108113 }
109114
110- constexpr nt_thread (nt_thread const &) noexcept = delete;
115+ inline constexpr nt_thread (nt_thread const &) noexcept = delete;
111116
112- constexpr nt_thread (nt_thread &&other) noexcept = default;
117+ inline constexpr nt_thread (nt_thread &&other) noexcept = default;
113118
114- constexpr ~nt_thread () noexcept
119+ inline constexpr ~nt_thread () noexcept
115120 {
116121 if (handle_ != nullptr )
117122 {
@@ -127,9 +132,9 @@ class nt_thread
127132 }
128133 }
129134
130- constexpr nt_thread &operator =(nt_thread const &) noexcept = delete ;
135+ inline constexpr nt_thread &operator =(nt_thread const &) noexcept = delete ;
131136
132- constexpr nt_thread &operator =(nt_thread &&other) noexcept
137+ inline constexpr nt_thread &operator =(nt_thread &&other) noexcept
133138 {
134139 if (this == __builtin_addressof (other)) [[unlikely]]
135140 {
@@ -138,26 +143,26 @@ class nt_thread
138143 this ->swap (other);
139144 return *this ;
140145 }
141- constexpr bool joinable () const noexcept
146+ inline constexpr bool joinable () const noexcept
142147 {
143148 return this ->id_ != nullptr ;
144149 }
145150
146- constexpr void join ()
151+ inline constexpr void join ()
147152 {
148153 if (!this ->joinable ()) [[unlikely]]
149154 {
150155 ::fast_io::fast_terminate ();
151156 }
152- auto status{::fast_io::win32::nt::nt_wait_for_single_object<zw>(this ->handle_ , /* INFINITE = */ int ( 0xffffffff ) , nullptr )};
157+ auto status{::fast_io::win32::nt::nt_wait_for_single_object<zw>(this ->handle_ , false , nullptr )};
153158 if (status) [[unlikely]]
154159 {
155160 ::fast_io::throw_nt_error (status);
156161 }
157162 this ->id_ = nullptr ;
158163 }
159164
160- constexpr void detach ()
165+ inline constexpr void detach ()
161166 {
162167 if (!this ->joinable ()) [[unlikely]]
163168 {
@@ -172,20 +177,20 @@ class nt_thread
172177 this ->id_ = nullptr ;
173178 }
174179
175- constexpr void swap (nt_thread &other) noexcept
180+ inline constexpr void swap (nt_thread &other) noexcept
176181 {
177182 ::std::ranges::swap (handle_, other.handle_);
178183 ::std::ranges::swap (id_, other.id_);
179184 }
180185
181186 [[nodiscard]]
182- constexpr auto get_id () const noexcept
187+ inline constexpr auto get_id () const noexcept
183188 {
184189 return this ->id_ ;
185190 }
186191
187192 [[nodiscard]]
188- constexpr auto native_handle () const noexcept
193+ inline constexpr auto native_handle () const noexcept
189194 {
190195 return this ->handle_ ;
191196 }
@@ -194,13 +199,22 @@ class nt_thread
194199 * @brief Get the win32 id of the thread.
195200 * @note same as win32 GetCurrentThreadId
196201 */
197- constexpr ::std::uint_least32_t get_win32_id () const noexcept
202+ inline constexpr ::std::uint_least32_t get_win32_id () const noexcept
198203 {
199- auto peb = ::fast_io::win32::nt::nt_current_teb ();
200- return static_cast <::std::uint_least32_t >(reinterpret_cast <::std::size_t >(peb->ClientId .UniqueThread ));
204+ ::fast_io::win32::nt::thread_basic_information tbi; // no init
205+
206+ auto status{::fast_io::win32::nt::nt_query_information_thread<zw>(
207+ this ->handle_ , ::fast_io::win32::nt::thread_information_class::ThreadBasicInformation, __builtin_addressof (tbi), sizeof (tbi), nullptr )};
208+
209+ if (status) [[unlikely]]
210+ {
211+ ::fast_io::throw_nt_error (status);
212+ }
213+
214+ return reinterpret_cast <::std::uint_least32_t >(tbi.ClientId .UniqueThread );
201215 }
202216
203- static constexpr ::std::uint_least32_t hardware_concurrency ()
217+ inline static constexpr ::std::uint_least32_t hardware_concurrency ()
204218 {
205219 ::fast_io::win32::nt::system_basic_information sb{};
206220 auto status{::fast_io::win32::nt::nt_query_system_information<zw>(::fast_io::win32::nt::system_information_class::SystemBasicInformation,
@@ -217,7 +231,7 @@ namespace this_thread
217231{
218232
219233template <bool zw = false >
220- constexpr auto get_id () -> ::fast_io::win32::nt::nt_thread<zw>::id
234+ inline constexpr ::fast_io::win32::nt::nt_thread<zw>::id get_id ()
221235{
222236 ::fast_io::win32::nt::thread_basic_information tbi;
223237 ::std::uint_least32_t status{::fast_io::win32::nt::nt_query_information_thread<zw>(
@@ -233,10 +247,48 @@ constexpr auto get_id() -> ::fast_io::win32::nt::nt_thread<zw>::id
233247 return tbi.ClientId .UniqueThread ;
234248}
235249
250+ inline ::std::uint_least32_t get_win32_id () noexcept
251+ {
252+ auto teb{::fast_io::win32::nt::nt_current_teb ()};
253+ return static_cast <::std::uint_least32_t >(reinterpret_cast <::std::size_t >(teb->ClientId .UniqueThread ));
254+ }
255+
236256template <bool zw = false , typename Rep, typename Period>
237- constexpr void sleep_for (::std::chrono::duration<Rep, Period> const &sleep_duration)
257+ inline constexpr void sleep_for (::std::chrono::duration<Rep, Period> const &sleep_duration)
238258{
239- auto val = -static_cast <::std::int_least64_t >(::std::chrono::duration_cast<::std::chrono::microseconds>(sleep_duration).count () * 10 );
259+ auto const count{
260+ ::std::chrono::duration_cast<::std::chrono::microseconds>(sleep_duration).count () * 10u +
261+ ::std::chrono::duration_cast<::std::chrono::nanoseconds>(sleep_duration).count () / 100u % 10u };
262+
263+ if (count > static_cast <::std::uint_least64_t >(::std::numeric_limits<::std::int_least64_t >::max ()))
264+ {
265+ ::fast_io::throw_nt_error (0xC000000D );
266+ }
267+
268+ auto val{-static_cast <::std::int_least64_t >(count)};
269+ ::std::uint_least32_t status{::fast_io::win32::nt::nt_delay_execution<zw>(false , __builtin_addressof (val))};
270+ if (status) [[unlikely]]
271+ {
272+ ::fast_io::throw_nt_error (status);
273+ }
274+ }
275+
276+ template <bool zw = false , ::std::int_least64_t off_to_epoch>
277+ inline constexpr void sleep_for (::fast_io::basic_timestamp<off_to_epoch> const &sleep_duration)
278+ {
279+ if (sleep_duration.seconds < 0 ) [[unlikely]]
280+ {
281+ ::fast_io::throw_nt_error (0xC000000D );
282+ }
283+
284+ auto const win_100ns_seconds{static_cast <::std::uint_least64_t >(static_cast <::std::uint_least64_t >(sleep_duration.seconds ) * 10'000'000u + sleep_duration.subseconds / 100u )};
285+
286+ if (win_100ns_seconds > static_cast <::std::uint_least64_t >(::std::numeric_limits<::std::int_least64_t >::max ())) [[unlikely]]
287+ {
288+ ::fast_io::throw_nt_error (0xC000000D );
289+ }
290+
291+ auto val = -static_cast <::std::int_least64_t >(win_100ns_seconds);
240292 ::std::uint_least32_t status{::fast_io::win32::nt::nt_delay_execution<zw>(false , __builtin_addressof (val))};
241293 if (status) [[unlikely]]
242294 {
@@ -245,19 +297,78 @@ constexpr void sleep_for(::std::chrono::duration<Rep, Period> const &sleep_durat
245297}
246298
247299template <bool zw = false , typename Clock, typename Duration>
248- constexpr void sleep_until (::std::chrono::time_point<Clock, Duration> const &expect_time)
300+ inline constexpr void sleep_until (::std::chrono::time_point<Clock, Duration> const &expect_time)
249301{
250302 auto const unix_ts = ::std::chrono::duration_cast<std::chrono::seconds>(
251- expect_time.time_since_epoch ())
252- .count ();
253- auto nt_ts = (unix_ts + 11644473600 ) * 10000000 ;
303+ expect_time.time_since_epoch ())
304+ .count ();
305+ auto const unix_subsec_ts = ::std::chrono::duration_cast<std::chrono::nanoseconds>(
306+ expect_time.time_since_epoch ())
307+ .count () /
308+ 100u % 10000000u ;
309+
310+ auto const unix_to_nt_secs{static_cast <::std::int_least64_t >(unix_ts) + 11644473600 };
311+ if (unix_to_nt_secs < 0 ) [[unlikely]]
312+ {
313+ ::fast_io::throw_nt_error (0xC000000D );
314+ }
315+
316+ auto const count{static_cast <::std::uint_least64_t >(unix_to_nt_secs) * 10000000u + static_cast <::std::uint_least64_t >(unix_subsec_ts)};
317+
318+ if (count > static_cast <::std::uint_least64_t >(::std::numeric_limits<::std::int_least64_t >::max ()))
319+ {
320+ ::fast_io::throw_nt_error (0xC000000D );
321+ }
322+
323+ auto nt_ts{static_cast <::std::int_least64_t >(count)};
254324 ::std::uint_least32_t status{::fast_io::win32::nt::nt_delay_execution<zw>(false , __builtin_addressof (nt_ts))};
255325 if (status) [[unlikely]]
256326 {
257327 ::fast_io::throw_nt_error (status);
258328 }
259329}
260330
331+ template <bool zw = false , ::std::int_least64_t off_to_epoch>
332+ inline constexpr void sleep_until (::fast_io::basic_timestamp<off_to_epoch> const &expect_time)
333+ {
334+ if (expect_time.seconds < 0 ) [[unlikely]]
335+ {
336+ ::fast_io::throw_nt_error (0xC000000D );
337+ }
338+
339+ auto const win32_ts{static_cast <::fast_io::win32_timestamp>(expect_time)};
340+
341+ auto const win_100ns_seconds = static_cast <::std::uint_least64_t >(win32_ts.seconds ) * 10'000'000u + win32_ts.subseconds / 100u ;
342+
343+ if (win_100ns_seconds > static_cast <::std::uint_least64_t >(::std::numeric_limits<::std::int_least64_t >::max ())) [[unlikely]]
344+ {
345+ ::fast_io::throw_nt_error (0xC000000D );
346+ }
347+
348+ auto val = static_cast <::std::int_least64_t >(win_100ns_seconds);
349+ ::std::uint_least32_t status{::fast_io::win32::nt::nt_delay_execution<zw>(false , __builtin_addressof (val))};
350+ if (status) [[unlikely]]
351+ {
352+ ::fast_io::throw_nt_error (status);
353+ }
354+ }
355+
261356} // namespace this_thread
262357
263- } // namespace fast_io::win32::nt
358+ } // namespace win32::nt
359+
360+ using nt_thread = win32::nt::nt_thread<false >;
361+ using zw_thread = win32::nt::nt_thread<true >;
362+
363+ #if defined(_WIN32) && !defined(_WIN32_WINDOWS)
364+ using native_thread = nt_thread;
365+
366+ namespace this_thread
367+ {
368+ using ::fast_io::win32::nt::this_thread::get_id;
369+ using ::fast_io::win32::nt::this_thread::sleep_for;
370+ using ::fast_io::win32::nt::this_thread::sleep_until;
371+ } // namespace this_thread
372+ #endif
373+
374+ } // namespace fast_io
0 commit comments