Repository navigation
1.11.3 - #83
Merged
Merged
1.11.3#83
Conversation
* test(integer_to_string): share one short performance schedule Hoist the per-section warmup, loop, and iteration counts to one shared schedule of 2 warmups, 1 loop, and 1,000,000 iterations. The previous 4 x 100 x 1,000,000 schedule was repeated in every section and took about ten minutes. * tidy * tidy * tidy * misc --------- Co-authored-by: Matt Wilson <matthew.wilson.synesis@gmail.com>
mwsis
approved these changes
Oct 26, 2026
* boilerplate * CI: align push branches with Synesis canonical set Use lexicographic boilerplate/dev/idiomatic/master/rc1–rc3 triggers; drop rc4/rc5/update. Keep unfiltered pull_request. * Scripts: add .sis/project_name.txt and wire ProjectName Canonical short name for helper-script status/--help messages, loaded via tr -d whitespace per Synesis convention. * Scripts: MSYS auto-MinGW in prepare_cmake; add ctest_cmake.sh Detect MSYSTEM to enable MinGW configure/make by default, and add a ProjectName-aware CTest wrapper aligned with peer libs. * CMake: set CMP0177 and fix BuildType default cache set Enable install-path normalisation on CMake 3.31+, and correct CMAKE_BUILD_TYPE CACHE assignment / .git detection in BuildType.cmake. * Docs: review and refresh TODO.md against current packaging Mark completed README/CI/.sis/CMake modernisation items, consolidate duplicate blog/Doxygen bullets, and clarify GHA vs dialect-matrix coverage. * Modernise STLSoft build/CI boilerplate and rewrite TODO roadmap. Align helper scripts and CMake with peer libraries (canonical CI branches, .sis project name, MSYS MinGW/ctest, CMP0177/BuildType, coloured runners) and replace TODO.md with a versioned 1.11/1.12 plan. * Colourise STLSoft test/example runners and add CI update.3/update.4 branches. Match peer tput/RbEnvClr_ output on execute/skip lines, and extend the push-branch list for the active update.* line of work. * CMake/CI: optional ACE discovery and dedicated ACE cell Add lean FindACE, NO_ACE/--no-ace, and a linux-gcc cell-ace job (libace-dev) so ACESTL can be exercised without burdening the default matrix; keep ace on push.branches for this branch. * test: ACESTL version smoke when ACE is present Gate _ACESTL_VER output in versions.iostreams and test.unit.versions on STLSOFT_HAS_ACE (link ACE::ACE), and assert ACE discovery in the ACE CI cell so enablement is visible in the logs. * fix * test: add ACESTL string-access shim unit tests Add HAS_ACE-gated unit tests for ACE_Time_Value and ACE_String_Base string-access shims. Includes a temporary deliberate failure in time_value to confirm GHA ACE unit-test failure reporting. * fix: ACE_Time_Value stream_insert shadowing; shim_string::data() Rename stream_insert's seconds local so it does not shadow the stream parameter (breaks -Werror builds), correct its length asserts, and use basic_shim_string::data() in the time_value unit test. * CI: restore +x after artifact download; fail on zero unit tests GitHub Actions artifacts drop execute bits, so find -exec test -x discovered nothing and unit/scratch jobs exited green. Chmod matching binaries after download (as Pantheios), and make run_all_unit_tests.sh fail when no executables are found. * CI/scripts: do not chmod or run CMake artefacts as examples Narrow post-artifact +x restore under examples/, and harden run_all_examples.sh to skip CMake files (e.g. CTestTestfile.cmake) so example jobs do not try to execute them. * test: remove deliberate ACESTL time_value failure used for GHA check * ACESTL: implement invoke_ACE_OS_snprintf via stlsoft_C_snprintf Replace ACE_OS::snprintf in the ACE_Time_Value string-access helpers with stlsoft_C_snprintf, and route stream_insert through the same invoke_ACE_OS_snprintf overloads (TODO 1.11.1). * CI: exercise MFCSTL on Windows via with-mfc cell Gate FindMFC behind with-mfc (cell-mfc / windows-cl-mfc), verify discovery, and apply CMAKE_MFC_FLAG/_AFXDLL only to MFC-consuming test targets. * fix * CI: exercise ATLSTL on Windows via with-atl cell Add FindATL, gate discovery behind with-atl (cell-atl / windows-cl-atl), verify atlbase.h, and smoke-test via test.unit.versions. * TODO * squash-commit * squash-commit * refactor(stlsoft): suffix C-API programs with `.C` Move C-API example and test names from a leading `C.` to a trailing `.C`, matching the Synesis convention for a C program beside a C++ counterpart: - rename directories and CMake/xTests runner ids across examples and tests; - skip `include/` in generate_cmakelists.rb and accept Proc ignore entries; - add a `sinteger64` copy constructor and fix the monitor `const_cast`; - call `try_string_to_integer_4slre_` from `string_to_integer_range`; - refresh copyright years and mark the MFCSTL CI TODO complete; * squash-commit * tidy * refactor(stlsoft): shorten test directory names (#25) * refactor(stlsoft): shorten the uds_helpers test directory Point add_subdirectory at uds_helpers. The executable name stays test.component.inetstl.util.uds_helpers. * refactor(stlsoft): shorten component-test directories Rename each test/component leaf to its subject segment and retarget add_subdirectory. Refresh each entry file's Updated and File banner. Executable names stay test.component.*. * refactor(stlsoft): shorten unit-test directories Rename each test/unit leaf except test.unit.versions to its subject segment and retarget add_subdirectory. Refresh each entry file's Updated and File banner. Executable names stay test.unit.*. test.unit.versions is unchanged. * refactor(stlsoft): shorten scratch-test directories Rename each test/scratch leaf to its subject segment and retarget add_subdirectory. Refresh Updated and File banners where present. Executable names stay test.scratch.*. * refactor(stlsoft): deepen performance-test directories Move each performance test onto its component header path, such as platformstl/diagnostics/stopwatch and stlsoft/memory/auto_buffer, and retarget add_subdirectory. Keep the C++ standard guards and the executable names. * refactor(stlsoft): shorten the test.unit.versions directory Rename test/unit/test.unit.versions to versions and retarget add_subdirectory. Refresh the entry file's Updated and File banner. The executable name stays test.unit.versions. * chore(stlsoft): record 1.11.1-rc7 for the test-tree reorganisation Advance `_STLSOFT_VER` to `_STLSOFT_VER_1_11_1_RC7` (`0x010b01c7`) and align the release notes with the shortened test directories and nested **test/performance** layout: - **CHANGES.md**, **NEWS.md**, and **INSTALL.md** updated for 30th September 2026; - **test.unit.versions** expects **_STLSOFT_VER_1_11_1_RC7**; * Remove empty test cases (#26) * refactor(stlsoft): shorten the uds_helpers test directory Point add_subdirectory at uds_helpers. The executable name stays test.component.inetstl.util.uds_helpers. * refactor(stlsoft): shorten component-test directories Rename each test/component leaf to its subject segment and retarget add_subdirectory. Refresh each entry file's Updated and File banner. Executable names stay test.component.*. * refactor(stlsoft): shorten unit-test directories Rename each test/unit leaf except test.unit.versions to its subject segment and retarget add_subdirectory. Refresh each entry file's Updated and File banner. Executable names stay test.unit.*. test.unit.versions is unchanged. * refactor(stlsoft): shorten scratch-test directories Rename each test/scratch leaf to its subject segment and retarget add_subdirectory. Refresh Updated and File banners where present. Executable names stay test.scratch.*. * refactor(stlsoft): deepen performance-test directories Move each performance test onto its component header path, such as platformstl/diagnostics/stopwatch and stlsoft/memory/auto_buffer, and retarget add_subdirectory. Keep the C++ standard guards and the executable names. * refactor(stlsoft): shorten the test.unit.versions directory Rename test/unit/test.unit.versions to versions and retarget add_subdirectory. Refresh the entry file's Updated and File banner. The executable name stays test.unit.versions. * test(STLSoft): remove empty unit-test case functions Remove empty xTests case functions (bodies with no statements), together with their forward declarations and XTESTS_RUN_CASE registrations, across 19 STLSoft unit-test entry files; - nine allocator suites keep a runner and no cases, because every case body was empty; - the Unix-built suites were rebuilt and passed; * test(STLSoft): flesh out empty allocator unit-test cases Give each of the nine allocator suites its seven cases: - round-trip 0, 4, 256, and 4096 ints, and reject a count past max_size(); - specialise std::list and std::vector with that allocator; - null_allocator must throw out_of_memory_exception on every request, including container insertion; - malloc_allocator, new_allocator, and null_allocator passed on this host; * fix * `platformstl::file_lines` automated tests (#20) * test(stlsoft): cover platformstl::file_lines component behavior Add a platformstl filesystem component suite covering empty files and one-line, terminated-line, and three-line inputs; verify embedded NUL data raises platformstl::invalid_file_type_exception; register the filesystem subtree with the existing platformstl component tests; * feat(platformstl): add FILE_stream::write_binary() Add a byte-oriented write that preserves embedded NULs, and deprecate write(void const*, size_t) in its favour. Cover CR and CRLF files in the file_lines component tests, and write the NUL fixture through write_binary(). * Bit functions: refactoring, extension, and optimisation (#23) * style(stlsoft): normalise bit-function header section banners Replace the short separator above each namespace close with the long section banner, and drop the short separator that precedes the include-guard close: - Refresh **Updated:** to 24th September 2026 and extend the Synesis Information Systems copyright through 2026; - Bump each header **EDIT** counter; * chore(tests): canonicalisation of test function names * test(stlsoft): cover all bit-function overloads by width Expand **test.unit.stlsoft.util.bit_functions** so every public C++ overload is called for each supported width, plus `count_bits(int)` for signedness; - Add Kernighan and 8-bit-table cases for **uint64_t**; - Add **count_bits** for **uint32_t**, **uint64_t**, and **int**; - Add **find_highest_bit** for **uint8_t** and **uint16_t**; - Add **calculate_xor_over_range** for 16-, 32-, and 64-bit ranges; - Remove in-unit stopwatch timing; * test(stlsoft): add bit-functions performance suite Add **test.performance.stlsoft.bit_functions** under a nested **stlsoft/** performance tree, with an aligned width × function timing table covering every public bit-function overload; - Wire **test/performance/CMakeLists.txt** → **stlsoft** → **bit_functions**; - Time Kernighan and 8-bit-table popcount, **count_bits**, **find_highest_bit**, and **calculate_xor_over_range**; * fix: `count_bits()` overloads were broken when `STLSOFT_BIT_COUNT_BY_Kernighan` is defined * test(stlsoft): vary popcount density in bit-functions perf Extend **test.performance.stlsoft.bit_functions** with denser popcount workloads so Kernighan vs 8-bit-table can be compared beyond the sparse sequential-i series; - Add /~i (bitwise-not), /ones (volatile all-ones), and /ones^1 (all-ones with one rotating bit cleared); - Widen the function-name column for the longer row labels; * fix(stlsoft): avoid uint64_t clash in bit-functions perf Stop importing stlsoft::uint64_t into the global namespace: it conflicts with ::uint64_t from <cstdint> (pulled in via std_chrono_hrc_stopwatch) and made 64-bit overloads ambiguous on Linux GCC. - Use stlsoft::ss_uintN_t aliases for variables and casts; keep column headers as uintN_t labels; * test(stlsoft.b): report median bit-function timings with a 64-bit anchor Time each row as one discarded warmup plus five samples and print the median. Accumulate the anchor in ss_uint64_t. Print STLSOFT_COMPILER_VERSION_STRING, whether optimisation is size, speed, or off, and whether this is a release or debug-asserts build. * fix(stlsoft): silence maybe-uninitialized in bit_functions median Zero-initialise the local sorted[] buffer in median_sample, guard empty n, and clamp n to NUM_SAMPLES so GCC -Werror=maybe-uninitialized no longer fails the performance harness on CI. * test(stlsoft.b): time more bit patterns and print per-call rates Add volatile-zero, rotating-bit, and both-halves-live rows for popcount and find_highest_bit, so the 64-bit high half is exercised. Print ns/call on the same line as the loop time, ns/element for XOR, and the anchor last. Honor SIS_PERFTESTS_GROUPGAPS with a blank line between operation and input-pattern groups. * docs(stlsoft.b): record bit-function timings and the default choice Keep the 8-bit table as the default for count_bits(). Apple Clang rewrites Kernighan into a hardware popcount; Linux and Windows compilers execute the source loop and the table is faster there. * feat(stlsoft): bit-function intrinsics for 1.11.1-rc7 Add unselected `count_bits_by_intrinsic()` / `find_highest_bit_by_intrinsic()`, with external/internal bitfns detection (GCC/Clang builtins preferred over MSVC), 8/16-bit count overloads, Clang `STLSOFT_CLANG_VER`, unit and performance coverage, and strategy notes that keep the 8-bit table as the `count_bits()` default; * fix(stlsoft): cast popcnt64; enable perf group gaps in CI Cast MSVC `__popcnt64` through `STLSOFT_C_CAST(int, …)` so `/WX` builds stop on C4244. Export `SIS_PERFTESTS_GROUPGAPS=1` for the performance job and only print the harness banner when that env is truey. Quiet getenv C4996 and narrow `~` promotions on uint8/16 ones patterns. Record Linux GCC 13.3 (~3.1 ns soft popcount vs table) and Apple Clang 21 CI findings in `strategy/BIT_FUNCTIONS.md`. * docs(stlsoft): fold full CI bit-function matrix into strategy Replace partial CI notes in strategy/BIT_FUNCTIONS.md with the six-cell wave (Linux Clang/GCC, macOS Clang/“gcc”, MSVC, MinGW): soft vs hard popcount, /bit deletions, and find_highest comparisons. Keep table as portable default; leave both intrinsics unselected pending a narrow gate. * test(stlsoft): add component tests for environment_variable_exists() (#24) * test(stlsoft): add component tests for environment_variable_exists() Cover stlsoft::environment_variable_exists() against the process environment, using platformstl::environment_variable_scope to set and restore each variable: absent, present, erased, value replacement, exact name match, std::string and simple_string shims, UNIX empty values, and case sensitivity. * refactor(stlsoft): rename environment_variable_exists_a to _m Rename `stlsoft_C_environment_variable_exists_a()` to `stlsoft_C_environment_variable_exists_m()` and keep the `_a` spelling as a deprecated forwarder; the C++ overloads and component tests call `_m`. * `platformstl::file_lines` performance tests (#21) * test(stlsoft): cover platformstl::file_lines component behavior Add a platformstl filesystem component suite covering empty files and one-line, terminated-line, and three-line inputs; verify embedded NUL data raises platformstl::invalid_file_type_exception; register the filesystem subtree with the existing platformstl component tests; * test(stlsoft): benchmark platformstl::file_lines Add a standalone comparative performance test for platformstl::file_lines_a and std::ifstream plus std::getline; follow existing STLSoft warm-up, stopwatch, anchoring, and tabular output conventions; * test(platformstl): improved performance test program for `platformstl::basic_file_lines<>` * fix(platformstl::file_lines): compatible with `std::basic_string_view` * perf(platformstl::file_lines): adjusted preallocation of number of reserved lines * perf(platformstl::file_lines): moved file-contents check into in-loop processing, so only pass once * perf(platformstl::file_lines): use of `#emplace_back()` (C++ 11+) * feat(platformstl): add FILE_stream::write_binary() Add a byte-oriented write that preserves embedded NULs, and deprecate write(void const*, size_t) in its favour. Cover CR and CRLF files in the file_lines component tests, and write the NUL fixture through write_binary(). * feat(platformstl): add FILE_stream::write_binary() Add a byte-oriented write that preserves embedded NULs, and deprecate write(void const*, size_t) in its favour. Cover CR and CRLF files in the file_lines component tests, and write the NUL fixture through write_binary(). * test(platformstl): cover CR, CRLF, and small files in file_lines perf Time LF, CRLF, and CR at the existing 1000×64 and 5000×80 shapes, and at 1×16, 8×32, and 32×64, so a later small-file path has a fixed-cost region to beat. Read the getline baseline in binary mode so the CR bytes are the same on every platform. * refactor(platformstl): parse file_lines directly from mapping Remove the full-file m_contents heap copy; parse directly from the mmap'd base pointer for lower memory bandwidth use. Drop the unused m_contents member and early-return on empty maps. * fix(platformstl): use C stdio in file_lines perf harness Avoid MinGW std::ifstream/std::getline crashes by switching the perf fixture writer/reader to fopen/fwrite/fgetc while preserving split on '\n' semantics (keeping '\r' in-line). * fix(performance): use STLSOFT fopen wrapper in file_lines benchmark * test(stlsoft): compare getline and getc file-line baselines - Rename the existing per-character stdio baseline to vector<std::string> plus getc; - add a genuine std::getline baseline using the appropriate LF or CR delimiter and normalise CRLF line endings; * ci * ci(stlsoft): trace the MinGW file_lines performance crash Temporarily run only the Windows/MinGW CI cell and write flushed stderr markers through the file_lines performance program; - Each scenario, warmup, and sampled iteration logs enter and leave; - `basic_file_lines` traces construct, iterate, and walk on those samples; * fix(platformstl): stop the MinGW getline baseline segfaulting `std::ifstream` dies on open under MinGW, which the progress log showed on the first getline call. Read that baseline through FILE* and still time `std::getline`; - Other compilers keep `std::ifstream`; * test(platformstl): stage the MinGW file_lines perf crash probe Print flushed C traces from constructors before main, then walk one small file through write, fgetc, getline, file_lines, and ifstream. The full matrix runs only when SIS_FILE_LINES_PERF_FULL is set. * test(platformstl): leave an on-disk trail for the MinGW file_lines death Add a pure-C boot probe and cwd breadcrumb file, fix the performance harness so it keeps the real child exit status, dump PE imports before exec, and restrict the MinGW cell to file_lines only. * ci(stlsoft): treat MinGW file_lines 127 as a loader failure Static-link libgcc/libstdc++ for the file_lines perf target, run that step under the msys2 shell, and on child-exit 127 dump MinGW runtimes, copy them beside the exe, and retry once. * ci(stlsoft): re-enable the file_lines full perf matrix on MinGW The staged probe passed end-to-end after static-linking libgcc/libstdc++, including std::ifstream. Set SIS_FILE_LINES_PERF_FULL so the next cell run hits the real workload with traces still enabled. * fix(cmake): static-link MinGW libgcc/libstdc++ for PE load MinGW performance exes were exiting 127 before any user code when the runner PATH did not match the toolchain that built them. Static-link libgcc and libstdc++ for Windows GNU targets in TargetMacros, restore the file_lines perf baseline and full CI, and capture the real child exit status in execute_performance_tests.sh. * docs(stlsoft): record file_lines.perf and restore GROUPGAPS in CI Restore SIS_PERFTESTS_GROUPGAPS=1 on the performance job; document platformstl::basic_file_lines<> mmap parse (~10–20× vs fgetc; ~parity / ~1.2× vs getline), the file_lines perf harness, MinGW static libgcc / libstdc++, and the execute_performance_tests.sh child_ec fix in CHANGES.md / NEWS.md for 1.11.1-rc7. * String comparison unit-tests (#27) * refactor(stlsoft): shorten the uds_helpers test directory Point add_subdirectory at uds_helpers. The executable name stays test.component.inetstl.util.uds_helpers. * refactor(stlsoft): shorten component-test directories Rename each test/component leaf to its subject segment and retarget add_subdirectory. Refresh each entry file's Updated and File banner. Executable names stay test.component.*. * refactor(stlsoft): shorten unit-test directories Rename each test/unit leaf except test.unit.versions to its subject segment and retarget add_subdirectory. Refresh each entry file's Updated and File banner. Executable names stay test.unit.*. test.unit.versions is unchanged. * refactor(stlsoft): shorten scratch-test directories Rename each test/scratch leaf to its subject segment and retarget add_subdirectory. Refresh Updated and File banners where present. Executable names stay test.scratch.*. * refactor(stlsoft): deepen performance-test directories Move each performance test onto its component header path, such as platformstl/diagnostics/stopwatch and stlsoft/memory/auto_buffer, and retarget add_subdirectory. Keep the C++ standard guards and the executable names. * refactor(stlsoft): shorten the test.unit.versions directory Rename test/unit/test.unit.versions to versions and retarget add_subdirectory. Refresh the entry file's Updated and File banner. The executable name stays test.unit.versions. * test(STLSoft): remove empty unit-test case functions Remove empty xTests case functions (bodies with no statements), together with their forward declarations and XTESTS_RUN_CASE registrations, across 19 STLSoft unit-test entry files; - nine allocator suites keep a runner and no cases, because every case body was empty; - the Unix-built suites were rebuilt and passed; * test(STLSoft): flesh out empty allocator unit-test cases Give each of the nine allocator suites its seven cases: - round-trip 0, 4, 256, and 4096 ints, and reject a count past max_size(); - specialise std::list and std::vector with that allocator; - null_allocator must throw out_of_memory_exception on every request, including container insertion; - malloc_allocator, new_allocator, and null_allocator passed on this host; * test(stlsoft): cover stlsoft_C_strnicmp and the C++ wrappers Add unit programs for stlsoft_C_strnicmp(), stlsoft_C_wcsnicmp(), and the stlsoft::c_string wrappers: - char and wchar_t equal, less, and greater; - n==0, stop at NUL, and ignore the byte past n; - ASCII case-fold, and high-bit bytes that share a sign; * test(stlsoft): cover c_string_traits string comparison Add a unit program for stlsoft::c_string_traits compare, n-compare, and the ASCII case-insensitive forms, for char and wchar_t: - equal, less, greater, and empty strings; - n==0, stop at NUL, and ignore the byte past n; * test(stlsoft): cover char_traits and char_traits_safe comparison Add a unit program for stlsoft::char_traits and char_traits_safe, for char and wchar_t: - eq, lt, and compare equal, less, and greater; - n==0, exact-n past NUL, and compare_max stopping at NUL; - compare_null for both-null and one-null; - char compare unsigned high-bit order; - char_traits_safe compare, and compare_max with null pointers; * test(stlsoft): cover stlsoft::strcmp and stlsoft::strncmp Add a unit program for the pointer overloads and the S const& shims: - char and wchar_t equal, less, greater, and empty; - n==0, the byte past n, and stop at NUL; - simple_string and string_view, including embedded NUL; * test(stlsoft): cover BSTR comparison wrappers and length edges Extend the C BSTR program and add a C++ program for the wrappers: - empty BSTR versus NULL and versus a live string; - embedded NUL keeps SysStringLen and wcscmp stops; - a length-limited prefix compares as that prefix; - BSTR_compare and one comstl__bstr_compare call match the C function; - bstr::equal for equal, unequal, empty, and a raw BSTR; * test(stlsoft): cover string_begins_with prefix checks Add a unit program for stlsoft::string_begins_with on char, including the simple_string shim: - match, reject, empty prefix, and a longer prefix; - case-sensitive ASCII; - a prefix containing NUL is only the part before that NUL; * test(stlsoft): cover special_string_instance::equal Add a unit program for special_string_instance::equal, using a fixed policy so the cases do not touch the environment: - case-sensitive and ASCII case-insensitive, for char and wchar_t; - length mismatch, including empty; - an embedded NUL stops the compare when both lengths include it; * test(stlsoft): require simple_string to keep embedded NULs Amend the simple_string unit so every write path is expected to keep an embedded NUL, for char and wchar_t: - construction from a counted range; - append, including a tail that begins with NUL, and push_back; - assign into an empty string, a reserved buffer, and a NUL fill, plus copy of a preserved string; - compare treats a difference after that NUL as unequal; The suite now fails where construction, append, push_back, and assign into an empty string still drop the NUL. * whitespace * fix(stlsoft): preserve counted NULs in simple_string append(pointer, count) copied only up to the first NUL, so push_back of NUL and a counted tail that begins with NUL were dropped. Copy the given count, and assign a single character by that count so '\0' is stored. Counted construction and assign already kept the full count. * test(stlsoft): cover static_string compare Add unit cases for stlsoft::basic_static_string compare: - char equal, less, greater, and unsigned high-bit order; - empty char strings; - a counted embedded NUL stays in the length and compare sees the byte after it, for char and wchar_t; - wchar_t order and empty strings; * test(stlsoft): cover string_view compare edges Add unit cases for stlsoft::basic_string_view compare: - empty char views; - a counted embedded NUL stays in the length and compare sees the byte after it; - wchar_t order, empty, and the same embedded NUL; - char_traits_safe order, empty, and the same embedded NUL; * test(stlsoft): cover string_slice compare edges Add unit cases for stlsoft::string_slice compare: - empty char and wchar_t slices; - a counted embedded NUL stays in the length and compare sees the byte after it, for char and wchar_t; - char high-bit order, with 0x01 before 0xFF; * fix(stlsoft): let string_begins_with accept wchar_t operator() called strncmp, so a wchar_t prefix did not compile. Compare with char_traits<C>::compare_max, which is strncmp for char and wcsncmp for wchar_t, and cover the wide match, reject, empty, longer, and case-sensitive cases, including a prefix that contains NUL. * fix(stlsoft): define char_traits_safe compare of a null pointer compare_null() called the parent compare(), so a null pointer and a non-zero count were not defined. A count of 0 still compares equal. A non-zero count orders a null pointer before a live pointer, for char and wchar_t. * fix(stlsoft): build cleanly with MSVC and MinGW windows-cl-atl treats the Windows small macro, truncated char casts, CRT deprecation, and an unreachable fail as errors. windows-mingw does not link NetApiBufferAllocate. - store high-bit bytes in unsigned char and view them as char; - suppress deprecation around strcpy, strcat, and strdup wrappers; - accept that null_allocator::allocate always throws; - pass a DWORD byte count to NetApiBufferAllocate and link netapi32; * fix(stlsoft): stop null_allocator test failing MSVC /WX allocate() always throws, so a fail after the call is unreachable in a Release build, and the warning disable does not cover that. Record the exception and assert the flag after the try. * release * fix * docs(stlsoft): complete the 1.11.1-rc7 notes Add the rc6-to-HEAD items missing from the 1.11.1-rc7 notes: FILE_stream write_binary(), file_lines tests, filled allocator units, and removal of empty placeholder cases. Counted concatenation stays with the simple_string NUL contract. * `platformstl::basic_file_lines<>` perf-tests improvements: gap-groups (#30) * test(stlsoft): cover platformstl::file_lines component behavior Add a platformstl filesystem component suite covering empty files and one-line, terminated-line, and three-line inputs; verify embedded NUL data raises platformstl::invalid_file_type_exception; register the filesystem subtree with the existing platformstl component tests; * test(stlsoft): benchmark platformstl::file_lines Add a standalone comparative performance test for platformstl::file_lines_a and std::ifstream plus std::getline; follow existing STLSoft warm-up, stopwatch, anchoring, and tabular output conventions; * test(platformstl): improved performance test program for `platformstl::basic_file_lines<>` * fix(platformstl::file_lines): compatible with `std::basic_string_view` * perf(platformstl::file_lines): adjusted preallocation of number of reserved lines * perf(platformstl::file_lines): moved file-contents check into in-loop processing, so only pass once * perf(platformstl::file_lines): use of `#emplace_back()` (C++ 11+) * feat(platformstl): add FILE_stream::write_binary() Add a byte-oriented write that preserves embedded NULs, and deprecate write(void const*, size_t) in its favour. Cover CR and CRLF files in the file_lines component tests, and write the NUL fixture through write_binary(). * feat(platformstl): add FILE_stream::write_binary() Add a byte-oriented write that preserves embedded NULs, and deprecate write(void const*, size_t) in its favour. Cover CR and CRLF files in the file_lines component tests, and write the NUL fixture through write_binary(). * test(platformstl): cover CR, CRLF, and small files in file_lines perf Time LF, CRLF, and CR at the existing 1000×64 and 5000×80 shapes, and at 1×16, 8×32, and 32×64, so a later small-file path has a fixed-cost region to beat. Read the getline baseline in binary mode so the CR bytes are the same on every platform. * refactor(platformstl): parse file_lines directly from mapping Remove the full-file m_contents heap copy; parse directly from the mmap'd base pointer for lower memory bandwidth use. Drop the unused m_contents member and early-return on empty maps. * fix(platformstl): use C stdio in file_lines perf harness Avoid MinGW std::ifstream/std::getline crashes by switching the perf fixture writer/reader to fopen/fwrite/fgetc while preserving split on '\n' semantics (keeping '\r' in-line). * fix(performance): use STLSOFT fopen wrapper in file_lines benchmark * test(stlsoft): compare getline and getc file-line baselines - Rename the existing per-character stdio baseline to vector<std::string> plus getc; - add a genuine std::getline baseline using the appropriate LF or CR delimiter and normalise CRLF line endings; * ci * ci(stlsoft): trace the MinGW file_lines performance crash Temporarily run only the Windows/MinGW CI cell and write flushed stderr markers through the file_lines performance program; - Each scenario, warmup, and sampled iteration logs enter and leave; - `basic_file_lines` traces construct, iterate, and walk on those samples; * fix(platformstl): stop the MinGW getline baseline segfaulting `std::ifstream` dies on open under MinGW, which the progress log showed on the first getline call. Read that baseline through FILE* and still time `std::getline`; - Other compilers keep `std::ifstream`; * test(platformstl): stage the MinGW file_lines perf crash probe Print flushed C traces from constructors before main, then walk one small file through write, fgetc, getline, file_lines, and ifstream. The full matrix runs only when SIS_FILE_LINES_PERF_FULL is set. * test(platformstl): leave an on-disk trail for the MinGW file_lines death Add a pure-C boot probe and cwd breadcrumb file, fix the performance harness so it keeps the real child exit status, dump PE imports before exec, and restrict the MinGW cell to file_lines only. * ci(stlsoft): treat MinGW file_lines 127 as a loader failure Static-link libgcc/libstdc++ for the file_lines perf target, run that step under the msys2 shell, and on child-exit 127 dump MinGW runtimes, copy them beside the exe, and retry once. * ci(stlsoft): re-enable the file_lines full perf matrix on MinGW The staged probe passed end-to-end after static-linking libgcc/libstdc++, including std::ifstream. Set SIS_FILE_LINES_PERF_FULL so the next cell run hits the real workload with traces still enabled. * fix(cmake): static-link MinGW libgcc/libstdc++ for PE load MinGW performance exes were exiting 127 before any user code when the runner PATH did not match the toolchain that built them. Static-link libgcc and libstdc++ for Windows GNU targets in TargetMacros, restore the file_lines perf baseline and full CI, and capture the real child exit status in execute_performance_tests.sh. * docs(stlsoft): record file_lines.perf and restore GROUPGAPS in CI Restore SIS_PERFTESTS_GROUPGAPS=1 on the performance job; document platformstl::basic_file_lines<> mmap parse (~10–20× vs fgetc; ~parity / ~1.2× vs getline), the file_lines perf harness, MinGW static libgcc / libstdc++, and the execute_performance_tests.sh child_ec fix in CHANGES.md / NEWS.md for 1.11.1-rc7. * test(performance): roll out GROUPGAPS helpers and --gap-groups Add shared perf_group_gaps.hpp on the test/performance include path and honour SIS_PERFTESTS_GROUPGAPS in every performance main. TTY emits a blank line between logical groups; non-TTY / CI emits `\t----------`. Add --gap-groups on execute_performance_tests.sh/.cmd; CI uses -M --gap-groups. bit_functions keeps family/pattern key derivation via the shared helpers. * docs(stlsoft): align remaining project notes with 1.11.1-rc7 Point the bit-function strategy note at the nested performance program and close the matching **TODO.md** item; name the versions test by its current directory in the MFC comment in **CMakeLists.txt**. * Boilerplate, CI (#53) * .gitattributes * fix(c-cpp): quote Dir resolution in CMake helper scripts Use Dir=$(cd "$(dirname "$ScriptPath")" && pwd) so paths with spaces resolve reliably; apply the same one-line fix across in-wave helper scripts (prepare/build/clean/ctest/remove and run_all_*). * 1.11.1-rc7 (#29) * refactor(stlsoft): shorten test directory names (#25) * refactor(stlsoft): shorten the uds_helpers test directory Point add_subdirectory at uds_helpers. The executable name stays test.component.inetstl.util.uds_helpers. * refactor(stlsoft): shorten component-test directories Rename each test/component leaf to its subject segment and retarget add_subdirectory. Refresh each entry file's Updated and File banner. Executable names stay test.component.*. * refactor(stlsoft): shorten unit-test directories Rename each test/unit leaf except test.unit.versions to its subject segment and retarget add_subdirectory. Refresh each entry file's Updated and File banner. Executable names stay test.unit.*. test.unit.versions is unchanged. * refactor(stlsoft): shorten scratch-test directories Rename each test/scratch leaf to its subject segment and retarget add_subdirectory. Refresh Updated and File banners where present. Executable names stay test.scratch.*. * refactor(stlsoft): deepen performance-test directories Move each performance test onto its component header path, such as platformstl/diagnostics/stopwatch and stlsoft/memory/auto_buffer, and retarget add_subdirectory. Keep the C++ standard guards and the executable names. * refactor(stlsoft): shorten the test.unit.versions directory Rename test/unit/test.unit.versions to versions and retarget add_subdirectory. Refresh the entry file's Updated and File banner. The executable name stays test.unit.versions. * chore(stlsoft): record 1.11.1-rc7 for the test-tree reorganisation Advance `_STLSOFT_VER` to `_STLSOFT_VER_1_11_1_RC7` (`0x010b01c7`) and align the release notes with the shortened test directories and nested **test/performance** layout: - **CHANGES.md**, **NEWS.md**, and **INSTALL.md** updated for 30th September 2026; - **test.unit.versions** expects **_STLSOFT_VER_1_11_1_RC7**; * Remove empty test cases (#26) * refactor(stlsoft): shorten the uds_helpers test directory Point add_subdirectory at uds_helpers. The executable name stays test.component.inetstl.util.uds_helpers. * refactor(stlsoft): shorten component-test directories Rename each test/component leaf to its subject segment and retarget add_subdirectory. Refresh each entry file's Updated and File banner. Executable names stay test.component.*. * refactor(stlsoft): shorten unit-test directories Rename each test/unit leaf except test.unit.versions to its subject segment and retarget add_subdirectory. Refresh each entry file's Updated and File banner. Executable names stay test.unit.*. test.unit.versions is unchanged. * refactor(stlsoft): shorten scratch-test directories Rename each test/scratch leaf to its subject segment and retarget add_subdirectory. Refresh Updated and File banners where present. Executable names stay test.scratch.*. * refactor(stlsoft): deepen performance-test directories Move each performance test onto its component header path, such as platformstl/diagnostics/stopwatch and stlsoft/memory/auto_buffer, and retarget add_subdirectory. Keep the C++ standard guards and the executable names. * refactor(stlsoft): shorten the test.unit.versions directory Rename test/unit/test.unit.versions to versions and retarget add_subdirectory. Refresh the entry file's Updated and File banner. The executable name stays test.unit.versions. * test(STLSoft): remove empty unit-test case functions Remove empty xTests case functions (bodies with no statements), together with their forward declarations and XTESTS_RUN_CASE registrations, across 19 STLSoft unit-test entry files; - nine allocator suites keep a runner and no cases, because every case body was empty; - the Unix-built suites were rebuilt and passed; * test(STLSoft): flesh out empty allocator unit-test cases Give each of the nine allocator suites its seven cases: - round-trip 0, 4, 256, and 4096 ints, and reject a count past max_size(); - specialise std::list and std::vector with that allocator; - null_allocator must throw out_of_memory_exception on every request, including container insertion; - malloc_allocator, new_allocator, and null_allocator passed on this host; * fix * `platformstl::file_lines` automated tests (#20) * test(stlsoft): cover platformstl::file_lines component behavior Add a platformstl filesystem component suite covering empty files and one-line, terminated-line, and three-line inputs; verify embedded NUL data raises platformstl::invalid_file_type_exception; register the filesystem subtree with the existing platformstl component tests; * feat(platformstl): add FILE_stream::write_binary() Add a byte-oriented write that preserves embedded NULs, and deprecate write(void const*, size_t) in its favour. Cover CR and CRLF files in the file_lines component tests, and write the NUL fixture through write_binary(). * Bit functions: refactoring, extension, and optimisation (#23) * style(stlsoft): normalise bit-function header section banners Replace the short separator above each namespace close with the long section banner, and drop the short separator that precedes the include-guard close: - Refresh **Updated:** to 24th September 2026 and extend the Synesis Information Systems copyright through 2026; - Bump each header **EDIT** counter; * chore(tests): canonicalisation of test function names * test(stlsoft): cover all bit-function overloads by width Expand **test.unit.stlsoft.util.bit_functions** so every public C++ overload is called for each supported width, plus `count_bits(int)` for signedness; - Add Kernighan and 8-bit-table cases for **uint64_t**; - Add **count_bits** for **uint32_t**, **uint64_t**, and **int**; - Add **find_highest_bit** for **uint8_t** and **uint16_t**; - Add **calculate_xor_over_range** for 16-, 32-, and 64-bit ranges; - Remove in-unit stopwatch timing; * test(stlsoft): add bit-functions performance suite Add **test.performance.stlsoft.bit_functions** under a nested **stlsoft/** performance tree, with an aligned width × function timing table covering every public bit-function overload; - Wire **test/performance/CMakeLists.txt** → **stlsoft** → **bit_functions**; - Time Kernighan and 8-bit-table popcount, **count_bits**, **find_highest_bit**, and **calculate_xor_over_range**; * fix: `count_bits()` overloads were broken when `STLSOFT_BIT_COUNT_BY_Kernighan` is defined * test(stlsoft): vary popcount density in bit-functions perf Extend **test.performance.stlsoft.bit_functions** with denser popcount workloads so Kernighan vs 8-bit-table can be compared beyond the sparse sequential-i series; - Add /~i (bitwise-not), /ones (volatile all-ones), and /ones^1 (all-ones with one rotating bit cleared); - Widen the function-name column for the longer row labels; * fix(stlsoft): avoid uint64_t clash in bit-functions perf Stop importing stlsoft::uint64_t into the global namespace: it conflicts with ::uint64_t from <cstdint> (pulled in via std_chrono_hrc_stopwatch) and made 64-bit overloads ambiguous on Linux GCC. - Use stlsoft::ss_uintN_t aliases for variables and casts; keep column headers as uintN_t labels; * test(stlsoft.b): report median bit-function timings with a 64-bit anchor Time each row as one discarded warmup plus five samples and print the median. Accumulate the anchor in ss_uint64_t. Print STLSOFT_COMPILER_VERSION_STRING, whether optimisation is size, speed, or off, and whether this is a release or debug-asserts build. * fix(stlsoft): silence maybe-uninitialized in bit_functions median Zero-initialise the local sorted[] buffer in median_sample, guard empty n, and clamp n to NUM_SAMPLES so GCC -Werror=maybe-uninitialized no longer fails the performance harness on CI. * test(stlsoft.b): time more bit patterns and print per-call rates Add volatile-zero, rotating-bit, and both-halves-live rows for popcount and find_highest_bit, so the 64-bit high half is exercised. Print ns/call on the same line as the loop time, ns/element for XOR, and the anchor last. Honor SIS_PERFTESTS_GROUPGAPS with a blank line between operation and input-pattern groups. * docs(stlsoft.b): record bit-function timings and the default choice Keep the 8-bit table as the default for count_bits(). Apple Clang rewrites Kernighan into a hardware popcount; Linux and Windows compilers execute the source loop and the table is faster there. * feat(stlsoft): bit-function intrinsics for 1.11.1-rc7 Add unselected `count_bits_by_intrinsic()` / `find_highest_bit_by_intrinsic()`, with external/internal bitfns detection (GCC/Clang builtins preferred over MSVC), 8/16-bit count overloads, Clang `STLSOFT_CLANG_VER`, unit and performance coverage, and strategy notes that keep the 8-bit table as the `count_bits()` default; * fix(stlsoft): cast popcnt64; enable perf group gaps in CI Cast MSVC `__popcnt64` through `STLSOFT_C_CAST(int, …)` so `/WX` builds stop on C4244. Export `SIS_PERFTESTS_GROUPGAPS=1` for the performance job and only print the harness banner when that env is truey. Quiet getenv C4996 and narrow `~` promotions on uint8/16 ones patterns. Record Linux GCC 13.3 (~3.1 ns soft popcount vs table) and Apple Clang 21 CI findings in `strategy/BIT_FUNCTIONS.md`. * docs(stlsoft): fold full CI bit-function matrix into strategy Replace partial CI notes in strategy/BIT_FUNCTIONS.md with the six-cell wave (Linux Clang/GCC, macOS Clang/“gcc”, MSVC, MinGW): soft vs hard popcount, /bit deletions, and find_highest comparisons. Keep table as portable default; leave both intrinsics unselected pending a narrow gate. * test(stlsoft): add component tests for environment_variable_exists() (#24) * test(stlsoft): add component tests for environment_variable_exists() Cover stlsoft::environment_variable_exists() against the process environment, using platformstl::environment_variable_scope to set and restore each variable: absent, present, erased, value replacement, exact name match, std::string and simple_string shims, UNIX empty values, and case sensitivity. * refactor(stlsoft): rename environment_variable_exists_a to _m Rename `stlsoft_C_environment_variable_exists_a()` to `stlsoft_C_environment_variable_exists_m()` and keep the `_a` spelling as a deprecated forwarder; the C++ overloads and component tests call `_m`. * `platformstl::file_lines` performance tests (#21) * test(stlsoft): cover platformstl::file_lines component behavior Add a platformstl filesystem component suite covering empty files and one-line, terminated-line, and three-line inputs; verify embedded NUL data raises platformstl::invalid_file_type_exception; register the filesystem subtree with the existing platformstl component tests; * test(stlsoft): benchmark platformstl::file_lines Add a standalone comparative performance test for platformstl::file_lines_a and std::ifstream plus std::getline; follow existing STLSoft warm-up, stopwatch, anchoring, and tabular output conventions; * test(platformstl): improved performance test program for `platformstl::basic_file_lines<>` * fix(platformstl::file_lines): compatible with `std::basic_string_view` * perf(platformstl::file_lines): adjusted preallocation of number of reserved lines * perf(platformstl::file_lines): moved file-contents check into in-loop processing, so only pass once * perf(platformstl::file_lines): use of `#emplace_back()` (C++ 11+) * feat(platformstl): add FILE_stream::write_binary() Add a byte-oriented write that preserves embedded NULs, and deprecate write(void const*, size_t) in its favour. Cover CR and CRLF files in the file_lines component tests, and write the NUL fixture through write_binary(). * feat(platformstl): add FILE_stream::write_binary() Add a byte-oriented write that preserves embedded NULs, and deprecate write(void const*, size_t) in its favour. Cover CR and CRLF files in the file_lines component tests, and write the NUL fixture through write_binary(). * test(platformstl): cover CR, CRLF, and small files in file_lines perf Time LF, CRLF, and CR at the existing 1000×64 and 5000×80 shapes, and at 1×16, 8×32, and 32×64, so a later small-file path has a fixed-cost region to beat. Read the getline baseline in binary mode so the CR bytes are the same on every platform. * refactor(platformstl): parse file_lines directly from mapping Remove the full-file m_contents heap copy; parse directly from the mmap'd base pointer for lower memory bandwidth use. Drop the unused m_contents member and early-return on empty maps. * fix(platformstl): use C stdio in file_lines perf harness Avoid MinGW std::ifstream/std::getline crashes by switching the perf fixture writer/reader to fopen/fwrite/fgetc while preserving split on '\n' semantics (keeping '\r' in-line). * fix(performance): use STLSOFT fopen wrapper in file_lines benchmark * test(stlsoft): compare getline and getc file-line baselines - Rename the existing per-character stdio baseline to vector<std::string> plus getc; - add a genuine std::getline baseline using the appropriate LF or CR delimiter and normalise CRLF line endings; * ci * ci(stlsoft): trace the MinGW file_lines performance crash Temporarily run only the Windows/MinGW CI cell and write flushed stderr markers through the file_lines performance program; - Each scenario, warmup, and sampled iteration logs enter and leave; - `basic_file_lines` traces construct, iterate, and walk on those samples; * fix(platformstl): stop the MinGW getline baseline segfaulting `std::ifstream` dies on open under MinGW, which the progress log showed on the first getline call. Read that baseline through FILE* and still time `std::getline`; - Other compilers keep `std::ifstream`; * test(platformstl): stage the MinGW file_lines perf crash probe Print flushed C traces from constructors before main, then walk one small file through write, fgetc, getline, file_lines, and ifstream. The full matrix runs only when SIS_FILE_LINES_PERF_FULL is set. * test(platformstl): leave an on-disk trail for the MinGW file_lines death Add a pure-C boot probe and cwd breadcrumb file, fix the performance harness so it keeps the real child exit status, dump PE imports before exec, and restrict the MinGW cell to file_lines only. * ci(stlsoft): treat MinGW file_lines 127 as a loader failure Static-link libgcc/libstdc++ for the file_lines perf target, run that step under the msys2 shell, and on child-exit 127 dump MinGW runtimes, copy them beside the exe, and retry once. * ci(stlsoft): re-enable the file_lines full perf matrix on MinGW The staged probe passed end-to-end after static-linking libgcc/libstdc++, including std::ifstream. Set SIS_FILE_LINES_PERF_FULL so the next cell run hits the real workload with traces still enabled. * fix(cmake): static-link MinGW libgcc/libstdc++ for PE load MinGW performance exes were exiting 127 before any user code when the runner PATH did not match the toolchain that built them. Static-link libgcc and libstdc++ for Windows GNU targets in TargetMacros, restore the file_lines perf baseline and full CI, and capture the real child exit status in execute_performance_tests.sh. * docs(stlsoft): record file_lines.perf and restore GROUPGAPS in CI Restore SIS_PERFTESTS_GROUPGAPS=1 on the performance job; document platformstl::basic_file_lines<> mmap parse (~10–20× vs fgetc; ~parity / ~1.2× vs getline), the file_lines perf harness, MinGW static libgcc / libstdc++, and the execute_performance_tests.sh child_ec fix in CHANGES.md / NEWS.md for 1.11.1-rc7. * String comparison unit-tests (#27) * refactor(stlsoft): shorten the uds_helpers test directory Point add_subdirectory at uds_helpers. The executable name stays test.component.inetstl.util.uds_helpers. * refactor(stlsoft): shorten component-test directories Rename each test/component leaf to its subject segment and retarget add_subdirectory. Refresh each entry file's Updated and File banner. Executable names stay test.component.*. * refactor(stlsoft): shorten unit-test directories Rename each test/unit leaf except test.unit.versions to its subject segment and retarget add_subdirectory. Refresh each entry file's Updated and File banner. Executable names stay test.unit.*. test.unit.versions is unchanged. * refactor(stlsoft): shorten scratch-test directories Rename each test/scratch leaf to its subject segment and retarget add_subdirectory. Refresh Updated and File banners where present. Executable names stay test.scratch.*. * refactor(stlsoft): deepen performance-test directories Move each performance test onto its component header path, such as platformstl/diagnostics/stopwatch and stlsoft/memory/auto_buffer, and retarget add_subdirectory. Keep the C++ standard guards and the executable names. * refactor(stlsoft): shorten the test.unit.versions directory Rename test/unit/test.unit.versions to versions and retarget add_subdirectory. Refresh the entry file's Updated and File banner. The executable name stays test.unit.versions. * test(STLSoft): remove empty unit-test case functions Remove empty xTests case functions (bodies with no statements), together with their forward declarations and XTESTS_RUN_CASE registrations, across 19 STLSoft unit-test entry files; - nine allocator suites keep a runner and no cases, because every case body was empty; - the Unix-built suites were rebuilt and passed; * test(STLSoft): flesh out empty allocator unit-test cases Give each of the nine allocator suites its seven cases: - round-trip 0, 4, 256, and 4096 ints, and reject a count past max_size(); - specialise std::list and std::vector with that allocator; - null_allocator must throw out_of_memory_exception on every request, including container insertion; - malloc_allocator, new_allocator, and null_allocator passed on this host; * test(stlsoft): cover stlsoft_C_strnicmp and the C++ wrappers Add unit programs for stlsoft_C_strnicmp(), stlsoft_C_wcsnicmp(), and the stlsoft::c_string wrappers: - char and wchar_t equal, less, and greater; - n==0, stop at NUL, and ignore the byte past n; - ASCII case-fold, and high-bit bytes that share a sign; * test(stlsoft): cover c_string_traits string comparison Add a unit program for stlsoft::c_string_traits compare, n-compare, and the ASCII case-insensitive forms, for char and wchar_t: - equal, less, greater, and empty strings; - n==0, stop at NUL, and ignore the byte past n; * test(stlsoft): cover char_traits and char_traits_safe comparison Add a unit program for stlsoft::char_traits and char_traits_safe, for char and wchar_t: - eq, lt, and compare equal, less, and greater; - n==0, exact-n past NUL, and compare_max stopping at NUL; - compare_null for both-null and one-null; - char compare unsigned high-bit order; - char_traits_safe compare, and compare_max with null pointers; * test(stlsoft): cover stlsoft::strcmp and stlsoft::strncmp Add a unit program for the pointer overloads and the S const& shims: - char and wchar_t equal, less, greater, and empty; - n==0, the byte past n, and stop at NUL; - simple_string and string_view, including embedded NUL; * test(stlsoft): cover BSTR comparison wrappers and length edges Extend the C BSTR program and add a C++ program for the wrappers: - empty BSTR versus NULL and versus a live string; - embedded NUL keeps SysStringLen and wcscmp stops; - a length-limited prefix compares as that prefix; - BSTR_compare and one comstl__bstr_compare call match the C function; - bstr::equal for equal, unequal, empty, and a raw BSTR; * test(stlsoft): cover string_begins_with prefix checks Add a unit program for stlsoft::string_begins_with on char, including the simple_string shim: - match, reject, empty prefix, and a longer prefix; - case-sensitive ASCII; - a prefix containing NUL is only the part before that NUL; * test(stlsoft): cover special_string_instance::equal Add a unit program for special_string_instance::equal, using a fixed policy so the cases do not touch the environment: - case-sensitive and ASCII case-insensitive, for char and wchar_t; - length mismatch, including empty; - an embedded NUL stops the compare when both lengths include it; * test(stlsoft): require simple_string to keep embedded NULs Amend the simple_string unit so every write path is expected to keep an embedded NUL, for char and wchar_t: - construction from a counted range; - append, including a tail that begins with NUL, and push_back; - assign into an empty string, a reserved buffer, and a NUL fill, plus copy of a preserved string; - compare treats a difference after that NUL as unequal; The suite now fails where construction, append, push_back, and assign into an empty string still drop the NUL. * whitespace * fix(stlsoft): preserve counted NULs in simple_string append(pointer, count) copied only up to the first NUL, so push_back of NUL and a counted tail that begins with NUL were dropped. Copy the given count, and assign a single character by that count so '\0' is stored. Counted construction and assign already kept the full count. * test(stlsoft): cover static_string compare Add unit cases for stlsoft::basic_static_string compare: - char equal, less, greater, and unsigned high-bit order; - empty char strings; - a counted embedded NUL stays in the length and compare sees the byte after it, for char and wchar_t; - wchar_t order and empty strings; * test(stlsoft): cover string_view compare edges Add unit cases for stlsoft::basic_string_view compare: - empty char views; - a counted embedded NUL stays in the length and compare sees the byte after it; - wchar_t order, empty, and the same embedded NUL; - char_traits_safe order, empty, and the same embedded NUL; * test(stlsoft): cover string_slice compare edges Add unit cases for stlsoft::string_slice compare: - empty char and wchar_t slices; - a counted embedded NUL stays in the length and compare sees the byte after it, for char and wchar_t; - char high-bit order, with 0x01 before 0xFF; * fix(stlsoft): let string_begins_with accept wchar_t operator() called strncmp, so a wchar_t prefix did not compile. Compare with char_traits<C>::compare_max, which is strncmp for char and wcsncmp for wchar_t, and cover the wide match, reject, empty, longer, and case-sensitive cases, including a prefix that contains NUL. * fix(stlsoft): define char_traits_safe compare of a null pointer compare_null() called the parent compare(), so a null pointer and a non-zero count were not defined. A count of 0 still compares equal. A non-zero count orders a null pointer before a live pointer, for char and wchar_t. * fix(stlsoft): build cleanly with MSVC and MinGW windows-cl-atl treats the Windows small macro, truncated char casts, CRT deprecation, and an unreachable fail as errors. windows-mingw does not link NetApiBufferAllocate. - store high-bit bytes in unsigned char and view them as char; - suppress deprecation around strcpy, strcat, and strdup wrappers; - accept that null_allocator::allocate always throws; - pass a DWORD byte count to NetApiBufferAllocate and link netapi32; * fix(stlsoft): stop null_allocator test failing MSVC /WX allocate() always throws, so a fail after the call is unreachable in a Release build, and the warning disable does not cover that. Record the exception and assert the flag after the try. * release * fix * docs(stlsoft): complete the 1.11.1-rc7 notes Add the rc6-to-HEAD items missing from the 1.11.1-rc7 notes: FILE_stream write_binary(), file_lines tests, filled allocator units, and removal of empty placeholder cases. Counted concatenation stays with the simple_string NUL contract. * `platformstl::basic_file_lines<>` perf-tests improvements: gap-groups (#30) * test(stlsoft): cover platformstl::file_lines component behavior Add a platformstl filesystem component suite covering empty files and one-line, terminated-line, and three-line inputs; verify embedded NUL data raises platformstl::invalid_file_type_exception; register the filesystem subtree with the existing platformstl component tests; * test(stlsoft): benchmark platformstl::file_lines Add a standalone comparative performance test for platformstl::file_lines_a and std::ifstream plus std::getline; follow existing STLSoft warm-up, stopwatch, anchoring, and tabular output conventions; * test(platformstl): improved performance test program for `platformstl::basic_file_lines<>` * fix(platformstl::file_lines): compatible with `std::basic_string_view` * perf(platformstl::file_lines): adjusted preallocation of number of reserved lines * perf(platformstl::file_lines): moved file-contents check into in-loop processing, so only pass once * perf(platformstl::file_lines): use of `#emplace_back()` (C++ 11+) * feat(platformstl): add FILE_stream::write_binary() Add a byte-oriented write that preserves embedded NULs, and deprecate write(void const*, size_t) in its favour. Cover CR and CRLF files in the file_lines component tests, and write the NUL fixture through write_binary(). * feat(platformstl): add FILE_stream::write_binary() Add a byte-oriented write that preserves embedded NULs, and deprecate write(void const*, size_t) in its favour. Cover CR and CRLF files in the file_lines component tests, and write the NUL fixture through write_binary(). * test(platformstl): cover CR, CRLF, and small files in file_lines perf Time LF, CRLF, and CR at the existing 1000×64 and 5000×80 shapes, and at 1×16, 8×32, and 32×64, so a later small-file path has a fixed-cost region to beat. Read the getline baseline in binary mode so the CR bytes are the same on every platform. * refactor(platformstl): parse file_lines directly from mapping Remove the full-file m_contents heap copy; parse directly from the mmap'd base pointer for lower memory bandwidth use. Drop the unused m_contents member and early-return on empty maps. * fix(platformstl): use C stdio in file_lines perf harness Avoid MinGW std::ifstream/std::getline crashes by switching the perf fixture writer/reader to fopen/fwrite/fgetc while preserving split on '\n' semantics (keeping '\r' in-line). * fix(performance): use STLSOFT fopen wrapper in file_lines benchmark * test(stlsoft): compare getline and getc file-line baselines - Rename the existing per-character stdio baseline to vector<std::string> plus getc; - add a genuine std::getline baseline using the appropriate LF or CR delimiter and normalise CRLF line endings; * ci * ci(stlsoft): trace the MinGW file_lines performance crash Temporarily run only the Windows/MinGW CI cell and write flushed stderr markers through the file_lines performance program; - Each scenario, warmup, and sampled iteration logs enter and leave; - `basic_file_lines` traces construct, iterate, and walk on those samples; * fix(platformstl): stop the MinGW getline baseline segfaulting `std::ifstream` dies on open under MinGW, which the progress log showed on the first getline call. Read that baseline through FILE* and still time `std::getline`; - Other compilers keep `std::ifstream`; * test(platformstl): stage the MinGW file_lines perf crash probe Print flushed C traces from constructors before main, then walk one small file through write, fgetc, getline, file_lines, and ifstream. The full matrix runs only when SIS_FILE_LINES_PERF_FULL is set. * test(platformstl): leave an on-disk trail for the MinGW file_lines death Add a pure-C boot probe and cwd breadcrumb file, fix the performance harness so it keeps the real child exit status, dump PE imports before exec, and restrict the MinGW cell to file_lines only. * ci(stlsoft): treat MinGW file_lines 127 as a loader failure Static-link libgcc/libstdc++ for the file_lines perf target, run that step under the msys2 shell, and on child-exit 127 dump MinGW runtimes, copy them beside the exe, and retry once. * ci(stlsoft): re-enable the file_lines full perf matrix on MinGW The staged probe passed end-to-end after static-linking libgcc/libstdc++, including std::ifstream. Set SIS_FILE_LINES_PERF_FULL so the next cell run hits the real workload with traces still enabled. * fix(cmake): static-link MinGW libgcc/libstdc++ for PE load MinGW performance exes were exiting 127 before any user code when the runner PATH did not match the toolchain that built them. Static-link libgcc and libstdc++ for Windows GNU targets in TargetMacros, restore the file_lines perf baseline and full CI, and capture the real child exit status in execute_performance_tests.sh. * docs(stlsoft): record file_lines.perf and restore GROUPGAPS in CI Restore SIS_PERFTESTS_GROUPGAPS=1 on the performance job; document platformstl::basic_file_lines<> mmap parse (~10–20× vs fgetc; ~parity / ~1.2× vs getline), the file_lines perf harness, MinGW static libgcc / libstdc++, and the execute_performance_tests.sh child_ec fix in CHANGES.md / NEWS.md for 1.11.1-rc7. * test(performance): roll out GROUPGAPS helpers and --gap-groups Add shared perf_group_gaps.hpp on the test/performance include path and honour SIS_PERFTESTS_GROUPGAPS in every performance main. TTY emits a blank line between logical groups; non-TTY / CI emits `\t----------`. Add --gap-groups on execute_performance_tests.sh/.cmd; CI uses -M --gap-groups. bit_functions keeps family/pattern key derivation via the shared helpers. * docs(stlsoft): align remaining project notes with 1.11.1-rc7 Point the bit-function strategy note at the nested performance program and close the matching **TODO.md** item; name the versions test by its current directory in the MFC comment in **CMakeLists.txt**. --------- Co-authored-by: Matt Wilson <152443343+mwsis@users.noreply.github.com> * boilerplate --------- Co-authored-by: Matt Wilson <152443343+mwsis@users.noreply.github.com> * chore(stlsoft): release 1.11.1-rc8 Release **STLSoft** 1.11.1-rc8 (10th October 2026), restoring behaviour lost in the boilerplate helper-script rewrite and adding the Doxygen inputs that **generate_doxygen.sh** requires: - add **_STLSOFT_VER_1_11_1_RC8** and align **test.unit.versions**, **CHANGES.md**, **NEWS.md**, and **INSTALL.md**; - restore **prepare_cmake.sh** `--no-ace`, `--no-cstring`, and `--use-unixem`, with their `-D` options; - restore **run_all_examples.sh** / **.cmd** `--skip-interactive`, and its use in CI to avoid hung runs; - fail **run_all_unit_tests.sh** and **run_all_component_tests.sh** when no programs are discovered; - run component tests in **ci-cell.yml** via **run_all_component_tests.sh**; - add **Doxyfile** and **doc/mainpage.md**; * Environment functions (#49) * test(stlsoft): add component tests for environment_variable_exists() Cover stlsoft::environment_variable_exists() against the process environment, using platformstl::environment_variable_scope to set and restore each variable: absent, present, erased, value replacement, exact name match, std::string and simple_string shims, UNIX empty values, and case sensitivity. * refactor(stlsoft): rename environment_variable_exists_a to _m Rename `stlsoft_C_environment_variable_exists_a()` to `stlsoft_C_environment_variable_exists_m()` and keep the `_a` spelling as a deprecated forwarder; the C++ overloads and component tests call `_m`. * version * fix(stlsoft): detect empty environment variables with getenv_s Use the required-size result from getenv_s() to distinguish an absent variable from an existing empty variable; Extend the environment-variable component test to cover empty values through the C API and C++ overloads, replacement, and erasure; * Traits conformance (#51) * chore(layout): trivial whitespace change…
mwsis
approved these changes
Oct 27, 2026
* build: publish HAS_<Pkg> for detected Synesis packages After each successful detection of a Synesis package other than STLSoft, define HAS_<Pkg> and HAS_<PKG>. Dots in package names become underscores. BDUT and CLASP, already all-caps, get the single macro. Client-prefixed presence macros were removed where only the client read them. Dependency switches such as XTESTS_HAS_SHWILD, PANTHEIOS_HAS_SHWILD, and the *_NO_* contracts stay. * fix: align versions links and current release symbols Keep versions target_link_libraries in the signature the project already uses, link header-only packages by their imported target, and compare version tests with the current release symbol. * feat(stlsoft): add opt-in woad and rework scratch versions programs Add an opt-in woad dependency and bring the three scratch versions programs into line with each other for the 1.11.3 release: - add --use-woad to prepare_cmake.sh, passing -DUSE_WOAD:BOOL, and find woad 0.2.0 in CMakeLists.txt when USE_WOAD and BUILD_TESTING are set, defining HAS_woad / HAS_WOAD and the HAS_woad CMake variable; - link woad::woad into the versions.format, versions.iostreams and versions.stdio targets when HAS_woad is set; - define STLSOFT_HAS_COM on WIN32 so that COMSTL is reported; - rework versions.stdio and versions.iostreams to a common layout with headings, language and compiler lines, subproject entries and a conditional efferent-dependencies section (cstring, Diagnosticism, shwild, UNIXem, woad, xTests), rendering versions via Diagnosticism when available; - colour versions.iostreams output via woad (magenta headings, blue names, green versions and values, cyan macros), falling back to plain text when woad is not in use; - include the ACESTL, ATLSTL, COMSTL and MFCSTL headers in the versions programs, ordered consistently; - record the work in CHANGES.md, NEWS.md and INSTALL.md, and add a TODO.md item to colour versions.stdio and versions.format; * fix: correct the Diagnosticism line in versions.stdio The fprintf passed an undeclared prefix and one argument too many. Print the name, the Diagnosticism string, and the macro, as the fallback line does. * fix(stlsoft): link xTests into the scratch versions reporters HAS_xTests is defined for the whole test build, so the scratch versions programs include xtests/xtests.h. They are example targets, which do not link xTests::core, so CI cannot see that header. Link it, as the unit tests already do. * fix(stlsoft): apply shared MFC settings to scratch versions versions.iostreams and versions.format include mfcstl.hpp when STLSOFT_HAS_MFC is set, but example targets never receive _AFXDLL. The windows-cl-mfc cell then rejects afx.h under /MD. Use the same per-target MFC settings as test/unit/versions. --------- Co-authored-by: Matt Wilson <152443343+mwsis@users.noreply.github.com>
* 1.11.2-alpha1 * test(integer_to_string): share one short performance schedule Hoist the per-section warmup, loop, and iteration counts to one shared schedule of 2 warmups, 1 loop, and 1,000,000 iterations. The previous 4 x 100 x 1,000,000 schedule was repeated in every section and took about ten minutes. * feature(C-string functions): added **test.performance.stlsoft.string.c_string** * test(stlsoft): add exhaustive c_string unit tests Cover strnchr, strnicmp, strnistrn, strnpbrkn, strnrchr, and strnstrn, plus each wchar analogue, with C and C++ programs. strnistrn stays on the current inner loop, so the first-character false-match cases fail; * fix(stlsoft): compare each strnistrn character, not only the first The inner loops of stlsoft_C_strnistrn() and stlsoft_C_wcsnistrn() compared *s1 with *s2 on every index, so a first-character hit was treated as a full match. Index the pair, and fold the wide form with towupper. * fix(stlsoft): quiet MSVC C4310 and GCC 15 free-nonheap-object Store high-bit c_string test bytes in unsigned char so MSVC does not warn C4310. Keep auto_buffer's deallocate out of line on GCC 12+, and suppress -Wfree-nonheap-object, which mis-reports a delete of the internal buffer from simple_string's unit test. * version * test(stlsoft): compare a full sun_path with a counted string A 108-character path fills Linux sun_path and is not NUL-terminated. TEST_MS_EQ then read past the array. Use TEST_MS_EQ_N when the path length is the capacity, as the 104-character case already does. * perf(stlsoft): fold ASCII case in strnistrn without toupper Replace per-byte toupper and towupper on the strnistrn hot path with an unsigned-char ASCII fold. The needle's first unit is folded once. wchar_t units outside 0-127 still use towupper. Non-ASCII bytes are no longer folded by the current locale. * perf(stlsoft): fold ASCII case in strnicmp without toupper Replace per-byte toupper and towupper on the strnicmp mismatch path with an unsigned-char ASCII fold. Equal bytes still skip the fold. wchar_t units outside 0-127 still use towupper. * tidy * perf(stlsoft): search ASCII strnchr with memchr Call memchr and wmemchr when the search value is in 0-127. Values outside that range stay on the scalar loop, so a high byte still compares as a promoted char. * perf(stlsoft): search strnstrn with memchr and memcmp Find the first needle byte with memchr over the positions that can still hold the needle, then memcmp the remaining bytes. A partial hit resumes one past that byte. wchar_t uses wmemchr and wmemcmp. An empty needle still returns the haystack. * tidy * canonicalisation * tidy * `auto_buffer` extraneous warning (#74) * 1.11.2 version elements * fix(stlsoft): silence GCC 12+ free-nonheap warning in auto_buffer Mark `deallocate_()` `STLSOFT_NOINLINE` on GCC 12+ so `operator delete` stays out of the inlined destructor, and suppress `-Wfree-nonheap-object` around the external-buffer `delete`, which GCC misattributes to the internal buffer. * test(stlsoft): compare a full sun_path with a counted string A 108-character path fills Linux sun_path and is not NUL-terminated. TEST_MS_EQ then read past the array. Use TEST_MS_EQ_N when the path length is the capacity, as the 104-character case already does. --------- Co-authored-by: Matt Wilson <matthew.wilson.synesis@gmail.com> * refactor(unit-tests): applying xTests' null macros (#70) * refactor(unit-tests): applying xTests' null macros * 1.11.2-alpha1 * `auto_buffer` extraneous warning (#74) * 1.11.2 version elements * fix(stlsoft): silence GCC 12+ free-nonheap warning in auto_buffer Mark `deallocate_()` `STLSOFT_NOINLINE` on GCC 12+ so `operator delete` stays out of the inlined destructor, and suppress `-Wfree-nonheap-object` around the external-buffer `delete`, which GCC misattributes to the internal buffer. * test(stlsoft): compare a full sun_path with a counted string A 108-character path fills Linux sun_path and is not NUL-terminated. TEST_MS_EQ then read past the array. Use TEST_MS_EQ_N when the path length is the capacity, as the 104-character case already does. --------- Co-authored-by: Matt Wilson <matthew.wilson.synesis@gmail.com> --------- Co-authored-by: synesissoftware <matthew@synesis.com.au> * chore(nomenclature): standardise use of alpha/beta/rc nomenclature throughout the repo (#75) * `auto_buffer` extraneous warning (#74) * 1.11.2 version elements * fix(stlsoft): silence GCC 12+ free-nonheap warning in auto_buffer Mark `deallocate_()` `STLSOFT_NOINLINE` on GCC 12+ so `operator delete` stays out of the inlined destructor, and suppress `-Wfree-nonheap-object` around the external-buffer `delete`, which GCC misattributes to the internal buffer. * test(stlsoft): compare a full sun_path with a counted string A 108-character path fills Linux sun_path and is not NUL-terminated. TEST_MS_EQ then read past the array. Use TEST_MS_EQ_N when the path length is the capacity, as the 104-character case already does. --------- Co-authored-by: Matt Wilson <matthew.wilson.synesis@gmail.com> * chore(nomenclature): standardise use of alpha/beta/rc nomenclature throughout the repo --------- Co-authored-by: Matt Wilson <matthew.wilson.synesis@gmail.com> * C-string function fixes (#77) * test(stlsoft): add exhaustive c_string unit tests Cover strnchr, strnicmp, strnistrn, strnpbrkn, strnrchr, and strnstrn, plus each wchar analogue, with C and C++ programs. strnistrn stays on the current inner loop, so the first-character false-match cases fail; * fix(stlsoft): compare each strnistrn character, not only the first The inner loops of stlsoft_C_strnistrn() and stlsoft_C_wcsnistrn() compared *s1 with *s2 on every index, so a first-character hit was treated as a full match. Index the pair, and fold the wide form with towupper. * chore(automated tests): namespace commenting * fix(stlsoft): quiet MSVC C4310 Store high-bit c_string test bytes in unsigned char so MSVC does not warn C4310. --------- Co-authored-by: Matt Wilson <matthew.wilson.synesis@gmail.com> * tidying * docs(stlsoft): summarise c_string performance by function Add one table per helper covering the local Mac and the six CI cells. Paired cells are baseline time divided by the STLSoft time, so a value above 1 means the STLSoft function was faster. strnistrn stays as total nanoseconds because it has no paired baseline. --------- Co-authored-by: synesissoftware <matthew@synesis.com.au>
Rewrite the **1.11.3** section for the work on dev since **1.11.2**: - ASCII case-fold and memchr/memcmp in the counted-string functions; - HAS_<Pkg> / HAS_<PKG>, opt-in woad, and the scratch version reporters; - subproject headers require STLSoft 1.11.2; - Doxyfile PROJECT_NUMBER is 1.11.3; unfinished 1.11.3 items move to 1.11.4;
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.