Skip to content

Commit 66af2af

Browse files
authored
Merge pull request #63 from ntoskrnl7/feature/stl-runtime-coverage-expansion
Expand STL runtime coverage
2 parents 03c4659 + 5d48f14 commit 66af2af

19 files changed

Lines changed: 1037 additions & 140 deletions

CMakeLists.txt

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,13 @@ function(crtsys_generate_msvc_future_overlay OUT_VAR)
9090

9191
file(READ "${MSVC_FUTURE_HEADER}" CRTSYS_MSVC_FUTURE_CONTENT)
9292

93-
set(CRTSYS_FUTURE_IS_READY_SNIPPET
93+
set(CRTSYS_FUTURE_IS_READY_NOEXCEPT_SNIPPET
9494
" bool _Is_ready() const noexcept {
9595
return _State._Is_ready();
9696
}
9797
9898
")
99-
set(CRTSYS_FUTURE_READY_OR_STORED_SNIPPET
99+
set(CRTSYS_FUTURE_READY_OR_STORED_NOEXCEPT_SNIPPET
100100
" bool _Is_ready() const noexcept {
101101
return _State._Is_ready();
102102
}
@@ -106,29 +106,66 @@ function(crtsys_generate_msvc_future_overlay OUT_VAR)
106106
}
107107
108108
")
109+
set(CRTSYS_FUTURE_IS_READY_SNIPPET
110+
" bool _Is_ready() const {
111+
return _State._Is_ready();
112+
}
113+
114+
")
115+
set(CRTSYS_FUTURE_READY_OR_STORED_SNIPPET
116+
" bool _Is_ready() const {
117+
return _State._Is_ready();
118+
}
109119
110-
string(FIND "${CRTSYS_MSVC_FUTURE_CONTENT}" "${CRTSYS_FUTURE_IS_READY_SNIPPET}" CRTSYS_FUTURE_IS_READY_INDEX)
111-
if(CRTSYS_FUTURE_IS_READY_INDEX EQUAL -1)
120+
bool _Already_has_stored_result() const {
121+
return _State._Ptr() && _State._Ptr()->_Already_has_stored_result();
122+
}
123+
124+
")
125+
126+
set(CRTSYS_FUTURE_IS_READY_INDEX -1)
127+
string(FIND "${CRTSYS_MSVC_FUTURE_CONTENT}" "${CRTSYS_FUTURE_IS_READY_NOEXCEPT_SNIPPET}" CRTSYS_FUTURE_IS_READY_NOEXCEPT_INDEX)
128+
if(NOT CRTSYS_FUTURE_IS_READY_NOEXCEPT_INDEX EQUAL -1)
129+
string(REPLACE "${CRTSYS_FUTURE_IS_READY_NOEXCEPT_SNIPPET}" "${CRTSYS_FUTURE_READY_OR_STORED_NOEXCEPT_SNIPPET}" CRTSYS_MSVC_FUTURE_CONTENT "${CRTSYS_MSVC_FUTURE_CONTENT}")
130+
else()
131+
string(FIND "${CRTSYS_MSVC_FUTURE_CONTENT}" "${CRTSYS_FUTURE_IS_READY_SNIPPET}" CRTSYS_FUTURE_IS_READY_INDEX)
132+
endif()
133+
if(CRTSYS_FUTURE_IS_READY_NOEXCEPT_INDEX EQUAL -1 AND CRTSYS_FUTURE_IS_READY_INDEX EQUAL -1)
112134
message(WARNING "Unable to patch MSVC <future>: _Promise::_Is_ready shape was not recognized.")
113135
return()
114136
endif()
115-
string(REPLACE "${CRTSYS_FUTURE_IS_READY_SNIPPET}" "${CRTSYS_FUTURE_READY_OR_STORED_SNIPPET}" CRTSYS_MSVC_FUTURE_CONTENT "${CRTSYS_MSVC_FUTURE_CONTENT}")
137+
if(NOT CRTSYS_FUTURE_IS_READY_INDEX EQUAL -1)
138+
string(REPLACE "${CRTSYS_FUTURE_IS_READY_SNIPPET}" "${CRTSYS_FUTURE_READY_OR_STORED_SNIPPET}" CRTSYS_MSVC_FUTURE_CONTENT "${CRTSYS_MSVC_FUTURE_CONTENT}")
139+
endif()
116140

117141
set(CRTSYS_FUTURE_PROMISE_DTOR_CONDITION "if (_MyPromise._Is_valid() && !_MyPromise._Is_ready())")
142+
set(CRTSYS_FUTURE_PROMISE_DTOR_AT_THREAD_EXIT_CONDITION "if (_MyPromise._Is_valid() && !_MyPromise._Is_ready() && !_MyPromise._Is_ready_at_thread_exit())")
143+
set(CRTSYS_FUTURE_DTOR_INDEX -1)
144+
set(CRTSYS_FUTURE_DTOR_AT_THREAD_EXIT_INDEX -1)
118145
string(FIND "${CRTSYS_MSVC_FUTURE_CONTENT}" "${CRTSYS_FUTURE_PROMISE_DTOR_CONDITION}" CRTSYS_FUTURE_DTOR_INDEX)
119-
if(CRTSYS_FUTURE_DTOR_INDEX EQUAL -1)
146+
string(FIND "${CRTSYS_MSVC_FUTURE_CONTENT}" "${CRTSYS_FUTURE_PROMISE_DTOR_AT_THREAD_EXIT_CONDITION}" CRTSYS_FUTURE_DTOR_AT_THREAD_EXIT_INDEX)
147+
if(CRTSYS_FUTURE_DTOR_INDEX EQUAL -1 AND CRTSYS_FUTURE_DTOR_AT_THREAD_EXIT_INDEX EQUAL -1)
120148
message(WARNING "Unable to patch MSVC <future>: promise destructor shape was not recognized.")
121149
return()
122150
endif()
123151

124152
# MSVC STL keeps set_value_at_thread_exit() states unready until the CRT
125153
# thread-exit callback broadcasts. A promise destructor must not translate
126154
# that already-stored-but-not-yet-ready value into broken_promise.
127-
string(REPLACE
128-
"${CRTSYS_FUTURE_PROMISE_DTOR_CONDITION}"
129-
"if (_MyPromise._Is_valid() && !_MyPromise._Is_ready() && !_MyPromise._Already_has_stored_result())"
130-
CRTSYS_MSVC_FUTURE_CONTENT
131-
"${CRTSYS_MSVC_FUTURE_CONTENT}")
155+
if(NOT CRTSYS_FUTURE_DTOR_AT_THREAD_EXIT_INDEX EQUAL -1)
156+
string(REPLACE
157+
"${CRTSYS_FUTURE_PROMISE_DTOR_AT_THREAD_EXIT_CONDITION}"
158+
"if (_MyPromise._Is_valid() && !_MyPromise._Is_ready() && !_MyPromise._Is_ready_at_thread_exit() && !_MyPromise._Already_has_stored_result())"
159+
CRTSYS_MSVC_FUTURE_CONTENT
160+
"${CRTSYS_MSVC_FUTURE_CONTENT}")
161+
endif()
162+
if(NOT CRTSYS_FUTURE_DTOR_INDEX EQUAL -1)
163+
string(REPLACE
164+
"${CRTSYS_FUTURE_PROMISE_DTOR_CONDITION}"
165+
"if (_MyPromise._Is_valid() && !_MyPromise._Is_ready() && !_MyPromise._Already_has_stored_result())"
166+
CRTSYS_MSVC_FUTURE_CONTENT
167+
"${CRTSYS_MSVC_FUTURE_CONTENT}")
168+
endif()
132169

133170
set(CRTSYS_MSVC_FUTURE_OVERLAY_DIR "${CMAKE_CURRENT_BINARY_DIR}/crtsys-msvc-overlay/${MSVC_TOOLSET_VERSION}")
134171
file(MAKE_DIRECTORY "${CRTSYS_MSVC_FUTURE_OVERLAY_DIR}")
@@ -212,7 +249,10 @@ else()
212249
src/custom/crt/math/nextafter.c
213250
src/custom/crt/math/fpclassify.c
214251
src/custom/crt/math/fma.c
215-
src/custom/crt/math/real_helpers.c
252+
src/custom/crt/math/copysign.c
253+
src/custom/crt/math/ilogb.c
254+
src/custom/crt/math/log2.c
255+
src/custom/crt/math/scalbn.c
216256
)
217257
list(APPEND SOURCE_FILES ${MATH_SOURCE_FILES})
218258
endif()

cmake/CrtSys.cmake

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,13 @@ function(crtsys_generate_msvc_future_overlay OUT_VAR)
9393

9494
file(READ "${MSVC_FUTURE_HEADER}" CRTSYS_MSVC_FUTURE_CONTENT)
9595

96-
set(CRTSYS_FUTURE_IS_READY_SNIPPET
96+
set(CRTSYS_FUTURE_IS_READY_NOEXCEPT_SNIPPET
9797
" bool _Is_ready() const noexcept {
9898
return _State._Is_ready();
9999
}
100100
101101
")
102-
set(CRTSYS_FUTURE_READY_OR_STORED_SNIPPET
102+
set(CRTSYS_FUTURE_READY_OR_STORED_NOEXCEPT_SNIPPET
103103
" bool _Is_ready() const noexcept {
104104
return _State._Is_ready();
105105
}
@@ -109,29 +109,66 @@ function(crtsys_generate_msvc_future_overlay OUT_VAR)
109109
}
110110
111111
")
112+
set(CRTSYS_FUTURE_IS_READY_SNIPPET
113+
" bool _Is_ready() const {
114+
return _State._Is_ready();
115+
}
116+
117+
")
118+
set(CRTSYS_FUTURE_READY_OR_STORED_SNIPPET
119+
" bool _Is_ready() const {
120+
return _State._Is_ready();
121+
}
112122
113-
string(FIND "${CRTSYS_MSVC_FUTURE_CONTENT}" "${CRTSYS_FUTURE_IS_READY_SNIPPET}" CRTSYS_FUTURE_IS_READY_INDEX)
114-
if(CRTSYS_FUTURE_IS_READY_INDEX EQUAL -1)
123+
bool _Already_has_stored_result() const {
124+
return _State._Ptr() && _State._Ptr()->_Already_has_stored_result();
125+
}
126+
127+
")
128+
129+
set(CRTSYS_FUTURE_IS_READY_INDEX -1)
130+
string(FIND "${CRTSYS_MSVC_FUTURE_CONTENT}" "${CRTSYS_FUTURE_IS_READY_NOEXCEPT_SNIPPET}" CRTSYS_FUTURE_IS_READY_NOEXCEPT_INDEX)
131+
if(NOT CRTSYS_FUTURE_IS_READY_NOEXCEPT_INDEX EQUAL -1)
132+
string(REPLACE "${CRTSYS_FUTURE_IS_READY_NOEXCEPT_SNIPPET}" "${CRTSYS_FUTURE_READY_OR_STORED_NOEXCEPT_SNIPPET}" CRTSYS_MSVC_FUTURE_CONTENT "${CRTSYS_MSVC_FUTURE_CONTENT}")
133+
else()
134+
string(FIND "${CRTSYS_MSVC_FUTURE_CONTENT}" "${CRTSYS_FUTURE_IS_READY_SNIPPET}" CRTSYS_FUTURE_IS_READY_INDEX)
135+
endif()
136+
if(CRTSYS_FUTURE_IS_READY_NOEXCEPT_INDEX EQUAL -1 AND CRTSYS_FUTURE_IS_READY_INDEX EQUAL -1)
115137
message(WARNING "Unable to patch MSVC <future>: _Promise::_Is_ready shape was not recognized.")
116138
return()
117139
endif()
118-
string(REPLACE "${CRTSYS_FUTURE_IS_READY_SNIPPET}" "${CRTSYS_FUTURE_READY_OR_STORED_SNIPPET}" CRTSYS_MSVC_FUTURE_CONTENT "${CRTSYS_MSVC_FUTURE_CONTENT}")
140+
if(NOT CRTSYS_FUTURE_IS_READY_INDEX EQUAL -1)
141+
string(REPLACE "${CRTSYS_FUTURE_IS_READY_SNIPPET}" "${CRTSYS_FUTURE_READY_OR_STORED_SNIPPET}" CRTSYS_MSVC_FUTURE_CONTENT "${CRTSYS_MSVC_FUTURE_CONTENT}")
142+
endif()
119143

120144
set(CRTSYS_FUTURE_PROMISE_DTOR_CONDITION "if (_MyPromise._Is_valid() && !_MyPromise._Is_ready())")
145+
set(CRTSYS_FUTURE_PROMISE_DTOR_AT_THREAD_EXIT_CONDITION "if (_MyPromise._Is_valid() && !_MyPromise._Is_ready() && !_MyPromise._Is_ready_at_thread_exit())")
146+
set(CRTSYS_FUTURE_DTOR_INDEX -1)
147+
set(CRTSYS_FUTURE_DTOR_AT_THREAD_EXIT_INDEX -1)
121148
string(FIND "${CRTSYS_MSVC_FUTURE_CONTENT}" "${CRTSYS_FUTURE_PROMISE_DTOR_CONDITION}" CRTSYS_FUTURE_DTOR_INDEX)
122-
if(CRTSYS_FUTURE_DTOR_INDEX EQUAL -1)
149+
string(FIND "${CRTSYS_MSVC_FUTURE_CONTENT}" "${CRTSYS_FUTURE_PROMISE_DTOR_AT_THREAD_EXIT_CONDITION}" CRTSYS_FUTURE_DTOR_AT_THREAD_EXIT_INDEX)
150+
if(CRTSYS_FUTURE_DTOR_INDEX EQUAL -1 AND CRTSYS_FUTURE_DTOR_AT_THREAD_EXIT_INDEX EQUAL -1)
123151
message(WARNING "Unable to patch MSVC <future>: promise destructor shape was not recognized.")
124152
return()
125153
endif()
126154

127155
# MSVC STL keeps set_value_at_thread_exit() states unready until the CRT
128156
# thread-exit callback broadcasts. A promise destructor must not translate
129157
# that already-stored-but-not-yet-ready value into broken_promise.
130-
string(REPLACE
131-
"${CRTSYS_FUTURE_PROMISE_DTOR_CONDITION}"
132-
"if (_MyPromise._Is_valid() && !_MyPromise._Is_ready() && !_MyPromise._Already_has_stored_result())"
133-
CRTSYS_MSVC_FUTURE_CONTENT
134-
"${CRTSYS_MSVC_FUTURE_CONTENT}")
158+
if(NOT CRTSYS_FUTURE_DTOR_AT_THREAD_EXIT_INDEX EQUAL -1)
159+
string(REPLACE
160+
"${CRTSYS_FUTURE_PROMISE_DTOR_AT_THREAD_EXIT_CONDITION}"
161+
"if (_MyPromise._Is_valid() && !_MyPromise._Is_ready() && !_MyPromise._Is_ready_at_thread_exit() && !_MyPromise._Already_has_stored_result())"
162+
CRTSYS_MSVC_FUTURE_CONTENT
163+
"${CRTSYS_MSVC_FUTURE_CONTENT}")
164+
endif()
165+
if(NOT CRTSYS_FUTURE_DTOR_INDEX EQUAL -1)
166+
string(REPLACE
167+
"${CRTSYS_FUTURE_PROMISE_DTOR_CONDITION}"
168+
"if (_MyPromise._Is_valid() && !_MyPromise._Is_ready() && !_MyPromise._Already_has_stored_result())"
169+
CRTSYS_MSVC_FUTURE_CONTENT
170+
"${CRTSYS_MSVC_FUTURE_CONTENT}")
171+
endif()
135172

136173
set(CRTSYS_MSVC_FUTURE_OVERLAY_DIR "${CMAKE_CURRENT_BINARY_DIR}/crtsys-msvc-overlay/${MSVC_TOOLSET_VERSION}")
137174
file(MAKE_DIRECTORY "${CRTSYS_MSVC_FUTURE_OVERLAY_DIR}")

docs/cppreference-attribution.md

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ test harness, typically by moving the sample `main()` body into a namespaced
3939
- `std::mutex`: <https://en.cppreference.com/w/cpp/thread/mutex>
4040
- `std::lock_guard`: <https://en.cppreference.com/w/cpp/thread/lock_guard>
4141
- `std::shared_mutex`: <https://en.cppreference.com/w/cpp/thread/shared_mutex>
42+
- `std::shared_timed_mutex`: <https://en.cppreference.com/w/cpp/thread/shared_timed_mutex>
4243
- `std::shared_lock`: <https://en.cppreference.com/w/cpp/thread/shared_lock>
4344
- `std::timed_mutex`: <https://en.cppreference.com/w/cpp/thread/timed_mutex>
4445
- `std::recursive_mutex`: <https://en.cppreference.com/w/cpp/thread/recursive_mutex>
@@ -148,6 +149,14 @@ test harness, typically by moving the sample `main()` body into a namespaced
148149
- `std::ranges::slide_view`: <https://en.cppreference.com/w/cpp/ranges/slide_view>
149150
- `std::ranges::stride_view`: <https://en.cppreference.com/w/cpp/ranges/stride_view>
150151
- `std::ranges::repeat_view`: <https://en.cppreference.com/w/cpp/ranges/repeat_view>
152+
- `std::ranges::take_view`: <https://en.cppreference.com/w/cpp/ranges/take_view>
153+
- `std::ranges::drop_view`: <https://en.cppreference.com/w/cpp/ranges/drop_view>
154+
- `std::ranges::reverse_view`: <https://en.cppreference.com/w/cpp/ranges/reverse_view>
155+
- `std::ranges::join_view`: <https://en.cppreference.com/w/cpp/ranges/join_view>
156+
- `std::ranges::split_view`: <https://en.cppreference.com/w/cpp/ranges/split_view>
157+
- `std::ranges::values_view`: <https://en.cppreference.com/w/cpp/ranges/values_view>
158+
- `std::ranges::keys_view`: <https://en.cppreference.com/w/cpp/ranges/keys_view>
159+
- `std::ranges::elements_view`: <https://en.cppreference.com/w/cpp/ranges/elements_view>
151160
- `std::merge`: <https://en.cppreference.com/w/cpp/algorithm/merge>
152161
- `std::make_heap`: <https://en.cppreference.com/w/cpp/algorithm/make_heap>
153162
- `std::next_permutation`: <https://en.cppreference.com/w/cpp/algorithm/next_permutation>
@@ -195,9 +204,17 @@ test harness, typically by moving the sample `main()` body into a namespaced
195204
- `std::derived_from` / `std::same_as`: <https://en.cppreference.com/w/cpp/concepts>
196205
- `std::strong_ordering`: <https://en.cppreference.com/w/cpp/utility/compare/strong_ordering>
197206
- `std::numbers`: <https://en.cppreference.com/w/cpp/numeric/constants>
207+
- `std::chrono::year_month_day`: <https://en.cppreference.com/w/cpp/chrono/year_month_day>
208+
- `std::chrono::weekday`: <https://en.cppreference.com/w/cpp/chrono/weekday>
209+
- `std::chrono::hh_mm_ss`: <https://en.cppreference.com/w/cpp/chrono/hh_mm_ss>
198210
- `std::format`: <https://en.cppreference.com/w/cpp/utility/format/format>
211+
- `std::formatter`: <https://en.cppreference.com/w/cpp/utility/format/formatter>
199212
- `std::print`: <https://en.cppreference.com/w/cpp/io/print>
200213
- `std::regex`: <https://en.cppreference.com/w/cpp/regex>
214+
- `std::regex_match`: <https://en.cppreference.com/w/cpp/regex/regex_match>
215+
- `std::regex_iterator`: <https://en.cppreference.com/w/cpp/regex/regex_iterator>
216+
- `std::regex_token_iterator`: <https://en.cppreference.com/w/cpp/regex/regex_token_iterator>
217+
- `std::quoted`: <https://en.cppreference.com/w/cpp/io/manip/quoted>
201218
- `std::distance`: <https://en.cppreference.com/w/cpp/iterator/distance>
202219
- `std::advance`: <https://en.cppreference.com/w/cpp/iterator/advance>
203220
- `std::next`: <https://en.cppreference.com/w/cpp/iterator/next>
@@ -248,6 +265,9 @@ test harness, typically by moving the sample `main()` body into a namespaced
248265
- `std::filesystem::space`: <https://en.cppreference.com/w/cpp/filesystem/space>
249266
- `std::filesystem::rename`: <https://en.cppreference.com/w/cpp/filesystem/rename>
250267
- `std::filesystem::temp_directory_path`: <https://en.cppreference.com/w/cpp/filesystem/temp_directory_path>
268+
- `std::filesystem::absolute`: <https://en.cppreference.com/w/cpp/filesystem/absolute>
269+
- `std::filesystem::current_path`: <https://en.cppreference.com/w/cpp/filesystem/current_path>
270+
- `std::filesystem::relative` / `std::filesystem::proximate`: <https://en.cppreference.com/w/cpp/filesystem/relative>
251271
- `std::filesystem::last_write_time`: <https://en.cppreference.com/w/cpp/filesystem/last_write_time>
252272
- `std::filesystem::canonical` / `std::filesystem::weakly_canonical`: <https://en.cppreference.com/w/cpp/filesystem/canonical>
253273
- `std::function`: <https://en.cppreference.com/w/cpp/utility/functional/function>
@@ -301,6 +321,14 @@ because the example embeds a 32 KiB tape buffer in the interpreter object.
301321

302322
The listed C++23 `std::views` examples are compiled into the driver test when
303323
the matching feature-test macro is available.
324+
The `std::ranges::split_view` example is kept source-identical where the active
325+
STL provides `std::string_view`'s C++23 range constructor; older toolsets print
326+
a skip line instead of using a non-cppreference workaround.
327+
The `std::ranges::keys_view` and `std::ranges::elements_view` examples keep the
328+
same view operations; their Unicode table/letter output is transliterated to
329+
ASCII in the driver source to keep the test file encoding simple. The
330+
`keys_view` harness restores `std::cout`'s previous locale after the example
331+
because all cppreference examples run in one driver instance.
304332

305333
The `std::to_chars` test follows the cppreference example, including the
306334
floating-point overload calls. The `std::from_chars` test follows the
@@ -312,12 +340,19 @@ The `std::expected` example is compiled into the driver test when the
312340

313341
The `std::format` and `std::print` examples run in the default driver build.
314342

315-
The `std::regex` example keeps the cppreference `regex_search`, iterator, and
316-
`regex_replace` flow.
343+
The `std::shared_timed_mutex` page leaves the protected resource as
344+
`/* data */`; the driver harness uses a small `int` so the assignment example
345+
can verify the copied value.
346+
347+
The `std::regex` coverage keeps the cppreference `regex_search`,
348+
`regex_match`, iterator, token-iterator, and `regex_replace` flows.
317349

318350
The filesystem examples listed above are ported into the driver harness.
319351
The `copy_symlink` page currently has no cppreference example, so the harness
320352
uses a small direct check for that function.
353+
The `current_path` and `canonical` examples restore the original current path
354+
before returning because cppreference examples are standalone programs, while
355+
the driver harness executes many examples in one process.
321356

322357
The `std::complex` test keeps the arithmetic portion of the cppreference
323358
example and also includes the `std::exp` and `std::pow` examples.

0 commit comments

Comments
 (0)