Skip to content

platformstl::basic_file_lines<> perf-tests improvements: gap-groups - #30

Merged
synesissoftware merged 28 commits into
devfrom
file_lines.perf.gap-groups
Sep 30, 2026
Merged

synesissoftware merged 28 commits into
devfrom
file_lines.perf.gap-groups

Conversation

@synesissoftware

Copy link
Copy Markdown
Owner

No description provided.

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;
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;
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().
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().
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.
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.
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).
- 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;
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;
`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`;
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.
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.
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.
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.
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.
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.
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.
@synesissoftware synesissoftware self-assigned this Sep 30, 2026
@synesissoftware
synesissoftware marked this pull request as ready for review September 30, 2026 02:52
@synesissoftware
synesissoftware merged commit ec095eb into dev Sep 30, 2026
105 of 118 checks passed
@synesissoftware
synesissoftware deleted the file_lines.perf.gap-groups branch September 30, 2026 03:39
synesissoftware added a commit that referenced this pull request Sep 30, 2026
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant